improved entity & world gen

v5stable
Ondřej Hruška 11 years ago
parent ffffbefefe
commit 5235b969c9
  1. 8
      src/mightypork/gamecore/audio/SoundBank.java
  2. 4
      src/mightypork/gamecore/gui/components/layout/HorizontalFixedFlowLayout.java
  3. 4
      src/mightypork/gamecore/gui/components/layout/VerticalFixedFlowLayout.java
  4. 4
      src/mightypork/gamecore/gui/screens/ScreenRegistry.java
  5. 4
      src/mightypork/gamecore/input/KeyStroke.java
  6. 4
      src/mightypork/gamecore/loading/DeferredResource.java
  7. 4
      src/mightypork/gamecore/render/fonts/FontBank.java
  8. 21
      src/mightypork/gamecore/render/textures/QuadGrid.java
  9. 19
      src/mightypork/rogue/screens/gamescreen/world/MIPClickPathfWalk.java
  10. 6
      src/mightypork/rogue/screens/gamescreen/world/MIPKeyWalk.java
  11. 14
      src/mightypork/rogue/screens/gamescreen/world/MIPMouseWalk.java
  12. 13
      src/mightypork/rogue/screens/gamescreen/world/MapView.java
  13. 58
      src/mightypork/rogue/world/Coord.java
  14. 112
      src/mightypork/rogue/world/EntityPos.java
  15. 14
      src/mightypork/rogue/world/PathStep.java
  16. 75
      src/mightypork/rogue/world/PlayerControl.java
  17. 33
      src/mightypork/rogue/world/World.java
  18. 5
      src/mightypork/rogue/world/WorldCreator.java
  19. 32
      src/mightypork/rogue/world/WorldRenderer.java
  20. 12
      src/mightypork/rogue/world/entity/Entities.java
  21. 235
      src/mightypork/rogue/world/entity/Entity.java
  22. 50
      src/mightypork/rogue/world/entity/EntityData.java
  23. 52
      src/mightypork/rogue/world/entity/models/EntityModel.java
  24. 8
      src/mightypork/rogue/world/entity/models/EntityMoveListener.java
  25. 32
      src/mightypork/rogue/world/entity/models/PlayerModel.java
  26. 8
      src/mightypork/rogue/world/entity/renderers/PlayerRenderer.java
  27. 8
      src/mightypork/rogue/world/gen/LevelGenerator.java
  28. 4
      src/mightypork/rogue/world/gen/RoomDesc.java
  29. 290
      src/mightypork/rogue/world/gen/ScratchMap.java
  30. 9
      src/mightypork/rogue/world/gen/rooms/DeadEndRoom.java
  31. 25
      src/mightypork/rogue/world/gen/rooms/SimpleRectRoom.java
  32. 153
      src/mightypork/rogue/world/level/Level.java
  33. 6
      src/mightypork/rogue/world/level/MapAccess.java
  34. 5
      src/mightypork/rogue/world/level/render/MapRenderContext.java
  35. 16
      src/mightypork/rogue/world/level/render/TileRenderContext.java
  36. 34
      src/mightypork/rogue/world/pathfinding/PathFinder.java
  37. 8
      src/mightypork/rogue/world/pathfinding/PathFindingContext.java
  38. 1
      src/mightypork/rogue/world/tile/Tile.java
  39. 13
      src/mightypork/rogue/world/tile/TileGenData.java
  40. 2
      src/mightypork/rogue/world/tile/TileRenderData.java
  41. 18
      src/mightypork/rogue/world/tile/Tiles.java
  42. 25
      src/mightypork/rogue/world/tile/models/NullFloor.java
  43. 10
      src/mightypork/rogue/world/tile/models/NullTile.java
  44. 4
      src/mightypork/util/control/eventbus/BusEvent.java
  45. 4
      src/mightypork/util/control/eventbus/EventChannel.java
  46. 4
      src/mightypork/util/control/eventbus/clients/BusNode.java
  47. 4
      src/mightypork/util/files/FileTreeDiff.java
  48. 24
      src/mightypork/util/files/FileUtils.java
  49. 8
      src/mightypork/util/files/OsUtils.java
  50. 4
      src/mightypork/util/files/config/PropertyManager.java
  51. 4
      src/mightypork/util/files/config/SortedProperties.java
  52. 16
      src/mightypork/util/files/ion/Ion.java
  53. 4
      src/mightypork/util/files/ion/IonOutput.java
  54. 8
      src/mightypork/util/logging/Log.java
  55. 4
      src/mightypork/util/logging/writers/ArchivingLog.java
  56. 8
      src/mightypork/util/math/Calc.java
  57. 12
      src/mightypork/util/math/color/Color.java
  58. 4
      src/mightypork/util/math/constraints/rect/Rect.java
  59. 8
      src/mightypork/util/math/constraints/rect/builders/TiledRect.java
  60. 8
      src/mightypork/util/objects/Convert.java
  61. 8
      src/mightypork/util/objects/Pair.java
  62. 4
      src/mightypork/util/objects/VarargsParser.java
  63. 4
      src/mightypork/util/string/filtering/FileSuffixFilter.java
  64. 8
      src/mightypork/util/timing/TimerFps.java

@ -70,9 +70,7 @@ public class SoundBank extends AppAdapter {
public LoopPlayer getLoop(String key)
{
final LoopPlayer p = loops.get(key);
if (p == null) {
throw new RuntimeException("Unknown sound loop \"" + key + "\".");
}
if (p == null) { throw new RuntimeException("Unknown sound loop \"" + key + "\"."); }
return p;
}
@ -86,9 +84,7 @@ public class SoundBank extends AppAdapter {
public EffectPlayer getEffect(String key)
{
final EffectPlayer p = effects.get(key);
if (p == null) {
throw new RuntimeException("Unknown sound effect \"" + key + "\".");
}
if (p == null) { throw new RuntimeException("Unknown sound effect \"" + key + "\"."); }
return p;
}
}

@ -34,9 +34,7 @@ public class HorizontalFixedFlowLayout extends LayoutComponent {
this.colWidth = elementWidth;
this.align = align;
if (align != AlignX.LEFT && align != AlignX.RIGHT) {
throw new IllegalArgumentException("Can align only left or right.");
}
if (align != AlignX.LEFT && align != AlignX.RIGHT) { throw new IllegalArgumentException("Can align only left or right."); }
}

@ -34,9 +34,7 @@ public class VerticalFixedFlowLayout extends LayoutComponent {
this.rowHeight = elementHeight;
this.align = align;
if (align != AlignY.TOP && align != AlignY.BOTTOM) {
throw new IllegalArgumentException("Can align only to top or bottom.");
}
if (align != AlignY.TOP && align != AlignY.BOTTOM) { throw new IllegalArgumentException("Can align only to top or bottom."); }
}

@ -69,9 +69,7 @@ public class ScreenRegistry extends AppModule implements ScreenRequestListener,
// find screen to show
final Screen toShow = screens.get(key);
if (toShow == null) {
throw new RuntimeException("Screen " + key + " not defined.");
}
if (toShow == null) { throw new RuntimeException("Screen " + key + " not defined."); }
// deactivate last screen
if (active != null) {

@ -82,9 +82,7 @@ public class KeyStroke {
if (keys == null) {
if (other.keys != null) return false;
} else if (!keys.equals(other.keys)) {
return false;
}
} else if (!keys.equals(other.keys)) { return false; }
if (fallingEdge != other.fallingEdge) return false;

@ -41,9 +41,7 @@ public abstract class DeferredResource implements Deferred, Destroyable {
loadFailed = false;
try {
if (resource == null) {
throw new NullPointerException("Resource string cannot be null for non-null resource.");
}
if (resource == null) { throw new NullPointerException("Resource string cannot be null for non-null resource."); }
Log.f3("<RES> Loading: " + this);
loadResource(resource);

@ -80,9 +80,7 @@ public class FontBank extends AppAdapter {
if (f == null) f = fonts.get(aliases.get(key));
if (f == null) {
throw new RuntimeException("There's no font called " + key + "!");
}
if (f == null) { throw new RuntimeException("There's no font called " + key + "!"); }
return f;
}

@ -37,9 +37,7 @@ public class QuadGrid {
*/
public TxQuad makeQuad(int x, int y)
{
if (x < 0 || x >= txWidth || y < 0 || y >= txHeight) {
throw new IndexOutOfBoundsException("Requested invalid txquad coordinates.");
}
if (x < 0 || x >= txWidth || y < 0 || y >= txHeight) { throw new IndexOutOfBoundsException("Requested invalid txquad coordinates."); }
return makeQuad(x, y, 1, 1);
}
@ -57,13 +55,9 @@ public class QuadGrid {
*/
public TxQuad makeQuad(double x, double y, double width, double height)
{
if (x < 0 || x >= txWidth || y < 0 || y >= txHeight) {
throw new IndexOutOfBoundsException("Requested invalid txquad coordinates.");
}
if (x < 0 || x >= txWidth || y < 0 || y >= txHeight) { throw new IndexOutOfBoundsException("Requested invalid txquad coordinates."); }
if (x + width > txWidth || y + height > txHeight) {
throw new IndexOutOfBoundsException("Requested invalid txquad size (would go beyond texture size).");
}
if (x + width > txWidth || y + height > txHeight) { throw new IndexOutOfBoundsException("Requested invalid txquad size (would go beyond texture size)."); }
return tx.makeQuad(Rect.make(tileW * x, tileH * y, tileW * width, tileH * height));
}
@ -80,13 +74,10 @@ public class QuadGrid {
*/
public TxSheet makeSheet(int x, int y, int width, int height)
{
if (x < 0 || x >= txWidth || y < 0 || y >= txHeight) {
throw new IndexOutOfBoundsException("Requested invalid txquad coordinates.");
}
if (x < 0 || x >= txWidth || y < 0 || y >= txHeight) { throw new IndexOutOfBoundsException("Requested invalid txquad coordinates."); }
if (x + width > txWidth || y + height > txHeight) {
throw new IndexOutOfBoundsException("Requested invalid txsheet size (would go beyond texture size).");
}
if (x + width > txWidth || y + height > txHeight) { throw new IndexOutOfBoundsException(
"Requested invalid txsheet size (would go beyond texture size)."); }
return makeQuad(x, y).makeSheet(width, height);
}

@ -2,36 +2,39 @@ package mightypork.rogue.screens.gamescreen.world;
import mightypork.gamecore.input.InputSystem;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.PlayerControl;
import mightypork.rogue.world.WorldPos;
import mightypork.util.math.constraints.vect.Vect;
public class MIPClickPathfWalk implements MapInteractionPlugin {
private static final int BTN = 1; // right
@Override
public void onStepEnd(MapView wv, PlayerControl player)
public void onStepEnd(MapView view, PlayerControl player)
{
if (InputSystem.isMouseButtonDown(0)) {
final WorldPos clicked = wv.toWorldPos(InputSystem.getMousePos());
if (InputSystem.isMouseButtonDown(BTN)) {
final Coord clicked = view.toWorldPos(InputSystem.getMousePos());
player.navigateTo(clicked);
}
}
@Override
public void onClick(MapView wv, PlayerControl player, Vect mouse, int button, boolean down)
public void onClick(MapView view, PlayerControl player, Vect mouse, int button, boolean down)
{
if (!down) return;
if (!down || button != BTN) return;
final WorldPos clicked = wv.toWorldPos(mouse);
final Coord clicked = view.toWorldPos(mouse);
player.navigateTo(clicked);
}
@Override
public void onKey(MapView wv, PlayerControl player, int key, boolean down)
public void onKey(MapView view, PlayerControl player, int key, boolean down)
{
}

@ -10,20 +10,20 @@ import mightypork.util.math.constraints.vect.Vect;
public class MIPKeyWalk implements MapInteractionPlugin {
@Override
public void onStepEnd(MapView wv, PlayerControl player)
public void onStepEnd(MapView view, PlayerControl player)
{
walkByKey(player);
}
@Override
public void onClick(MapView wv, PlayerControl player, Vect mouse, int button, boolean down)
public void onClick(MapView view, PlayerControl player, Vect mouse, int button, boolean down)
{
}
@Override
public void onKey(MapView wv, PlayerControl player, int key, boolean down)
public void onKey(MapView view, PlayerControl player, int key, boolean down)
{
if (down) walkByKey(player);
}

@ -2,8 +2,8 @@ package mightypork.rogue.screens.gamescreen.world;
import mightypork.gamecore.input.InputSystem;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.PlayerControl;
import mightypork.rogue.world.WorldPos;
import mightypork.util.math.Calc.Deg;
import mightypork.util.math.Polar;
import mightypork.util.math.constraints.vect.Vect;
@ -12,22 +12,22 @@ import mightypork.util.math.constraints.vect.Vect;
public class MIPMouseWalk implements MapInteractionPlugin {
@Override
public void onStepEnd(MapView wv, PlayerControl player)
public void onStepEnd(MapView world, PlayerControl player)
{
if (InputSystem.isMouseButtonDown(0)) {
// walk by holding btn
onClick(wv, player, InputSystem.getMousePos(), 0, true);
onClick(world, player, InputSystem.getMousePos(), 0, true);
}
}
@Override
public void onClick(MapView wv, PlayerControl player, Vect mouse, int button, boolean down)
public void onClick(MapView world, PlayerControl player, Vect mouse, int button, boolean down)
{
if (!down) return;
final WorldPos plpos = player.getPos();
final WorldPos clicked = wv.toWorldPos(mouse);
final Coord plpos = player.getCoord();
final Coord clicked = world.toWorldPos(mouse);
final Polar p = Polar.fromCoord(clicked.x - plpos.x, clicked.y - plpos.y);
@ -54,7 +54,7 @@ public class MIPMouseWalk implements MapInteractionPlugin {
@Override
public void onKey(MapView wv, PlayerControl player, int key, boolean down)
public void onKey(MapView world, PlayerControl player, int key, boolean down)
{
}

@ -9,13 +9,12 @@ import mightypork.gamecore.control.events.input.KeyListener;
import mightypork.gamecore.control.events.input.MouseButtonEvent;
import mightypork.gamecore.control.events.input.MouseButtonListener;
import mightypork.gamecore.gui.components.InputComponent;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.PlayerControl;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.WorldRenderer;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.models.EntityMoveListener;
import mightypork.rogue.world.level.Level;
import mightypork.util.math.constraints.vect.Vect;
@ -31,7 +30,7 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL
public MapView(World world)
{
this.world = world;
this.worldRenderer = new WorldRenderer(world, this, 12, 8, 40);//8, 8, 64
this.worldRenderer = new WorldRenderer(world, this, 12, 8, 32);//8, 8, 64
pc = world.getPlayerControl();
pc.addMoveListener(this);
}
@ -57,14 +56,14 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL
* @param pos position on screen (px)
* @return position on map (tiles)
*/
public WorldPos toWorldPos(Vect pos)
public Coord toWorldPos(Vect pos)
{
return worldRenderer.getClickedTile(pos);
}
@Override
public void onStepFinished(Entity entity, World world, Level level)
public void onStepFinished(Entity entity)
{
for (final MapInteractionPlugin p : plugins) {
p.onStepEnd(this, pc);
@ -73,7 +72,7 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL
@Override
public void onPathFinished(Entity entity, World world, Level level)
public void onPathFinished(Entity entity)
{
for (final MapInteractionPlugin p : plugins) {
p.onStepEnd(this, pc);
@ -82,7 +81,7 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL
@Override
public void onPathInterrupted(Entity entity, World world, Level level)
public void onPathInterrupted(Entity entity)
{
for (final MapInteractionPlugin p : plugins) {
p.onStepEnd(this, pc);

@ -1,11 +1,19 @@
package mightypork.rogue.world;
import java.io.IOException;
import mightypork.util.annotations.FactoryMethod;
import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.IonBundled;
// coord
public class Coord {
/**
* Coordinate
*
* @author MightyPork
*/
public class Coord implements IonBundled {
public int x;
public int y;
@ -25,6 +33,13 @@ public class Coord {
}
@FactoryMethod
public static Coord zero()
{
return make(0, 0);
}
public Coord(int x, int y)
{
super();
@ -58,6 +73,44 @@ public class Coord {
}
public void setTo(int x, int y)
{
this.x = x;
this.y = y;
}
public void setTo(Coord pos)
{
setTo(pos.x, pos.y);
}
/**
* Check if coord is in a range (inclusive)
*/
public boolean isInRange(int x0, int y0, int x1, int y1)
{
return !(x < x0 || x > x1 || y < y0 || y > y1);
}
@Override
public void load(IonBundle bundle) throws IOException
{
x = bundle.get("x", 0);
y = bundle.get("y", 0);
}
@Override
public void save(IonBundle bundle) throws IOException
{
bundle.put("x", x);
bundle.put("y", y);
}
@Override
public String toString()
{
@ -87,5 +140,4 @@ public class Coord {
if (y != other.y) return false;
return true;
}
}

@ -12,25 +12,29 @@ import mightypork.util.timing.Updateable;
/**
* A simple dimension data object
* Entity position
*
* @author MightyPork
*/
public class WorldPos implements IonBundled, Updateable {
public class EntityPos implements IonBundled, Updateable {
public int x, y;
private final Coord coord = new Coord(0, 0);
private final VectAnimated walkOffset = new VectAnimated(Vect.ZERO, Easing.LINEAR);
public WorldPos(int x, int y)
public EntityPos(Coord pos)
{
super();
this.x = x;
this.y = y;
this.coord.setTo(pos);
}
public WorldPos()
public EntityPos(int x, int y)
{
this.coord.setTo(x, y);
}
public EntityPos()
{
}
@ -44,8 +48,7 @@ public class WorldPos implements IonBundled, Updateable {
@Override
public void load(IonBundle in) throws IOException
{
x = in.get("x", 0);
y = in.get("y", 0);
in.loadBundled("pos", coord);
walkOffset.reset();
}
@ -53,42 +56,41 @@ public class WorldPos implements IonBundled, Updateable {
@Override
public void save(IonBundle out) throws IOException
{
out.put("x", x);
out.put("y", y);
out.putBundled("pos", coord);
}
public double getX()
public int x()
{
return x;
return coord.x;
}
public double getY()
public int y()
{
return y;
return coord.y;
}
public double getVisualX()
public double visualX()
{
return x + walkOffset.x();
return coord.x + walkOffset.x();
}
public double getVisualY()
public double visualY()
{
return y + walkOffset.y();
return coord.y + walkOffset.y();
}
public double getVisualXOffset()
public double visualXOffset()
{
return walkOffset.x();
}
public double getVisualYOffset()
public double visualYOffset()
{
return walkOffset.y();
}
@ -96,53 +98,37 @@ public class WorldPos implements IonBundled, Updateable {
public void setTo(int x, int y)
{
this.x = x;
this.y = y;
coord.setTo(x, y);
walkOffset.reset();
}
public void setTo(WorldPos other)
public void setTo(EntityPos pos)
{
setTo(other.x, other.y);
}
setTo(pos.getCoord());
@Override
public String toString()
{
return "WorldPos(" + x + "," + y + ")";
}
@Override
public int hashCode()
public void setTo(Coord c)
{
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
coord.setTo(c);
walkOffset.reset();
}
@Override
public boolean equals(Object obj)
public String toString()
{
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof WorldPos)) return false;
final WorldPos other = (WorldPos) obj;
if (x != other.x) return false;
if (y != other.y) return false;
return true;
return "EntityPos{" + coord + "}";
}
public void walk(int x, int y, double secs)
public void walk(PathStep step, double secs)
{
setTo(this.x + x, this.y + y);
walkOffset.setTo(-x, -y);
setTo(coord.x + step.x, coord.y + step.y);
walkOffset.setTo(-step.x, -step.y);
walkOffset.animate(0, 0, 0, secs);
}
@ -160,9 +146,33 @@ public class WorldPos implements IonBundled, Updateable {
}
public Coord toCoord()
public Coord getCoord()
{
return new Coord(x, y);
return coord;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((coord == null) ? 0 : coord.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof EntityPos)) return false;
final EntityPos other = (EntityPos) obj;
if (coord == null) {
if (other.coord != null) return false;
} else if (!coord.equals(other.coord)) return false;
return true;
}
}

@ -8,6 +8,12 @@ import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
/**
* Path step.<br>
* Must be binary in order to be saveable in lists.
*
* @author MightyPork
*/
public class PathStep implements IonBinary {
public static final PathStep NORTH = new PathStep(0, -1);
@ -59,6 +65,12 @@ public class PathStep implements IonBinary {
}
public Coord toCoord()
{
return Coord.make(x, y);
}
@Override
public short getIonMark()
{
@ -69,7 +81,7 @@ public class PathStep implements IonBinary {
@Override
public String toString()
{
return "(" + x + "|" + y + ")";
return "(" + x + ";" + y + ")";
}
}

@ -1,43 +1,15 @@
package mightypork.rogue.world;
import java.util.List;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.models.EntityMoveListener;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.pathfinding.PathCostProvider;
import mightypork.rogue.world.pathfinding.PathFinder;
public class PlayerControl {
private final World world;
PathCostProvider costProvider = new PathCostProvider() {
@Override
public boolean isAccessible(Coord pos)
{
return getLevel().canWalkInto(pos.x, pos.y);
}
@Override
public int getMinCost()
{
return 10;
}
@Override
public int getCost(Coord from, Coord to)
{
return 10;
}
};
private final PathFinder pf = new PathFinder(costProvider, PathFinder.CORNER_HEURISTIC);
public PlayerControl(World w)
{
@ -45,56 +17,55 @@ public class PlayerControl {
}
public Entity getEntity()
{
return world.getPlayerEntity();
}
public void goNorth()
{
world.getPlayerEntity().cancelPath();
world.getPlayerEntity().addStep(PathStep.NORTH);
getEntity().cancelPath();
getEntity().addStep(PathStep.NORTH);
}
public void goSouth()
{
world.getPlayerEntity().cancelPath();
world.getPlayerEntity().addStep(PathStep.SOUTH);
getEntity().cancelPath();
getEntity().addStep(PathStep.SOUTH);
}
public void goEast()
{
world.getPlayerEntity().cancelPath();
world.getPlayerEntity().addStep(PathStep.EAST);
getEntity().cancelPath();
getEntity().addStep(PathStep.EAST);
}
public void goWest()
{
world.getPlayerEntity().cancelPath();
world.getPlayerEntity().addStep(PathStep.WEST);
getEntity().cancelPath();
getEntity().addStep(PathStep.WEST);
}
public void navigateTo(WorldPos where)
public void navigateTo(Coord pos)
{
final Coord start = world.getPlayerEntity().getPosition().toCoord();
final Coord end = where.toCoord();
final List<PathStep> path = pf.findPathRelative(start, end);
if (path == null) return;
world.getPlayerEntity().cancelPath();
world.getPlayerEntity().addSteps(path);
getEntity().navigateTo(pos);
}
public void addMoveListener(EntityMoveListener eml)
{
world.getPlayerEntity().addMoveListener(eml);
getEntity().addMoveListener(eml);
}
public WorldPos getPos()
public EntityPos getPos()
{
return world.getPlayerEntity().getPosition();
return getEntity().getPosition();
}
@ -108,4 +79,10 @@ public class PlayerControl {
{
return world.getCurrentLevel();
}
public Coord getCoord()
{
return getEntity().getCoord();
}
}

@ -26,8 +26,11 @@ public class World implements IonBundled, Updateable {
private final PlayerControl control = new PlayerControl(this);
private long seed; // world seed
private int eid; // next entity ID
/** World seed */
private long seed;
/** Next entity ID */
private int eid;
@Override
@ -36,6 +39,12 @@ public class World implements IonBundled, Updateable {
seed = in.get("seed", 0L);
eid = in.get("next_eid", 0);
in.loadSequence("levels", levels);
// join levels to world
for (final Level lvl : levels) {
lvl.setWorld(this);
}
in.loadBundled("player", playerInfo);
playerEntity = levels.get(playerInfo.getLevel()).getEntity(playerInfo.getEID());
@ -61,7 +70,7 @@ public class World implements IonBundled, Updateable {
@Override
public void update(double delta)
{
getCurrentLevel().update(this, delta);
getCurrentLevel().update(delta);
}
@ -86,27 +95,19 @@ public class World implements IonBundled, Updateable {
}
public void createPlayer(WorldPos pos, int level)
{
createPlayer(pos.x, pos.y, level);
}
public void createPlayer(int x, int y, int level)
public void createPlayer(int level)
{
if (playerInfo.isInitialized()) {
throw new RuntimeException("Player already created.");
}
if (playerInfo.isInitialized()) { throw new RuntimeException("Player already created."); }
// make entity
final int playerEid = getNewEID();
playerEntity = Entities.PLAYER.createEntity(playerEid, new WorldPos(x, y));
playerEntity = Entities.PLAYER.createEntity(playerEid);
levels.get(level).addEntity(playerEntity);
playerEntity.setPosition(levels.get(level).getEnterPoint());
playerInfo.setLevel(level);
playerInfo.setEID(playerEid);
levels.get(level).addEntity(playerEntity);
}

@ -23,9 +23,10 @@ public class WorldCreator {
Level l;
// first level
l = LevelGenerator.build(rand.nextLong(), LevelGenerator.DUNGEON_THEME);
l = LevelGenerator.build(rand.nextLong(), 2, LevelGenerator.DUNGEON_THEME); //
w.addLevel(l);
w.createPlayer(l.getEnterPoint(), 0);
w.createPlayer(0);
return w;
}

@ -83,9 +83,9 @@ public class WorldRenderer extends RectProxy implements Pollable {
private Vect getOffset()
{
final WorldPos pos = player.getPosition();
final double playerX = pos.getVisualX();
final double playerY = pos.getVisualY();
final EntityPos pos = player.getPosition();
final double playerX = pos.visualX();
final double playerY = pos.visualY();
final double ts = tileSize.value();
@ -100,7 +100,7 @@ public class WorldRenderer extends RectProxy implements Pollable {
Render.translate(getOffset());
// tiles to render
final WorldPos pos = player.getPosition();
final EntityPos pos = player.getPosition();
final double w = width().value();
final double h = height().value();
final double ts = tileSize.value();
@ -108,10 +108,10 @@ public class WorldRenderer extends RectProxy implements Pollable {
final int xtilesh = (int) (w / (ts * 2)) + 1;
final int ytilesh = (int) (h / (ts * 2)) + 1;
final int x1 = pos.x - xtilesh;
final int y1 = pos.y - ytilesh;
final int x2 = pos.x + xtilesh;
final int y2 = pos.y + ytilesh;
final int x1 = pos.x() - xtilesh;
final int y1 = pos.y() - ytilesh;
final int x2 = pos.x() + xtilesh;
final int y2 = pos.y() + ytilesh;
// === TILES ===
@ -120,8 +120,8 @@ public class WorldRenderer extends RectProxy implements Pollable {
Render.enterBatchTexturedQuadMode(Res.getTexture("tiles16"));
}
for (trc.y = y1; trc.y <= y2; trc.y++) {
for (trc.x = x1; trc.x <= x2; trc.x++) {
for (trc.pos.x = x1; trc.pos.x <= x2; trc.pos.x++) {
for (trc.pos.y = y1; trc.pos.y <= y2; trc.pos.y++) {
trc.renderTile();
}
}
@ -132,8 +132,8 @@ public class WorldRenderer extends RectProxy implements Pollable {
// === ITEMS ON TILES ===
for (trc.y = y1; trc.y <= y2; trc.y++) {
for (trc.x = x1; trc.x <= x2; trc.x++) {
for (trc.pos.x = x1; trc.pos.x <= x2; trc.pos.x++) {
for (trc.pos.y = y1; trc.pos.y <= y2; trc.pos.y++) {
trc.renderItems();
}
}
@ -143,8 +143,8 @@ public class WorldRenderer extends RectProxy implements Pollable {
for (final Entity e : activeLevel.getEntities()) {
// avoid entities out of view rect
final int x = (int) Math.round(e.getPosition().getVisualX());
final int y = (int) Math.round(e.getPosition().getVisualY());
final int x = (int) Math.round(e.getPosition().visualX());
final int y = (int) Math.round(e.getPosition().visualY());
if (x < x1 - ts || x > x2 + ts) continue;
if (y < y1 - ts || y > y2 + ts) continue;
@ -164,11 +164,11 @@ public class WorldRenderer extends RectProxy implements Pollable {
}
public WorldPos getClickedTile(Vect clickPos)
public Coord getClickedTile(Vect clickPos)
{
final Vect v = clickPos.sub(mapRect.origin().add(getOffset()));
final int ts = (int) tileSize.value();
return new WorldPos(v.xi() / ts, v.yi() / ts);
return new Coord(v.xi() / ts, v.yi() / ts);
}

@ -19,13 +19,9 @@ public final class Entities {
public static void register(int id, EntityModel model)
{
if (id < 0 || id >= entities.length) {
throw new IllegalArgumentException("Entity model ID " + id + " is out of range.");
}
if (id < 0 || id >= entities.length) { throw new IllegalArgumentException("Entity model ID " + id + " is out of range."); }
if (entities[id] != null) {
throw new IllegalArgumentException("Entity model ID " + id + " already in use.");
}
if (entities[id] != null) { throw new IllegalArgumentException("Entity model ID " + id + " already in use."); }
entities[id] = model;
}
@ -35,9 +31,7 @@ public final class Entities {
{
final EntityModel e = entities[id];
if (e == null) {
throw new IllegalArgumentException("No entity model with ID " + id + ".");
}
if (e == null) { throw new IllegalArgumentException("No entity model with ID " + id + "."); }
return e;
}

@ -3,20 +3,21 @@ package mightypork.rogue.world.entity;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.EntityPos;
import mightypork.rogue.world.PathStep;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.entity.models.EntityModel;
import mightypork.rogue.world.entity.models.EntityMoveListener;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.level.render.MapRenderContext;
import mightypork.rogue.world.pathfinding.Heuristic;
import mightypork.rogue.world.pathfinding.PathFinder;
import mightypork.rogue.world.pathfinding.PathFindingContext;
import mightypork.util.files.ion.IonBinary;
import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.IonBundled;
import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
@ -26,51 +27,68 @@ import mightypork.util.files.ion.IonOutput;
*
* @author MightyPork
*/
public final class Entity implements IonBinary, IonBundled, EntityMoveListener {
// binary & bundled - binary stores via a bundle
public final class Entity implements IonBinary, EntityMoveListener {
public static final int ION_MARK = 52;
private final WorldPos position = new WorldPos(); // saved
private final WorldPos lastPosition = new WorldPos();
/** Last pos, will be freed upon finishing move */
private final EntityPos lastPosition = new EntityPos();
private boolean walking = false;
private Level level;
private EntityModel model;
/** Entity ID */
private int eid = 0; // saved
private int entityId = -1;
/** Model ID */
private int id; // saved
private int modelId = -1;
private final Queue<PathStep> path = new LinkedList<>(); // saved
private EntityModel model;
public final IonBundle metadata = new IonBundle(); // saved
/** Entity data holder */
private final EntityData data = new EntityData();
/** Some infos for/by the renderer, not saved */
/** Temporary renderer's data */
public final EntityRenderData renderData = new EntityRenderData();
private final List<EntityMoveListener> moveListeners = new ArrayList<>();
// tmp flag
private boolean walking = false;
private final PathFindingContext pfc = new PathFindingContext() {
@Override
public boolean isAccessible(Coord pos)
{
return model.canWalkInto(Entity.this, pos);
}
public Entity(int eid, WorldPos pos, EntityModel entityModel)
{
this.eid = eid;
setPosition(pos);
setModel(entityModel);
}
@Override
public int getMinCost()
{
return model.getPathMinCost();
}
@Override
public Heuristic getHeuristic()
{
return model.getPathHeuristic();
}
@Override
public int getCost(Coord from, Coord to)
{
return model.getPathCost(Entity.this, from, to);
}
};
protected final void setModel(EntityModel entityModel)
public Entity(int eid, EntityModel entityModel)
{
// replace listener
if (model != null) moveListeners.remove(model);
moveListeners.add(entityModel);
this.entityId = eid;
setModel(entityModel);
this.id = entityModel.id;
this.model = entityModel;
model.initMetadata(data);
}
@ -80,124 +98,115 @@ public final class Entity implements IonBinary, IonBundled, EntityMoveListener {
}
@Override
public short getIonMark()
private void setModel(EntityModel entityModel)
{
return ION_MARK;
// replace listener
if (model != null) moveListeners.remove(model);
moveListeners.add(entityModel);
this.modelId = entityModel.id;
this.model = entityModel;
}
@Override
public void save(IonOutput out) throws IOException
public Level getLevel()
{
final IonBundle ib = new IonBundle();
save(ib);
out.writeBundle(ib);
if (level == null) throw new IllegalStateException("Entity has no level assigned.");
return level;
}
@Override
public void load(IonInput in) throws IOException
public World getWorld()
{
load(in.readBundle());
return getLevel().getWorld();
}
@Override
public void save(IonBundle bundle) throws IOException
public short getIonMark()
{
bundle.put("id", id);
bundle.putBundled("pos", position);
bundle.putSequence("steps", path);
bundle.put("eid", eid);
if (model.hasMetadata()) {
bundle.put("metadata", metadata);
}
return ION_MARK;
}
@Override
public void load(IonBundle bundle) throws IOException
public void save(IonOutput out) throws IOException
{
id = bundle.get("id", 0);
final IonBundle bundle = new IonBundle();
bundle.put("model", modelId);
bundle.put("id", entityId);
bundle.putBundled("data", data);
if (model == null || id != model.id) {
setModel(Entities.get(id));
}
out.writeBundle(bundle);
}
bundle.loadBundled("pos", position);
bundle.loadSequence("path", path);
eid = bundle.get("eid", eid);
if (model.hasMetadata()) {
metadata.clear();
bundle.loadBundle("metadata", metadata);
}
@Override
public void load(IonInput in) throws IOException
{
final IonBundle bundle = in.readBundle();
modelId = bundle.get("model", 0);
entityId = bundle.get("id", entityId);
bundle.loadBundled("data", data);
setModel(Entities.get(modelId));
}
/**
* @return unique entity id
*/
public int getEID()
{
return eid;
}
public WorldPos getPosition()
public int getEntityId()
{
return position;
return entityId;
}
public final void setPosition(WorldPos pos)
public EntityPos getPosition()
{
setPosition(pos.x, pos.y);
return data.position;
}
public void setPosition(int x, int y)
public void setPosition(Coord coord)
{
position.setTo(x, y);
lastPosition.setTo(x, y);
data.position.setTo(coord);
lastPosition.setTo(coord);
cancelPath(); // discard remaining steps
}
/**
* @param world the world
* @param delta delta time
*/
public void update(World world, Level level, double delta)
public void update(double delta)
{
if (!position.isFinished()) {
position.update(delta);
if (!data.position.isFinished()) {
data.position.update(delta);
}
if (walking && position.isFinished()) {
if (walking && data.position.isFinished()) {
walking = false;
level.freeTile(lastPosition.x, lastPosition.y);
level.freeTile(lastPosition.getCoord());
onStepFinished(this, world, level);
onStepFinished(this);
if (path.isEmpty()) {
onPathFinished(this, world, level);
if (data.path.isEmpty()) {
onPathFinished(this);
}
}
if (!walking && !path.isEmpty()) {
if (!walking && !data.path.isEmpty()) {
walking = true;
final PathStep step = path.poll();
final PathStep step = data.path.poll();
final int projX = position.x + step.x, projY = position.y + step.y;
final Coord planned = data.position.getCoord().add(step.toCoord());
if (!level.canWalkInto(projX, projY)) {
if (!level.canWalkInto(planned)) {
cancelPath();
onPathInterrupted(this, world, level);
onPathInterrupted(this);
walking = false;
} else {
@ -205,14 +214,14 @@ public final class Entity implements IonBinary, IonBundled, EntityMoveListener {
if (step.x != 0) renderData.lastXDir = step.x;
if (step.y != 0) renderData.lastYDir = step.y;
lastPosition.setTo(position);
position.walk(step.x, step.y, getStepTime());
level.occupyTile(projX, projY);
lastPosition.setTo(data.position);
data.position.walk(step, model.getStepTime(this));
level.occupyTile(planned);
}
}
if (!walking) {
model.update(this, level, delta);
model.update(this, delta);
}
}
@ -225,51 +234,57 @@ public final class Entity implements IonBinary, IonBundled, EntityMoveListener {
public boolean isPathFinished()
{
return position.isFinished() && path.isEmpty();
return data.position.isFinished() && data.path.isEmpty();
}
public void addStep(PathStep step)
{
path.add(step);
data.path.add(step);
}
public void cancelPath()
{
path.clear();
data.path.clear();
}
protected double getStepTime()
public boolean navigateTo(Coord pos)
{
return model.getStepTime(this);
final List<PathStep> path = PathFinder.findPathRelative(pfc, getPosition().getCoord(), pos);
if (path == null) return false;
this.cancelPath();
this.addSteps(path);
return true;
}
@Override
public void onStepFinished(Entity entity, World world, Level level)
public void onStepFinished(Entity entity)
{
for (final EntityMoveListener l : moveListeners) {
l.onStepFinished(entity, world, level);
l.onStepFinished(entity);
}
}
@Override
public void onPathFinished(Entity entity, World world, Level level)
public void onPathFinished(Entity entity)
{
for (final EntityMoveListener l : moveListeners) {
l.onStepFinished(entity, world, level);
l.onStepFinished(entity);
}
}
@Override
public void onPathInterrupted(Entity entity, World world, Level level)
public void onPathInterrupted(Entity entity)
{
for (final EntityMoveListener l : moveListeners) {
l.onPathInterrupted(entity, world, level);
l.onPathInterrupted(entity);
}
}
@ -282,6 +297,18 @@ public final class Entity implements IonBinary, IonBundled, EntityMoveListener {
public void addSteps(List<PathStep> path)
{
this.path.addAll(path);
data.path.addAll(path);
}
public void setLevel(Level level)
{
this.level = level;
}
public Coord getCoord()
{
return data.position.getCoord();
}
}

@ -0,0 +1,50 @@
package mightypork.rogue.world.entity;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import mightypork.rogue.world.EntityPos;
import mightypork.rogue.world.PathStep;
import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.IonBundled;
public class EntityData implements IonBundled {
public int health = 1;
public int maxHealth = 1;
public boolean dead = false;
public final IonBundle extra = new IonBundle();
public final Queue<PathStep> path = new LinkedList<>();
public final EntityPos position = new EntityPos();
@Override
public void save(IonBundle bundle) throws IOException
{
bundle.put("health", health);
bundle.put("max_health", maxHealth);
bundle.put("dead", dead);
bundle.putSequence("steps", path);
bundle.putBundled("pos", position);
bundle.put("extra", extra);
}
@Override
public void load(IonBundle bundle) throws IOException
{
health = bundle.get("health", health);
maxHealth = bundle.get("max_health", maxHealth);
dead = bundle.get("dead", dead);
bundle.loadSequence("path", path);
bundle.loadBundled("pos", position);
bundle.loadBundle("extra", extra);
}
}

@ -1,12 +1,13 @@
package mightypork.rogue.world.entity.models;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityData;
import mightypork.rogue.world.entity.renderers.EntityRenderer;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.pathfinding.Heuristic;
import mightypork.rogue.world.pathfinding.PathFinder;
/**
@ -38,22 +39,16 @@ public abstract class EntityModel implements EntityMoveListener {
/**
* @return new tile of this type; if 100% invariant, can return cached one.
*/
public Entity createEntity(int eid, WorldPos pos)
public Entity createEntity(int eid)
{
return new Entity(eid, pos, this);
return new Entity(eid, this);
}
/**
* Entity is idle, waiting for action.
*/
public abstract void update(Entity entity, Level level, double delta);
/**
* @return true if this entity type has metadata worth saving
*/
public abstract boolean hasMetadata();
public abstract void update(Entity entity, double delta);
/**
@ -63,14 +58,41 @@ public abstract class EntityModel implements EntityMoveListener {
@Override
public abstract void onStepFinished(Entity entity, World world, Level level);
public abstract void onStepFinished(Entity entity);
@Override
public abstract void onPathFinished(Entity entity, World world, Level level);
public abstract void onPathFinished(Entity entity);
@Override
public abstract void onPathInterrupted(Entity entity, World world, Level level);
public abstract void onPathInterrupted(Entity entity);
public boolean canWalkInto(Entity entity, Coord pos)
{
return entity.getLevel().canWalkInto(pos);
}
public int getPathMinCost()
{
return 10;
}
public Heuristic getPathHeuristic()
{
return PathFinder.DIAGONAL_HEURISTIC;
}
public int getPathCost(Entity entity, Coord from, Coord to)
{
return 10;
}
public abstract void initMetadata(EntityData metadata);
}

@ -1,9 +1,7 @@
package mightypork.rogue.world.entity.models;
import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.level.Level;
public interface EntityMoveListener {
@ -11,18 +9,18 @@ public interface EntityMoveListener {
/**
* One step of a path finished
*/
void onStepFinished(Entity entity, World world, Level level);
void onStepFinished(Entity entity);
/**
* Scheduled path finished
*/
void onPathFinished(Entity entity, World world, Level level);
void onPathFinished(Entity entity);
/**
* Path was interrupted (bumped into a wall or entity)
*/
void onPathInterrupted(Entity entity, World world, Level level);
void onPathInterrupted(Entity entity);
}

@ -1,11 +1,9 @@
package mightypork.rogue.world.entity.models;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityData;
import mightypork.rogue.world.entity.renderers.PlayerRenderer;
import mightypork.rogue.world.level.Level;
/**
@ -15,7 +13,7 @@ import mightypork.rogue.world.level.Level;
*/
public class PlayerModel extends EntityModel {
private static final double STEP_TIME = 0.3;
private static final double STEP_TIME = 0.25;
public PlayerModel(int id)
@ -26,50 +24,38 @@ public class PlayerModel extends EntityModel {
@Override
public Entity createEntity(int eid, WorldPos pos)
public void update(Entity entity, double delta)
{
final Entity e = super.createEntity(eid, pos);
// set metadata
return e;
}
@Override
public void update(Entity entity, Level level, double delta)
{
}
@Override
public boolean hasMetadata()
public double getStepTime(Entity entity)
{
return true;
return STEP_TIME;
}
@Override
public double getStepTime(Entity entity)
public void onStepFinished(Entity entity)
{
return STEP_TIME;
}
@Override
public void onStepFinished(Entity entity, World world, Level level)
public void onPathFinished(Entity entity)
{
}
@Override
public void onPathFinished(Entity entity, World world, Level level)
public void onPathInterrupted(Entity entity)
{
}
@Override
public void onPathInterrupted(Entity entity, World world, Level level)
public void initMetadata(EntityData metadata)
{
}
}

@ -5,7 +5,7 @@ import mightypork.gamecore.render.Render;
import mightypork.gamecore.render.textures.TxQuad;
import mightypork.gamecore.render.textures.TxSheet;
import mightypork.rogue.Res;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.EntityPos;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.level.render.MapRenderContext;
import mightypork.util.math.Calc;
@ -30,12 +30,12 @@ public class PlayerRenderer extends EntityRenderer {
if (entity.renderData.lastXDir == -1) q = q.flipX();
final WorldPos pos = entity.getPosition();
final EntityPos pos = entity.getPosition();
final Rect tileRect = context.getRectForTile(pos.x, pos.y);
final Rect tileRect = context.getRectForTile(pos.getCoord());
final double w = tileRect.width().value();
Rect spriteRect = tileRect.move(pos.getVisualXOffset() * w, pos.getVisualYOffset() * w);
Rect spriteRect = tileRect.move(pos.visualXOffset() * w, pos.visualYOffset() * w);
spriteRect = spriteRect.shrink(w * 0.1);
Render.quadTextured(spriteRect, q);

@ -18,22 +18,22 @@ public class LevelGenerator {
private static final RoomBuilder DEAD_END = new DeadEndRoom();
public static Level build(long seed, Theme theme)
public static Level build(long seed, int complexity, Theme theme)
{
final Random rand = new Random(seed + 13);
final int max_size = 512;
final int max_size = 256;
final ScratchMap map = new ScratchMap(max_size, theme, rand);
// start
map.addRoom(ROOM_SQUARE);
for (int i = 0; i < 5 + rand.nextInt(8); i++) {
for (int i = 0; i < 2 + rand.nextInt(1 + complexity + (int) Math.pow(complexity, 1.6)); i++) {
map.addRoom(ROOM_SQUARE);
}
for (int i = 0; i < 5 + rand.nextInt(6); i++) {
for (int i = 0; i < 2 + rand.nextInt(1 + complexity / 3 + (int) Math.pow(complexity, 1.2)); i++) {
map.addRoom(DEAD_END);
}

@ -30,9 +30,7 @@ public class RoomDesc {
int rw = amax.x - amin.x;
int rh = amax.y - amin.y;
if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
return false;
}
if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) { return false; }
final int tx = min.x;
final int ty = min.y;

@ -6,10 +6,10 @@ import java.util.List;
import java.util.Random;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.pathfinding.PathCostProvider;
import mightypork.rogue.world.pathfinding.Heuristic;
import mightypork.rogue.world.pathfinding.PathFinder;
import mightypork.rogue.world.pathfinding.PathFindingContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.Tiles;
@ -18,14 +18,27 @@ import mightypork.util.logging.Log;
public class ScratchMap {
private final Tile[][] map;
//@formatter:off
public static final Coord[] MOVES = {
Coord.make(-1, 0),
Coord.make(-1, -1),
Coord.make(0, -1),
Coord.make(1, -1),
Coord.make(1, 0),
Coord.make(1, 1),
Coord.make(0, 1),
Coord.make(-1, 1)
};
//@formatter:on
private Tile[][] map;
private final int width;
private final int height;
private final List<RoomDesc> rooms = new ArrayList<>();
private final List<Coord> nodes = new ArrayList<>(); // points to connect with corridors
private final PathCostProvider pcp = new PathCostProvider() {
private final PathFindingContext pfc = new PathFindingContext() {
@Override
public boolean isAccessible(Coord pos)
@ -39,12 +52,14 @@ public class ScratchMap {
{
final Tile t = get(pos);
if (t.isNull()) return 15;
if (t.isNull()) return 60;
if (t.isDoor()) return 10; // door
if (t.isFloor()) return 20; // floor
return 400; // wall
if (t.isWall() && t.genData.isProtected) return 1000;
return 100; // wall
}
@ -54,16 +69,27 @@ public class ScratchMap {
return 10;
}
};
private final PathFinder pathFinder = new PathFinder(pcp, PathFinder.CORNER_HEURISTIC);
@Override
public Heuristic getHeuristic()
{
return PathFinder.CORNER_HEURISTIC;
}
};
Coord genMin;
Coord genMax;
private final Theme theme;
private final Random rand;
private Coord enterPoint;
public static final byte CARDINAL = (byte) 0b10101010;
public static final byte DIAGONAL = (byte) 0b01010101;
private static final boolean FIX_GLITCHES = true;
public ScratchMap(int max_size, Theme theme, Random rand)
{
@ -77,7 +103,7 @@ public class ScratchMap {
this.rand = rand;
this.theme = theme;
fill(Coord.make(0, 0), Coord.make(width - 1, height - 1), Tiles.NULL_EMPTY);
fill(Coord.make(0, 0), Coord.make(width - 1, height - 1), Tiles.NULL);
}
@ -148,9 +174,7 @@ public class ScratchMap {
public Tile get(Coord pos)
{
if (!isIn(pos)) {
throw new IndexOutOfBoundsException("Tile not in map: " + pos);
}
if (!isIn(pos)) { throw new IndexOutOfBoundsException("Tile not in map: " + pos); }
return map[pos.y][pos.x];
}
@ -164,9 +188,7 @@ public class ScratchMap {
public boolean set(Coord pos, Tile tile)
{
if (!isIn(pos)) {
throw new IndexOutOfBoundsException("Tile not in map: " + pos);
}
if (!isIn(pos)) { throw new IndexOutOfBoundsException("Tile not in map: " + pos); }
map[pos.y][pos.x] = tile;
return true;
@ -184,6 +206,17 @@ public class ScratchMap {
}
public void protect(Coord min, Coord max)
{
if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max);
final Coord c = Coord.make(0, 0);
for (c.x = min.x; c.x <= max.x; c.x++)
for (c.y = min.y; c.y <= max.y; c.y++)
get(c).genData.isProtected = true;
}
public void fill(Coord min, Coord max, TileModel tm)
{
if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max);
@ -200,14 +233,23 @@ public class ScratchMap {
if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max);
final Coord c = Coord.make(0, 0);
for (c.x = min.x; c.x <= max.x; c.x++) {
for (c.y = min.y; c.y <= max.y; c.y++) {
if (c.y > min.y && c.y < max.y && c.x > min.x && c.x < max.x) continue;
// top
for (c.x = min.x, c.y = min.y; c.x <= max.x; c.x++)
set(c, tm.createTile());
//bottom
for (c.x = min.x, c.y = max.y; c.x <= max.x; c.x++)
set(c, tm.createTile());
//left
for (c.x = min.x, c.y = min.y + 1; c.y < max.y; c.y++)
set(c, tm.createTile());
//right
for (c.x = max.x, c.y = min.y + 1; c.y < max.y; c.y++)
set(c, tm.createTile());
set(c, tm.createTile());
}
}
}
@ -225,7 +267,7 @@ public class ScratchMap {
private void buildCorridor(Coord node1, Coord node2)
{
//Log.f3("Finding path " + node1 + " -> " + node2);
final List<Coord> steps = pathFinder.findPath(node1, node2);
final List<Coord> steps = PathFinder.findPath(pfc, node1, node2);
if (steps == null) {
Log.w("Could not build corridor " + node1 + "->" + node2);
@ -258,6 +300,7 @@ public class ScratchMap {
if (i == 0 && j == 0) {
set(c, theme.floor());
} else {
if (current.isWall()) continue;
set(c, theme.wall());
}
}
@ -271,7 +314,7 @@ public class ScratchMap {
}
private int countBits(byte b)
public int countBits(byte b)
{
int c = 0;
for (int i = 0; i < 8; i++) {
@ -281,129 +324,158 @@ public class ScratchMap {
}
public void writeToLevel(Level level)
public byte findWalls(Coord pos)
{
//@formatter:off
final Coord[] moves = {
Coord.make(-1, 0),
Coord.make(-1, -1),
Coord.make(0, -1),
Coord.make(1, -1),
Coord.make(1, 0),
Coord.make(1, 1),
Coord.make(0, 1),
Coord.make(-1, 1)
};
//@formatter:on
final byte cardinal = (byte) 0b10101010;
final byte diagonal = (byte) 0b01010101;
byte walls = 0;
for (int i = 0; i <= 7; i++) {
final Coord cc = pos.add(MOVES[i]);
if (!isIn(cc)) continue;
// make sure no walkable are at edges.
final Coord c = Coord.make(0, 0);
final Coord c1 = Coord.make(0, 0);
for (c.x = 0; c.x < width; c.x++) {
for (c.y = 0; c.y < height; c.y++) {
if (get(cc).isWall()) {
walls |= 1 << (7 - i);
}
}
return walls;
}
public byte findFloors(Coord pos)
{
byte floors = 0;
for (int i = 0; i <= 7; i++) {
final Coord cc = pos.add(MOVES[i]);
if (!isIn(cc)) continue;
final Tile t = get(c);
final boolean isNull = t.isNull();
if (get(cc).isFloor()) {
floors |= 1 << (7 - i);
}
}
return floors;
}
final boolean isDoor = !isNull && t.isDoor();
final boolean isFloor = !isNull && t.isFloor();
final boolean isWall = !isNull && t.isWall();
// bitmasks
byte walls = 0;
byte nils = 0;
byte doors = 0;
byte floors = 0;
public byte findDoors(Coord pos)
{
byte doors = 0;
for (int i = 0; i <= 7; i++) {
final Coord cc = pos.add(MOVES[i]);
if (!isIn(cc)) continue;
// gather info
for (int i = 0; i <= 7; i++) {
final Coord cc = c.add(moves[i]);
if (get(cc).isDoor()) {
doors |= 1 << (7 - i);
}
}
return doors;
}
if (!isIn(cc)) {
nils |= 1 << (7 - i);
continue;
}
final Tile t2 = get(cc);
public byte findNils(Coord pos)
{
byte nils = 0;
for (int i = 0; i <= 7; i++) {
final Coord cc = pos.add(MOVES[i]);
if (t2.isNull()) {
nils |= 1 << (7 - i);
continue;
}
if (!isIn(cc) || get(cc).isNull()) {
nils |= 1 << (7 - i);
}
}
return nils;
}
if (t2.isDoor()) {
doors |= 1 << (7 - i);
continue;
}
if (t2.isWall()) {
walls |= 1 << (7 - i);
continue;
}
public void writeToLevel(Level level)
{
// make sure no walkable are at edges.
final Coord c = Coord.make(0, 0);
final Coord c1 = Coord.make(0, 0);
floors |= 1 << (7 - i);
}
if (FIX_GLITCHES) {
boolean toWall = false;
boolean toFloor = false;
boolean toNull = false;
final Tile[][] out = new Tile[height][width];
if (isFloor && (nils & cardinal) != 0) {
toWall = true; // floor with adjacent cardinal null
}
for (c.x = 0; c.x < width; c.x++) {
for (c.y = 0; c.y < height; c.y++) {
if (isNull && (floors & diagonal) != 0) {
toWall = true; // null with adjacent diagonal floor
}
final Tile t = get(c);
final boolean isNull = t.isNull();
if (isWall && floors == 0) {
toNull = true;
}
final boolean isDoor = !isNull && t.isDoor();
final boolean isFloor = !isNull && t.isFloor();
final boolean isWall = !isNull && t.isWall();
// bitmasks
final byte walls = findWalls(c);
final byte nils = findNils(c);
final byte floors = findFloors(c);
boolean toWall = false;
boolean toFloor = false;
boolean toNull = false;
if (isDoor) {
do {
if (countBits((byte) (floors & cardinal)) < 2) {
toWall = true;
if (isWall && floors == 0) {
toNull = true;
break;
}
if (countBits((byte) (walls & cardinal)) > 2) {
toWall = true;
if (isFloor && (nils & CARDINAL) != 0) {
toWall = true; // floor with adjacent cardinal null
break;
}
if (countBits((byte) (floors & cardinal)) > 2) {
toFloor = true;
if (isNull && (floors & DIAGONAL) != 0) {
System.out.println(c);
toWall = true; // null with adjacent diagonal floor
break;
}
if ((floors & 0b11100000) == 0b11100000) toWall = true;
if ((floors & 0b00111000) == 0b00111000) toWall = true;
if ((floors & 0b00001110) == 0b00001110) toWall = true;
if ((floors & 0b10000011) == 0b10000011) toWall = true;
if (isDoor) {
if (countBits((byte) (floors & CARDINAL)) < 2) {
toWall = true;
break;
}
if (countBits((byte) (walls & CARDINAL)) > 2) {
toWall = true;
break;
}
if (countBits((byte) (floors & CARDINAL)) > 2) {
toFloor = true;
break;
}
if ((floors & 0b11100000) == 0b11100000) toWall = true;
if ((floors & 0b00111000) == 0b00111000) toWall = true;
if ((floors & 0b00001110) == 0b00001110) toWall = true;
if ((floors & 0b10000011) == 0b10000011) toWall = true;
}
} while (false);
}
if (toWall) {
set(c, theme.wall());
} else if (toFloor) {
set(c, theme.floor());
} else if (toNull) {
set(c, Tiles.NULL_EMPTY);
if (toNull) {
out[c.y][c.x] = Tiles.NULL.createTile();
} else if (toWall) {
out[c.y][c.x] = theme.wall().createTile();
} else if (toFloor) {
out[c.y][c.x] = theme.floor().createTile();
} else {
out[c.y][c.x] = map[c.y][c.x];
}
}
}
map = out;
}
for (c.x = genMin.x, c1.x = 0; c.x <= genMax.x; c.x++, c1.x++) {
for (c.y = genMin.y, c1.y = 0; c.y <= genMax.y; c.y++, c1.y++) {
level.setTile(get(c), c1.x, c1.y);
level.setTile(c1, get(c));
}
}
final WorldPos p = new WorldPos(enterPoint.x - genMin.x, enterPoint.y - genMin.y);
level.setEnterPoint(p);
final Coord entrance = new Coord(enterPoint.x - genMin.x, enterPoint.y - genMin.y);
level.setEnterPoint(entrance);
}
}

@ -15,14 +15,11 @@ public class DeadEndRoom implements RoomBuilder {
@Override
public RoomDesc buildToFit(ScratchMap map, Theme theme, Random rand, Coord center)
{
final Coord min = new Coord(center.x - 1, center.y - 1);
final Coord max = new Coord(center.x + 1, center.y + 1);
if (!map.isClear(min, max)) return null;
if (!map.isClear(center, center)) return null;
map.fill(min, max, theme.floor());
map.border(min, max, theme.wall());
map.set(center, theme.floor());
return new RoomDesc(min, max);
return new RoomDesc(center, center);
}
}

@ -26,29 +26,32 @@ public class SimpleRectRoom implements RoomBuilder {
map.fill(min, max, theme.floor());
map.border(min, max, theme.wall());
map.protect(min, max);
for (int i = 0; i < 2 + rand.nextInt(4); i++) {
final Coord d = min.copy();
for (int i = 0; i <= 2 + rand.nextInt(4); i++) {
final Coord door = min.copy();
switch (rand.nextInt(4)) {
case 0:
d.y = min.y;
d.x += 1 + rand.nextInt((width - 1) * 2);
door.y = min.y;
door.x += 1 + rand.nextInt((width - 1) * 2);
break;
case 1:
d.y = max.y;
d.x += 1 + rand.nextInt((width - 1) * 2);
door.y = max.y;
door.x += 1 + rand.nextInt((width - 1) * 2);
break;
case 2:
d.x = min.x;
d.y += 1 + rand.nextInt((height - 1) * 2);
door.x = min.x;
door.y += 1 + rand.nextInt((height - 1) * 2);
break;
case 3:
d.x = max.x;
d.y += 1 + rand.nextInt((height - 1) * 2);
door.x = max.x;
door.y += 1 + rand.nextInt((height - 1) * 2);
break;
}
map.set(d, theme.door());
if ((map.findDoors(door) & map.CARDINAL) == 0) {
map.set(door, theme.door());
}
}
return new RoomDesc(min.add(-1, -1), max);

@ -8,8 +8,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.World;
import mightypork.rogue.world.WorldPos;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel;
@ -18,6 +18,7 @@ import mightypork.util.files.ion.IonBinary;
import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
import mightypork.util.logging.Log;
import mightypork.util.math.noise.NoiseGen;
@ -30,15 +31,16 @@ public class Level implements MapAccess, IonBinary {
public static final int ION_MARK = 53;
private int width, height;
private final Coord size = Coord.zero();
private World world;
private WorldPos enterPoint;
private final Coord enterPoint = Coord.zero();
/** Array of tiles [y][x] */
private Tile[][] tiles;
private final Map<Integer, Entity> entity_map = new HashMap<>();
private final Set<Entity> entity_set = new HashSet<>();
private final Map<Integer, Entity> entityMap = new HashMap<>();
private final Set<Entity> entitySet = new HashSet<>();
/** Level seed (used for generation and tile variation) */
public long seed;
@ -53,15 +55,14 @@ public class Level implements MapAccess, IonBinary {
public Level(int width, int height)
{
this.width = width;
this.height = height;
size.setTo(width, height);
buildArray();
}
private void buildArray()
{
this.tiles = new Tile[height][width];
this.tiles = new Tile[size.y][size.x];
}
@ -73,54 +74,57 @@ public class Level implements MapAccess, IonBinary {
public void fill(TileModel model)
{
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
tiles[y][x] = model.createTile();
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
for (c.y = 0; c.y < size.y; c.y++) {
setTile(c, model.createTile());
}
}
}
@Override
public final Tile getTile(int x, int y)
public final Tile getTile(Coord pos)
{
if (x < 0 || x >= width || y < 0 || y >= height) return Tiles.NULL_SOLID.createTile(); // out of range
if (!pos.isInRange(0, 0, size.x - 1, size.y - 1)) return Tiles.NULL.createTile(); // out of range
return tiles[y][x];
return tiles[pos.y][pos.x];
}
public final void setTile(TileModel model, int x, int y)
public final void setTile(Coord pos, TileModel model)
{
setTile(model.createTile(), x, y);
setTile(pos, model.createTile());
}
public final void setTile(int tileId, int x, int y)
public final void setTile(Coord pos, int tileId)
{
setTile(new Tile(tileId), x, y);
setTile(pos, new Tile(tileId));
}
public final void setTile(Tile tile, int x, int y)
public final void setTile(Coord pos, Tile tile)
{
if (x < 0 || x > width || y < 0 || y >= height) return; // out of range
if (!pos.isInRange(0, 0, size.x - 1, size.y - 1)) {
Log.w("Invalid tile coord to set: " + pos + ", map size: " + size);
return; // out of range
}
tiles[y][x] = tile;
tiles[pos.y][pos.x] = tile;
}
@Override
public final int getWidth()
{
return width;
return size.x;
}
@Override
public final int getHeight()
{
return height;
return size.y;
}
@ -143,29 +147,31 @@ public class Level implements MapAccess, IonBinary {
// metadata
final IonBundle ib = in.readBundle();
seed = ib.get("seed", 0L);
width = ib.get("w", 0);
height = ib.get("h", 0);
ib.loadBundled("size", size);
ib.loadBundled("enter_point", enterPoint);
ib.loadSequence("entities", entity_set);
for (final Entity ent : entity_set) {
entity_map.put(ent.getEID(), ent);
ib.loadSequence("entities", entitySet);
for (final Entity ent : entitySet) {
ent.setLevel(this);
entityMap.put(ent.getEntityId(), ent);
}
// init array of size
buildArray();
// load tiles
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
for (c.y = 0; c.y < size.y; c.y++) {
// no mark
tiles[y][x] = new Tile();
tiles[y][x].load(in);
final Tile tile = new Tile();
tile.load(in);
setTile(c, tile);
}
}
// mark tiles as occupied
for (final Entity e : entity_set) {
occupyTile(e.getPosition().x, e.getPosition().y);
for (final Entity e : entitySet) {
occupyTile(e.getPosition().getCoord());
}
}
@ -176,16 +182,17 @@ public class Level implements MapAccess, IonBinary {
// metadata
final IonBundle ib = new IonBundle();
ib.put("seed", seed);
ib.put("w", width);
ib.put("h", height);
ib.putSequence("entities", entity_set);
ib.putBundled("size", size);
ib.putBundled("enter_point", enterPoint);
ib.putSequence("entities", entitySet);
out.writeBundle(ib);
// tiles (writing this way to save space)
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
for (c.y = 0; c.y < size.y; c.y++) {
// no mark to save space
tiles[y][x].save(out);
getTile(c).save(out);
}
}
}
@ -198,17 +205,17 @@ public class Level implements MapAccess, IonBinary {
}
public void update(World w, double delta)
public void update(double delta)
{
// just update them all
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
getTile(x, y).update(this, delta);
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
for (c.y = 0; c.y < size.y; c.y++) {
getTile(c).update(this, delta);
}
}
for (final Entity e : entity_set) {
e.update(w, this, delta);
for (final Entity e : entitySet) {
e.update(delta);
}
}
@ -226,34 +233,42 @@ public class Level implements MapAccess, IonBinary {
public Entity getEntity(int eid)
{
return entity_map.get(eid);
return entityMap.get(eid);
}
public void addEntity(Entity entity)
{
entity_map.put(entity.getEID(), entity);
entity_set.add(entity);
if (entityMap.containsKey(entity.getEntityId())) {
Log.w("Entity already in level.");
return;
}
entityMap.put(entity.getEntityId(), entity);
entitySet.add(entity);
// join to level & world
entity.setLevel(this);
}
public void removeEntity(Entity entity)
{
entity_map.remove(entity.getEID());
entity_set.remove(entity);
entityMap.remove(entity.getEntityId());
entitySet.remove(entity);
}
public void removeEntity(int eid)
{
final Entity removed = entity_map.remove(eid);
entity_set.remove(removed);
final Entity removed = entityMap.remove(eid);
entitySet.remove(removed);
}
public boolean canWalkInto(int x, int y)
public boolean canWalkInto(Coord pos)
{
final Tile t = getTile(x, y);
final Tile t = getTile(pos);
return t.isWalkable() && !t.isOccupied();
}
@ -262,35 +277,47 @@ public class Level implements MapAccess, IonBinary {
/**
* Mark tile as occupied by an entity
*/
public void occupyTile(int x, int y)
public void occupyTile(Coord pos)
{
getTile(x, y).setOccupied(true);
getTile(pos).setOccupied(true);
}
/**
* Mark tile as free (no longet occupied)
*/
public void freeTile(int x, int y)
public void freeTile(Coord pos)
{
getTile(x, y).setOccupied(false);
getTile(pos).setOccupied(false);
}
public Collection<Entity> getEntities()
{
return entity_set;
return entitySet;
}
public void setEnterPoint(WorldPos enterPoint)
public void setEnterPoint(Coord pos)
{
this.enterPoint = enterPoint;
this.enterPoint.setTo(pos);
}
public WorldPos getEnterPoint()
public Coord getEnterPoint()
{
return enterPoint;
}
public World getWorld()
{
return world;
}
public void setWorld(World world)
{
this.world = world;
}
}

@ -1,6 +1,7 @@
package mightypork.rogue.world.level;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.math.noise.NoiseGen;
@ -15,11 +16,10 @@ public interface MapAccess {
/**
* Ge tile at X,Y
*
* @param x
* @param y
* @param pos
* @return tile
*/
Tile getTile(int x, int y);
Tile getTile(Coord pos);
/**

@ -1,6 +1,7 @@
package mightypork.rogue.world.level.render;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.level.MapAccess;
import mightypork.util.math.constraints.rect.Rect;
import mightypork.util.math.constraints.rect.builders.TiledRect;
@ -22,9 +23,9 @@ public abstract class MapRenderContext {
}
public Rect getRectForTile(int x, int y)
public Rect getRectForTile(Coord pos)
{
return tiler.tile(x, y);
return tiler.tile(pos.x, pos.y);
}

@ -1,6 +1,7 @@
package mightypork.rogue.world.level.render;
import mightypork.rogue.world.Coord;
import mightypork.rogue.world.level.MapAccess;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.math.constraints.rect.Rect;
@ -15,8 +16,7 @@ import mightypork.util.math.noise.NoiseGen;
*/
public final class TileRenderContext extends MapRenderContext implements RectBound {
public int x;
public int y;
public final Coord pos = Coord.zero();
private final NoiseGen noise;
@ -35,7 +35,7 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
*/
public Tile getTile()
{
return map.getTile(x, y);
return map.getTile(pos);
}
@ -48,7 +48,7 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
*/
public Tile getAdjacentTile(int offsetX, int offsetY)
{
return map.getTile(x + offsetX, y + offsetY);
return map.getTile(pos.add(offsetX, offsetY));
}
@ -57,19 +57,19 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
*/
public double getTileNoise()
{
return noise.valueAt(x, y);
return noise.valueAt(pos.x, pos.y);
}
public void renderTile()
{
map.getTile(x, y).renderTile(this);
map.getTile(pos).renderTile(this);
}
public void renderItems()
{
map.getTile(x, y).renderItems(this);
map.getTile(pos).renderItems(this);
}
@ -79,6 +79,6 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
@Override
public Rect getRect()
{
return getRectForTile(x, y);
return getRectForTile(pos);
}
}

@ -19,28 +19,19 @@ import mightypork.rogue.world.PathStep;
public class PathFinder {
private static final FComparator F_COMPARATOR = new FComparator();
public static final Heuristic CORNER_HEURISTIC = new ManhattanHeuristic();
public static final Heuristic DIAGONAL_HEURISTIC = new DiagonalHeuristic();
private final PathCostProvider costProvider;
private final Heuristic heuristic;
public PathFinder(PathCostProvider costProvider, Heuristic heuristic)
public static List<PathStep> findPathRelative(PathFindingContext context, Coord start, Coord end)
{
this.costProvider = costProvider;
this.heuristic = heuristic;
}
public List<PathStep> findPathRelative(Coord start, Coord end)
{
final List<Coord> path = findPath(start, end);
final List<Coord> path = findPath(context, start, end);
if (path == null) return null;
final List<PathStep> out = new ArrayList<>();
final Coord current = start;
final Coord current = start.copy();
for (final Coord c : path) {
if (c.equals(current)) continue;
out.add(PathStep.make(c.x - current.x, c.y - current.y));
@ -52,15 +43,17 @@ public class PathFinder {
}
public List<Coord> findPath(Coord start, Coord end)
public static List<Coord> findPath(PathFindingContext context, Coord start, Coord end)
{
final LinkedList<Node> open = new LinkedList<>();
final LinkedList<Node> closed = new LinkedList<>();
final Heuristic heuristic = context.getHeuristic();
// add first node
{
final Node n = new Node(start);
n.h_cost = (int) (heuristic.getCost(start, end) * costProvider.getMinCost());
n.h_cost = (int) (heuristic.getCost(start, end) * context.getMinCost());
n.g_cost = 0;
open.add(n);
}
@ -92,13 +85,13 @@ public class PathFinder {
for (final Coord go : walkDirs) {
final Coord c = current.pos.add(go);
if (!costProvider.isAccessible(c)) continue;
if (!context.isAccessible(c)) continue;
final Node a = new Node(c);
a.g_cost = current.g_cost + costProvider.getCost(c, a.pos);
a.h_cost = (int) (heuristic.getCost(a.pos, end) * costProvider.getMinCost());
a.g_cost = current.g_cost + context.getCost(c, a.pos);
a.h_cost = (int) (heuristic.getCost(a.pos, end) * context.getMinCost());
a.parent = current;
if (costProvider.isAccessible(a.pos)) {
if (context.isAccessible(a.pos)) {
if (!closed.contains(a)) {
if (open.contains(a)) {
@ -128,8 +121,7 @@ public class PathFinder {
}
if (current == null) {
return null; // no path found
if (current == null) { return null; // no path found
}
final LinkedList<Coord> path = new LinkedList<>();

@ -4,7 +4,7 @@ package mightypork.rogue.world.pathfinding;
import mightypork.rogue.world.Coord;
public interface PathCostProvider {
public interface PathFindingContext {
/**
* @param pos tile pos
@ -27,4 +27,10 @@ public interface PathCostProvider {
* @return lowest cost. Used to multiply heuristics.
*/
int getMinCost();
/**
* @return used heuristic
*/
Heuristic getHeuristic();
}

@ -33,6 +33,7 @@ public final class Tile implements IonBinary {
public final IonBundle metadata = new IonBundle();
public final TileRenderData renderData = new TileRenderData();
public final TileGenData genData = new TileGenData();
// temporary flag for map.
private boolean occupied;

@ -0,0 +1,13 @@
package mightypork.rogue.world.tile;
/**
* Data storage for world generator
*
* @author MightyPork
*/
public class TileGenData {
public boolean isProtected = false;
}

@ -2,7 +2,7 @@ package mightypork.rogue.world.tile;
/**
* Data storage for renderer / entity.
* Data storage for tile renderer
*
* @author MightyPork
*/

@ -2,8 +2,7 @@ package mightypork.rogue.world.tile;
import mightypork.rogue.world.tile.models.Floor;
import mightypork.rogue.world.tile.models.NullFloor;
import mightypork.rogue.world.tile.models.NullWall;
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.FloorRenderer;
@ -19,8 +18,7 @@ public final class Tiles {
private static final TileModel[] tiles = new TileModel[256];
public static final TileModel NULL_SOLID = new NullWall(0);
public static final TileModel NULL_EMPTY = new NullFloor(1);
public static final TileModel NULL = new NullTile(0);
public static final TileModel FLOOR_DARK = new Floor(10).setRenderer(new FloorRenderer("tile.floor.dark"));
public static final TileModel WALL_BRICK = new Wall(11).setRenderer(new WallRenderer("tile.wall.brick"));
@ -45,13 +43,9 @@ public final class Tiles {
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."); }
if (tiles[id] != null) {
throw new IllegalArgumentException("Tile ID " + id + " already in use.");
}
if (tiles[id] != null) { throw new IllegalArgumentException("Tile ID " + id + " already in use."); }
tiles[id] = model;
}
@ -61,9 +55,7 @@ public final class Tiles {
{
final TileModel m = tiles[id];
if (m == null) {
throw new IllegalArgumentException("No tile with ID " + id + ".");
}
if (m == null) { throw new IllegalArgumentException("No tile with ID " + id + "."); }
return m;
}

@ -1,25 +0,0 @@
package mightypork.rogue.world.tile.models;
public class NullFloor extends AbstractNullTile {
public NullFloor(int id)
{
super(id);
}
@Override
public boolean isFloor()
{
return true;
}
@Override
public boolean isPotentiallyWalkable()
{
return true;
}
}

@ -1,9 +1,9 @@
package mightypork.rogue.world.tile.models;
public class NullWall extends AbstractNullTile {
public class NullTile extends AbstractNullTile {
public NullWall(int id)
public NullTile(int id)
{
super(id);
}
@ -15,10 +15,4 @@ public class NullWall extends AbstractNullTile {
return false;
}
@Override
public boolean isWall()
{
return true;
}
}

@ -54,9 +54,7 @@ public abstract class BusEvent<HANDLER> {
{
if (consumed) throw new IllegalStateException("Already consumed.");
if (getClass().isAnnotationPresent(NonConsumableEvent.class)) {
throw new UnsupportedOperationException("Not consumable.");
}
if (getClass().isAnnotationPresent(NonConsumableEvent.class)) { throw new UnsupportedOperationException("Not consumable."); }
consumed = true;
}

@ -31,9 +31,7 @@ class EventChannel<EVENT extends BusEvent<CLIENT>, CLIENT> {
public EventChannel(Class<EVENT> eventClass, Class<CLIENT> clientClass)
{
if (eventClass == null || clientClass == null) {
throw new NullPointerException("Null Event or Client class.");
}
if (eventClass == null || clientClass == null) { throw new NullPointerException("Null Event or Client class."); }
this.clientClass = clientClass;
this.eventClass = eventClass;

@ -62,9 +62,7 @@ public abstract class BusNode implements BusAccess, ClientHub {
@Override
public void addChildClient(Object client)
{
if (client instanceof RootBusNode) {
throw new IllegalArgumentException("Cannot nest RootBusNode.");
}
if (client instanceof RootBusNode) { throw new IllegalArgumentException("Cannot nest RootBusNode."); }
clients.add(client);
}

@ -82,9 +82,7 @@ public class FileTreeDiff {
final int read1 = cin1.read(BUFFER);
final int read2 = cin2.read(BUFFER);
if (read1 != read2 || ck1.getValue() != ck2.getValue()) {
throw new NotEqualException("Bytes differ:\n" + pair.a + "\n" + pair.b);
}
if (read1 != read2 || ck1.getValue() != ck2.getValue()) { throw new NotEqualException("Bytes differ:\n" + pair.a + "\n" + pair.b); }
if (read1 == -1) break;
}

@ -39,9 +39,7 @@ public class FileUtils {
if (!source.exists()) return;
if (source.isDirectory()) {
if (!target.exists() && !target.mkdir()) {
throw new IOException("Could not open destination directory.");
}
if (!target.exists() && !target.mkdir()) { throw new IOException("Could not open destination directory."); }
final String[] children = source.list();
for (final String element : children) {
@ -49,9 +47,7 @@ public class FileUtils {
}
} else {
if (filter != null && !filter.accept(source)) {
return;
}
if (filter != null && !filter.accept(source)) { return; }
if (filesCopied != null) filesCopied.add(target);
copyFile(source, target);
@ -76,9 +72,7 @@ public class FileUtils {
}
} else {
if (filter != null && !filter.accept(source.getAbsolutePath())) {
return;
}
if (filter != null && !filter.accept(source.getAbsolutePath())) { return; }
files.add(source);
}
@ -112,13 +106,9 @@ public class FileUtils {
*/
public static void copyStream(InputStream in, OutputStream out) throws IOException
{
if (in == null) {
throw new NullPointerException("Input stream is null");
}
if (in == null) { throw new NullPointerException("Input stream is null"); }
if (out == null) {
throw new NullPointerException("Output stream is null");
}
if (out == null) { throw new NullPointerException("Output stream is null"); }
final byte[] buf = new byte[2048];
int len;
@ -137,9 +127,7 @@ public class FileUtils {
*/
public static boolean delete(File path, boolean recursive)
{
if (!path.exists()) {
return true;
}
if (!path.exists()) { return true; }
if (!recursive || !path.isDirectory()) return path.delete();

@ -56,9 +56,7 @@ public class OsUtils {
final File f = new File(getWorkDir(dirname), subfolderName);
if (!f.exists() && create) {
if (!f.mkdirs()) {
throw new RuntimeException("Could not create.");
}
if (!f.mkdirs()) { throw new RuntimeException("Could not create."); }
}
return f;
@ -137,9 +135,7 @@ public class OsUtils {
if (!file.exists() || !file.isDirectory()) {
if (create) {
if (!file.mkdirs()) {
throw new RuntimeException("Could not create working directory.");
}
if (!file.mkdirs()) { throw new RuntimeException("Could not create working directory."); }
}
}

@ -182,9 +182,7 @@ public class PropertyManager {
{
boolean needsSave = false;
if (!file.getParentFile().mkdirs()) {
if (!file.getParentFile().exists()) {
throw new RuntimeException("Cound not create config file.");
}
if (!file.getParentFile().exists()) { throw new RuntimeException("Cound not create config file."); }
}
try(FileInputStream fis = new FileInputStream(file)) {

@ -263,9 +263,7 @@ public class SortedProperties extends java.util.Properties {
private static char hexDigit(char ch, int offset)
{
final int val = (ch >> offset) & 0xF;
if (val <= 9) {
return (char) ('0' + val);
}
if (val <= 9) { return (char) ('0' + val); }
return (char) ('A' + val - 10);
}

@ -95,13 +95,9 @@ public class Ion {
if (mark > 255) throw new IllegalArgumentException("Mark must be < 256.");
if (mark < 0) throw new IllegalArgumentException("Mark must be positive.");
if (reservedMarkChecking && mark < 50) {
throw new IllegalArgumentException("Marks 0..49 are reserved.");
}
if (reservedMarkChecking && mark < 50) { throw new IllegalArgumentException("Marks 0..49 are reserved."); }
if (registered[mark] != null) {
throw new IllegalArgumentException("Mark " + mark + " is already in use.");
}
if (registered[mark] != null) { throw new IllegalArgumentException("Mark " + mark + " is already in use."); }
try {
objClass.getConstructor();
@ -284,13 +280,9 @@ public class Ion {
final Class<? extends IonBinary> clz = Ion.getClassForMark(mark);
if (clz == null) {
throw new IOException("Not registered - mark: " + mark + ", class: " + Log.str(obj.getClass()));
}
if (clz == null) { throw new IOException("Not registered - mark: " + mark + ", class: " + Log.str(obj.getClass())); }
if (clz != obj.getClass()) {
throw new IOException("Class mismatch - mark: " + mark + ", class: " + Log.str(obj.getClass()));
}
if (clz != obj.getClass()) { throw new IOException("Class mismatch - mark: " + mark + ", class: " + Log.str(obj.getClass())); }
}
}

@ -269,9 +269,7 @@ public class IonOutput {
return;
}
if (obj instanceof IonBundled) {
throw new IOException("Bundled objects cannot be written to ION stream directly at " + obj);
}
if (obj instanceof IonBundled) { throw new IOException("Bundled objects cannot be written to ION stream directly at " + obj); }
if (obj instanceof Boolean) {
writeMark(Ion.BOOLEAN);

@ -295,9 +295,7 @@ public class Log {
final String nl = System.getProperty("line.separator");
if (message.equals("\n")) {
return nl;
}
if (message.equals("\n")) { return nl; }
if (message.charAt(0) == '\n') {
message = nl + message.substring(1);
@ -359,9 +357,7 @@ public class Log {
public static String str(Class<?> cls)
{
final LogAlias ln = cls.getAnnotation(LogAlias.class);
if (ln != null) {
return ln.name();
}
if (ln != null) { return ln.name(); }
String name = cls.getName();

@ -112,9 +112,7 @@ public class ArchivingLog extends SimpleLog {
// playing with fireee
for (int i = 0; i < oldLogs.size() - logs_to_keep; i++) {
if (!oldLogs.get(i).delete()) {
throw new RuntimeException("Could not delete old log file.");
}
if (!oldLogs.get(i).delete()) { throw new RuntimeException("Could not delete old log file."); }
}
}

@ -594,9 +594,7 @@ public class Calc {
*/
public static List<Integer> parseIntList(String list)
{
if (list == null) {
return null;
}
if (list == null) { return null; }
final String[] parts = list.split(",");
final ArrayList<Integer> intList = new ArrayList<>();
@ -656,8 +654,6 @@ public class Calc {
*/
public static void assertValidIndex(int index, int length)
{
if (!inRange(index, 0, length - 1)) {
throw new IndexOutOfBoundsException();
}
if (!inRange(index, 0, length - 1)) { throw new IndexOutOfBoundsException(); }
}
}

@ -205,9 +205,7 @@ public abstract class Color {
*/
public static void pushAlpha(Num alpha)
{
if (!alphaStackEnabled) {
return;
}
if (!alphaStackEnabled) { return; }
alphaStack.push(alpha);
}
@ -221,13 +219,9 @@ public abstract class Color {
*/
public static void popAlpha()
{
if (!alphaStackEnabled) {
return;
}
if (!alphaStackEnabled) { return; }
if (alphaStack.isEmpty()) {
throw new EmptyStackException();
}
if (alphaStack.isEmpty()) { throw new EmptyStackException(); }
alphaStack.pop();
}

@ -1028,9 +1028,7 @@ public abstract class Rect implements RectBound, Digestable<RectDigest> {
double rw = other.size().x();
double rh = other.size().y();
if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
return false;
}
if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) { return false; }
final double tx = this.origin().x();
final double ty = this.origin().y();

@ -58,13 +58,9 @@ public class TiledRect extends RectProxy {
*/
public Rect tile(int x, int y)
{
if (x >= tilesX || x < 0) {
throw new IndexOutOfBoundsException("X coordinate out fo range: " + x);
}
if (x >= tilesX || x < 0) { throw new IndexOutOfBoundsException("X coordinate out fo range: " + x); }
if (y >= tilesY || y < 0) {
throw new IndexOutOfBoundsException("Y coordinate out of range: " + y);
}
if (y >= tilesY || y < 0) { throw new IndexOutOfBoundsException("Y coordinate out of range: " + y); }
return aTile.move(perCol.mul(x), perRow.mul(y));
}

@ -137,9 +137,7 @@ public class Convert {
return String.format("{%f|%f}", c.getMin(), c.getMax());
}
if (o instanceof Class<?>) {
return Log.str(o);
}
if (o instanceof Class<?>) { return Log.str(o); }
return o.toString();
}
@ -179,9 +177,7 @@ public class Convert {
final double x = Double.parseDouble(parts[0].trim());
final double y = Double.parseDouble(parts[1].trim());
if (parts.length == 2) {
return Vect.make(x, y);
}
if (parts.length == 2) { return Vect.make(x, y); }
final double z = Double.parseDouble(parts[2].trim());

@ -59,13 +59,9 @@ public class Pair<T1, T2> {
@Override
public boolean equals(Object obj)
{
if (obj == null) {
return false;
}
if (obj == null) { return false; }
if (!this.getClass().equals(obj.getClass())) {
return false;
}
if (!this.getClass().equals(obj.getClass())) { return false; }
final Pair<?, ?> t = (Pair<?, ?>) obj;

@ -34,9 +34,7 @@ public class VarargsParser<K, V> {
{
final LinkedHashMap<K, V> attrs = new LinkedHashMap<>();
if (args.length % 2 != 0) {
throw new IllegalArgumentException("Odd number of elements in varargs map!");
}
if (args.length % 2 != 0) { throw new IllegalArgumentException("Odd number of elements in varargs map!"); }
K key = null;
for (final Object o : args) {

@ -35,9 +35,7 @@ public class FileSuffixFilter implements FileFilter {
final String fname = pathname.getName().toLowerCase().trim();
for (final String suffix : suffixes) {
if (fname.endsWith(suffix.toLowerCase().trim())) {
return true;
}
if (fname.endsWith(suffix.toLowerCase().trim())) { return true; }
}
return false;

@ -64,15 +64,11 @@ public class TimerFps {
*/
public double getFraction()
{
if (getSkipped() >= 1) {
return 1;
}
if (getSkipped() >= 1) { return 1; }
final long time = getTime();
if (time <= nextFrame) {
return (double) (time - lastFrame) / (double) FRAME;
}
if (time <= nextFrame) { return (double) (time - lastFrame) / (double) FRAME; }
return 1;
}

Loading…
Cancel
Save