first monster, remade tile renderer system etc

v5stable
Ondřej Hruška 10 years ago
parent 78035ced7a
commit fb244dc2b9
  1. 10
      src/mightypork/gamecore/util/math/algo/Sides.java
  2. 106
      src/mightypork/gamecore/util/math/algo/pathfinding/PathFinder.java
  3. 12
      src/mightypork/gamecore/util/math/algo/pathfinding/PathFinderProxy.java
  4. 40
      src/mightypork/gamecore/util/math/algo/pathfinding/PathFindingContext.java
  5. 2
      src/mightypork/gamecore/util/math/timing/Animator.java
  6. 5
      src/mightypork/gamecore/util/math/timing/TimedTask.java
  7. 2
      src/mightypork/rogue/App.java
  8. 5
      src/mightypork/rogue/Res.java
  9. 4
      src/mightypork/rogue/world/World.java
  10. 2
      src/mightypork/rogue/world/WorldCreator.java
  11. 2
      src/mightypork/rogue/world/WorldRenderer.java
  12. 2
      src/mightypork/rogue/world/entity/Entities.java
  13. 22
      src/mightypork/rogue/world/entity/Entity.java
  14. 5
      src/mightypork/rogue/world/entity/EntityModel.java
  15. 15
      src/mightypork/rogue/world/entity/EntityPathFinder.java
  16. 29
      src/mightypork/rogue/world/entity/SimpleEntityPathFindingContext.java
  17. 286
      src/mightypork/rogue/world/entity/entities/MonsterAi.java
  18. 24
      src/mightypork/rogue/world/entity/entities/PlayerEntity.java
  19. 59
      src/mightypork/rogue/world/entity/entities/RatAi.java
  20. 59
      src/mightypork/rogue/world/entity/entities/RatEntity.java
  21. 41
      src/mightypork/rogue/world/entity/entities/SimpleMonster.java
  22. 6
      src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java
  23. 8
      src/mightypork/rogue/world/entity/modules/EntityModulePosition.java
  24. 11
      src/mightypork/rogue/world/entity/renderers/EntityRenderer.java
  25. 6
      src/mightypork/rogue/world/entity/renderers/EntityRendererMobLR.java
  26. 21
      src/mightypork/rogue/world/gen/LevelGenerator.java
  27. 17
      src/mightypork/rogue/world/gen/ScratchMap.java
  28. 2
      src/mightypork/rogue/world/gen/rooms/AbstractRectRoom.java
  29. 2
      src/mightypork/rogue/world/gui/MapView.java
  30. 23
      src/mightypork/rogue/world/level/Level.java
  31. 23
      src/mightypork/rogue/world/tile/Tile.java
  32. 10
      src/mightypork/rogue/world/tile/TileModel.java
  33. 14
      src/mightypork/rogue/world/tile/TileRenderData.java
  34. 64
      src/mightypork/rogue/world/tile/TileRenderer.java
  35. 20
      src/mightypork/rogue/world/tile/Tiles.java
  36. 7
      src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java
  37. 39
      src/mightypork/rogue/world/tile/renderers/DoorRenderer.java
  38. 70
      src/mightypork/rogue/world/tile/renderers/DoorTileRenderer.java
  39. 38
      src/mightypork/rogue/world/tile/renderers/LockedDoorRenderer.java
  40. 30
      src/mightypork/rogue/world/tile/renderers/NullTileRenderer.java
  41. 29
      src/mightypork/rogue/world/tile/tiles/DoorTile.java
  42. 22
      src/mightypork/rogue/world/tile/tiles/FloorTile.java
  43. 44
      src/mightypork/rogue/world/tile/tiles/LockedDoorTile.java
  44. 10
      src/mightypork/rogue/world/tile/tiles/NullTile.java
  45. 82
      src/mightypork/rogue/world/tile/tiles/TileBaseDoor.java
  46. 34
      src/mightypork/rogue/world/tile/tiles/TileBaseFloor.java
  47. 49
      src/mightypork/rogue/world/tile/tiles/TileBasePassage.java
  48. 11
      src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java
  49. 35
      src/mightypork/rogue/world/tile/tiles/TileBaseWall.java
  50. 6
      src/mightypork/rogue/world/tile/tiles/TileSolid.java
  51. 7
      src/mightypork/rogue/world/tile/tiles/TileWalkable.java
  52. 35
      src/mightypork/rogue/world/tile/tiles/WallPassageTile.java
  53. 22
      src/mightypork/rogue/world/tile/tiles/WallTile.java
  54. 22
      src/mightypork/rogue/world/tile/tiles/brick/TileBrickDoor.java
  55. 16
      src/mightypork/rogue/world/tile/tiles/brick/TileBrickFloor.java
  56. 17
      src/mightypork/rogue/world/tile/tiles/brick/TileBrickPassage.java
  57. 26
      src/mightypork/rogue/world/tile/tiles/brick/TileBrickSecretDoor.java
  58. 16
      src/mightypork/rogue/world/tile/tiles/brick/TileBrickWall.java

@ -12,8 +12,8 @@ public class Sides {
public static final byte MASK_SW = (byte) 0b00000010;
public static final byte MASK_W = (byte) 0b00000001;
public static final byte CARDINAL = MASK_N | MASK_S | MASK_E | MASK_W;
public static final byte DIAGONAL = MASK_NE | MASK_NW | MASK_SE | MASK_SW;
public static final byte MASK_CARDINAL = MASK_N | MASK_S | MASK_E | MASK_W;
public static final byte MASK_DIAGONAL = MASK_NE | MASK_NW | MASK_SE | MASK_SW;
public static final byte NW_CORNER = MASK_W | MASK_NW | MASK_N;
public static final byte NE_CORNER = MASK_E | MASK_NE | MASK_N;
@ -31,7 +31,7 @@ public class Sides {
//@formatter:off
/** All sides, in the order of bits. */
public final static Step[] allSides = {
public final static Step[] ALL_SIDES = {
NW,
N,
NE,
@ -42,7 +42,7 @@ public class Sides {
W
};
public final static Step[] cardinalSides = {
public final static Step[] CARDINAL_SIDES = {
N,
E,
S,
@ -59,7 +59,7 @@ public class Sides {
*/
public static Step get(int i)
{
return allSides[i];
return ALL_SIDES[i];
}

@ -18,7 +18,7 @@ import mightypork.gamecore.util.math.algo.pathfinding.heuristics.ManhattanHeuris
*
* @author MightyPork
*/
public class PathFinder {
public abstract class PathFinder {
private static final FComparator F_COMPARATOR = new FComparator();
@ -26,9 +26,15 @@ public class PathFinder {
public static final Heuristic DIAGONAL_HEURISTIC = new DiagonalHeuristic();
public static List<Step> findPathRelative(PathFindingContext context, Coord start, Coord end)
public List<Step> findPathRelative(Coord start, Coord end)
{
final List<Coord> path = findPath(context, start, end);
return findPathRelative(start, end, false);
}
public List<Step> findPathRelative(Coord start, Coord end, boolean ignoreEnd)
{
final List<Coord> path = findPath(start, end, ignoreEnd);
if (path == null) return null;
final List<Step> out = new ArrayList<>();
@ -45,22 +51,28 @@ public class PathFinder {
}
public static List<Coord> findPath(PathFindingContext context, Coord start, Coord end)
public List<Coord> findPath(Coord start, Coord end)
{
return findPath(start, end, false);
}
public List<Coord> findPath(Coord start, Coord end, boolean ignoreEnd)
{
final LinkedList<Node> open = new LinkedList<>();
final LinkedList<Node> closed = new LinkedList<>();
final Heuristic heuristic = context.getHeuristic();
final Heuristic heuristic = getHeuristic();
// add first node
{
final Node n = new Node(start);
n.h_cost = (int) (heuristic.getCost(start, end) * context.getMinCost());
n.h_cost = (int) (heuristic.getCost(start, end) * getMinCost());
n.g_cost = 0;
open.add(n);
}
final Step[] walkDirs = context.getWalkSides();
final Step[] walkDirs = getWalkSides();
Node current = null;
@ -80,43 +92,43 @@ public class PathFinder {
for (final Step go : walkDirs) {
final Coord c = current.pos.add(go);
if (!context.isAccessible(c)) continue;
if (!isAccessible(c) && !(c.equals(end) && ignoreEnd)) continue;
final Node a = new Node(c);
a.g_cost = current.g_cost + context.getCost(c, a.pos);
a.h_cost = (int) (heuristic.getCost(a.pos, end) * context.getMinCost());
a.g_cost = current.g_cost + getCost(c, a.pos);
a.h_cost = (int) (heuristic.getCost(a.pos, end) * getMinCost());
a.parent = current;
if (context.isAccessible(a.pos)) {
if (!closed.contains(a)) {
if (!closed.contains(a)) {
if (open.contains(a)) {
if (open.contains(a)) {
boolean needSort = false;
// find where it is
for (final Node n : open) {
if (n.pos.equals(a.pos)) { // found it
if (n.g_cost > a.g_cost) {
n.parent = current;
n.g_cost = a.g_cost;
needSort = true;
}
break;
boolean needSort = false;
// find where it is
for (final Node n : open) {
if (n.pos.equals(a.pos)) { // found it
if (n.g_cost > a.g_cost) {
n.parent = current;
n.g_cost = a.g_cost;
needSort = true;
}
break;
}
if (needSort) Collections.sort(open, F_COMPARATOR);
} else {
open.add(a);
}
if (needSort) Collections.sort(open, F_COMPARATOR);
} else {
open.add(a);
}
}
}
}
if (current == null) { return null; // no path found
if (current == null) {
return null; // no path found
}
final LinkedList<Coord> path = new LinkedList<>();
@ -189,4 +201,36 @@ public class PathFinder {
return n1.fCost() - n2.fCost();
}
}
/**
* @return used heuristic
*/
protected abstract Heuristic getHeuristic();
protected abstract Step[] getWalkSides();
/**
* @param pos tile pos
* @return true if the tile is walkable
*/
protected abstract boolean isAccessible(Coord pos);
/**
* Cost of walking onto a tile. It's useful to use ie. 10 for basic step.
*
* @param from last tile
* @param to current tile
* @return cost
*/
protected abstract int getCost(Coord from, Coord to);
/**
* @return lowest cost. Used to multiply heuristics.
*/
protected abstract int getMinCost();
}

@ -6,17 +6,17 @@ import mightypork.gamecore.util.math.algo.Step;
/**
* Pathfinding context proxy. Can be used to override individual methods but
* Pathfinder proxy. Can be used to override individual methods but
* keep the rest as is.
*
* @author MightyPork
*/
public class PathFindingContextProxy implements PathFindingContext {
public class PathFinderProxy extends PathFinder {
private final PathFindingContext source;
private final PathFinder source;
public PathFindingContextProxy(PathFindingContext other)
public PathFinderProxy(PathFinder other)
{
this.source = other;
}
@ -44,14 +44,14 @@ public class PathFindingContextProxy implements PathFindingContext {
@Override
public Heuristic getHeuristic()
protected Heuristic getHeuristic()
{
return source.getHeuristic();
}
@Override
public Step[] getWalkSides()
protected Step[] getWalkSides()
{
return source.getWalkSides();
}

@ -1,40 +0,0 @@
package mightypork.gamecore.util.math.algo.pathfinding;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step;
public interface PathFindingContext {
/**
* @param pos tile pos
* @return true if the tile is walkable
*/
boolean isAccessible(Coord pos);
/**
* Cost of walking onto a tile. It's useful to use ie. 10 for basic step.
*
* @param from last tile
* @param to current tile
* @return cost
*/
int getCost(Coord from, Coord to);
/**
* @return lowest cost. Used to multiply heuristics.
*/
int getMinCost();
/**
* @return used heuristic
*/
Heuristic getHeuristic();
Step[] getWalkSides();
}

@ -83,7 +83,7 @@ public abstract class Animator extends Num implements Updateable, Pauseable {
public void restart()
{
reset();
nextCycle(numAnim);
resume();
}

@ -29,6 +29,11 @@ public abstract class TimedTask implements Runnable, Updateable {
}
public boolean isRunning() {
return !timer.isFinished();
}
public void start(double seconds)
{
timer.reset();

@ -162,6 +162,6 @@ public final class App extends BaseApp {
// TODO tmp
WorldProvider.get().createWorld(Double.doubleToLongBits(Math.random()));
getEventBus().send(new CrossfadeRequest("menu", true));
getEventBus().send(new CrossfadeRequest("game", true));
}
}

@ -86,7 +86,8 @@ public final class Res {
textures.addSheet("tile.brick.floor", tiles.makeSheet(0, 1, 5, 1));
textures.addSheet("tile.brick.wall", tiles.makeSheet(0, 0, 8, 1));
textures.addSheet("tile.brick.door.locked", tiles.makeSheet(1, 2, 1, 1));//TODO unique tx
textures.addSheet("tile.brick.door.closed", tiles.makeSheet(1, 2, 1, 1));
textures.addSheet("tile.brick.door.open", tiles.makeSheet(2, 2, 1, 1));
textures.addSheet("tile.brick.door.secret", tiles.makeSheet(0, 3, 2, 1));
@ -134,7 +135,7 @@ public final class Res {
}
public static TxSheet getTxSheet(String key)
public static TxSheet sheet(String key)
{
return textures.getSheet(key);
}

@ -9,6 +9,7 @@ import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonObjBundled;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityModel;
import mightypork.rogue.world.level.Level;
@ -94,7 +95,6 @@ public class World implements IonObjBundled, Updateable {
return eid++;
}
public void createPlayer(int level)
{
if (playerInfo.isInitialized()) { throw new RuntimeException("Player already created."); }
@ -103,7 +103,7 @@ public class World implements IonObjBundled, Updateable {
final int playerEid = getNewEID();
playerEntity = Entities.PLAYER.createEntity(playerEid);
playerEntity.pos.setPosition(levels.get(level).getEnterPoint());
playerEntity.setCoord(levels.get(level).getEnterPoint());
levels.get(level).addEntity(playerEntity);
playerInfo.setLevel(level);

@ -25,7 +25,7 @@ public class WorldCreator {
// TODO real algorithm
// first level
l = LevelGenerator.build(rand.nextLong(), 6, LevelGenerator.DUNGEON_THEME); //
l = LevelGenerator.build(w, rand.nextLong(), 1, LevelGenerator.DUNGEON_THEME); //
w.addLevel(l);
w.createPlayer(0);

@ -89,7 +89,7 @@ public class WorldRenderer extends RectProxy {
// tiles to render
final Entity ent = WorldProvider.get().getPlayerEntity();
final Coord pos = ent.pos.getCoord();
final Coord pos = ent.getCoord();
final double w = width().value();
final double h = height().value();

@ -7,6 +7,7 @@ import java.util.Collection;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.entity.entities.PlayerEntity;
import mightypork.rogue.world.entity.entities.RatEntity;
/**
@ -19,6 +20,7 @@ public final class Entities {
private static final EntityModel[] entities = new EntityModel[256];
public static final EntityModel PLAYER = new EntityModel(1, PlayerEntity.class);
public static final EntityModel RAT = new EntityModel(2, RatEntity.class);
public static void register(int id, EntityModel model)

@ -12,7 +12,7 @@ import mightypork.gamecore.util.error.IllegalValueException;
import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonObjBundled;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContext;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.modules.EntityModuleHealth;
import mightypork.rogue.world.entity.modules.EntityModulePosition;
@ -101,7 +101,9 @@ public abstract class Entity implements IonObjBundled, Updateable {
protected final void addModule(String key, EntityModule module)
{
if (modules.containsKey(key)) { throw new RuntimeException("Entity module " + key + " already defined."); }
if (modules.containsKey(key)) {
throw new RuntimeException("Entity module " + key + " already defined.");
}
modules.put(key, module);
}
@ -117,7 +119,11 @@ public abstract class Entity implements IonObjBundled, Updateable {
public void setLevel(Level level)
{
if (level != null) level.freeTile(getCoord());
this.level = level;
if (level != null) level.occupyTile(getCoord());
}
@ -139,7 +145,7 @@ public abstract class Entity implements IonObjBundled, Updateable {
}
public abstract PathFindingContext getPathfindingContext();
public abstract PathFinder getPathFinder();
@DefaultImpl
@ -176,6 +182,16 @@ public abstract class Entity implements IonObjBundled, Updateable {
}
public void setCoord(Coord coord)
{
if (level != null) level.freeTile(getCoord());
pos.setCoord(coord);
if (level != null) level.occupyTile(getCoord());
}
/**
* Called right after the entity's health reaches zero.
*/

@ -6,6 +6,7 @@ import java.io.IOException;
import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.World;
/**
@ -27,6 +28,10 @@ public final class EntityModel {
this.tileClass = entity;
}
public Entity createEntity(World world)
{
return createEntity(world.getNewEID());
}
public Entity createEntity(int eid)
{

@ -6,15 +6,14 @@ import mightypork.gamecore.util.math.algo.Sides;
import mightypork.gamecore.util.math.algo.Step;
import mightypork.gamecore.util.math.algo.pathfinding.Heuristic;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContext;
public abstract class EntityPathfindingContext implements PathFindingContext {
public class EntityPathFinder extends PathFinder {
protected final Entity entity;
public EntityPathfindingContext(Entity entity)
public EntityPathFinder(Entity entity)
{
this.entity = entity;
}
@ -28,11 +27,15 @@ public abstract class EntityPathfindingContext implements PathFindingContext {
@Override
public abstract int getCost(Coord from, Coord to);
public int getCost(Coord from, Coord to) {
return 10;
}
@Override
public abstract int getMinCost();
public int getMinCost() {
return 10;
}
@Override
@ -45,7 +48,7 @@ public abstract class EntityPathfindingContext implements PathFindingContext {
@Override
public Step[] getWalkSides()
{
return Sides.cardinalSides;
return Sides.CARDINAL_SIDES;
}
}

@ -1,29 +0,0 @@
package mightypork.rogue.world.entity;
import mightypork.gamecore.util.math.algo.Coord;
public class SimpleEntityPathFindingContext extends EntityPathfindingContext {
public SimpleEntityPathFindingContext(Entity entity)
{
super(entity);
}
@Override
public int getCost(Coord from, Coord to)
{
return 10;
}
@Override
public int getMinCost()
{
return 10;
}
}

@ -9,8 +9,7 @@ import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContext;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContextProxy;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinderProxy;
import mightypork.rogue.world.entity.AiTimer;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityModule;
@ -29,7 +28,8 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
@Override
public void run()
{
System.out.println("Mob looks around.");
if (chasing) return;
//System.out.println("Mob looks around.");
lookForTarget();
}
};
@ -39,21 +39,42 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
@Override
public void run()
{
System.out.println("Mob going to sleep");
if (chasing) return;
//System.out.println("Mob going to sleep");
sleeping = true;
}
};
private PathFindingContext pathfcNoDoor;
private final AiTimer timerAttack = new AiTimer(3) {
@Override
public void run()
{
if (!chasing) return;
Entity prey = getPreyEntity();
if (prey == null || prey.isDead()) {
//System.out.println("prey dead?");
return;
}
//System.out.println("Timed prey attack");
attackPrey(prey);
}
};
private PathFinder noDoorPf;
private int targetId = -1;
/** Prey id */
private int preyId = -1;
public MonsterAi(final Entity entity)
{
super(entity);
pathfcNoDoor = new PathFindingContextProxy(entity.getPathfindingContext()) {
noDoorPf = new PathFinderProxy(entity.getPathFinder()) {
@Override
public boolean isAccessible(Coord pos)
@ -65,32 +86,164 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
}
};
timerAttack.start();
timerFindPrey.start();
timerSleepStart.start();
}
@Override
public void onStepFinished()
{
//System.out.println("monster ai step finished.");
if (chasing) {
//System.out.println("chasing..");
final Entity prey = getPreyEntity();
if (!isPreyValid(prey)) {
//System.out.println("prey dead or null, stop chasing: " + prey + ", prey.isdead " + prey.isDead());
stopChasing();
return;
}
if (shouldRandomlyAbandonPrey()) {
stopChasing();
return;
}
if (isPreyInAttackRange(prey)) {
//System.out.println("prey in attack range");
return; // attacking
} else {
stepTowardsPrey(prey);
}
} else {
//System.out.println("not chasing.");
}
}
@Override
public void onPathFinished()
{
}
@Override
public void onPathInterrupted()
{
}
@Override
public void save(IonBundle bundle) throws IOException
{
bundle.putBundled("tscan", timerFindPrey);
bundle.putBundled("tsleep", timerSleepStart);
bundle.putBundled("tattack", timerAttack);
bundle.put("chasing", chasing);
bundle.put("sleeping", sleeping);
bundle.put("prey", preyId);
}
@Override
public void load(IonBundle bundle) throws IOException
{
bundle.loadBundled("tscan", timerFindPrey);
bundle.loadBundled("tsleep", timerSleepStart);
bundle.loadBundled("tattack", timerAttack);
chasing = bundle.get("chasing", chasing);
sleeping = bundle.get("sleeping", sleeping);
preyId = bundle.get("prey", preyId);
}
@Override
public boolean isModuleSaved()
{
return true;
}
@Override
public void update(double delta)
{
timerFindPrey.update(delta);
timerSleepStart.update(delta);
timerAttack.update(delta);
if (chasing && !entity.pos.isMoving()) {
Entity prey = getPreyEntity();
if (!isPreyInAttackRange(prey)) {
//System.out.println("-upd STEP--");
stepTowardsPrey(prey);
}
}
}
public boolean isSleeping()
{
return sleeping;
}
private void lookForTarget()
{
if (rand.nextInt(3) == 0) return; // not hungry right now
if (shouldSkipScan()) return; // not hungry right now
//System.out.println("- Lookin for prey, r=" + getScanRadius());
final Entity prey = entity.getLevel().getClosestEntity(entity, EntityType.PLAYER, getScanRadius());
if (prey != null) {
//System.out.println("-- Prey in sight: " + prey);
//System.out.println("-- path would be: " + entity.getCoord() + "->" + prey.getCoord());
// check if reachable without leaving room
final List<Coord> noDoorPath = PathFinder.findPath(pathfcNoDoor, entity.getCoord(), prey.getCoord());
final List<Coord> noDoorPath = noDoorPf.findPath(entity.getCoord(), prey.getCoord(), true);
if (noDoorPath == null) { return; // cant reach, give up
if (noDoorPath == null) {
//System.out.println("-- Could not navigate to prey, aborting.");
return; // cant reach, give up
}
startChasing(prey);
} else {
//System.out.println("-- Prey is null.");
}
}
private Entity getPreyEntity()
{
return entity.getLevel().getEntity(preyId);
}
private boolean isPreyInAttackRange(Entity prey)
{
return prey.getCoord().dist(entity.getCoord()) <= getAttackDistance();
}
private boolean isPreyValid(Entity prey)
{
return prey != null && !prey.isDead();
}
private void startChasing(Entity prey)
{
// TODO if too close, attack directly
//System.out.println("start chasing");
targetId = prey.getEntityId();
preyId = prey.getEntityId();
chasing = true;
sleeping = false;
@ -106,8 +259,9 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
private void stopChasing()
{
//System.out.println("stop chasing.");
chasing = false;
targetId = -1;
preyId = -1;
timerSleepStart.restart();
timerFindPrey.restart();
}
@ -115,113 +269,107 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
private List<Step> getPathToPrey(Entity prey)
{
return PathFinder.findPathRelative(entity.getPathfindingContext(), entity.getCoord(), prey.getCoord());
}
protected double getScanRadius()
{
return sleeping ? 1 + rand.nextInt(3) : 4 + rand.nextInt(4); // For override
}
protected int getPreyAbandonDistance()
{
return 5 + rand.nextInt(4); // For override
}
@DefaultImpl
@Override
public void onStepFinished()
{
if (chasing) {
final Entity prey = entity.getLevel().getEntity(targetId);
if (prey == null || prey.isDead()) {
stopChasing();
return;
}
stepTowardsPrey(prey);
// TODO if close enough, attack.
}
if (!isPreyValid(prey)) return null;
return entity.getPathFinder().findPathRelative(entity.getCoord(), prey.getCoord(), true);
}
private void stepTowardsPrey(Entity prey)
{
//System.out.println("stepTowardsPrey");
if (!isPreyValid(prey)) {
//System.out.println("prey dead?");
return;
}
// if close enough
final Coord preyPos = prey.getCoord();
if (preyPos.dist(entity.getCoord()) <= 1.5) {
if (isPreyInAttackRange(prey)) {
//System.out.println("attack");
attackPrey(prey);
return;
}
final List<Step> preyPath = getPathToPrey(prey);
if (preyPath.size() > getPreyAbandonDistance()) {
if (preyPath == null || preyPath.size() > getPreyAbandonDistance()) {
//System.out.println("no path");
stopChasing();
return;
}
//System.out.println("step to prey");
entity.pos.addStep(preyPath.get(0));
}
private void attackPrey(Entity prey)
{
if (!isPreyInAttackRange(prey)) {
//System.out.println("prey out of attack range, cant attack");
return;
}
prey.receiveAttack(entity, getAttackStrength());
}
protected int getAttackStrength()
protected void setSleepTime(double secs)
{
return 1; // For override
timerSleepStart.setDuration(secs);
}
@Override
public void onPathFinished()
protected void setAttackTime(double secs)
{
timerAttack.setDuration(secs);
}
@Override
public void onPathInterrupted()
protected void setScanTime(double secs)
{
timerFindPrey.setDuration(secs);
}
@Override
public void save(IonBundle bundle) throws IOException
@DefaultImpl
protected double getScanRadius()
{
bundle.putBundled("tscan", timerFindPrey);
bundle.putBundled("tsleep", timerSleepStart);
return sleeping ? 1 + rand.nextInt(3) : 4 + rand.nextInt(4); // For override
}
@Override
public void load(IonBundle bundle) throws IOException
@DefaultImpl
protected int getPreyAbandonDistance()
{
bundle.loadBundled("tscan", timerFindPrey);
bundle.loadBundled("tsleep", timerSleepStart);
return 5 + rand.nextInt(4); // For override
}
@Override
public boolean isModuleSaved()
@DefaultImpl
protected double getAttackDistance()
{
return true;
return 1.6;
}
@Override
public void update(double delta)
@DefaultImpl
protected int getAttackStrength()
{
timerFindPrey.update(delta);
timerSleepStart.update(delta);
return 1; // For override
}
@DefaultImpl
protected boolean shouldSkipScan()
{
return false;
}
@DefaultImpl
protected boolean shouldRandomlyAbandonPrey()
{
return false;
}
}

@ -2,7 +2,7 @@ package mightypork.rogue.world.entity.entities;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContext;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.rogue.world.entity.*;
import mightypork.rogue.world.entity.modules.EntityMoveListener;
import mightypork.rogue.world.entity.renderers.EntityRenderer;
@ -17,6 +17,8 @@ public class PlayerEntity extends Entity {
public PlayerAi(Entity entity)
{
super(entity);
health.setMaxHealth(24);
health.fill();
}
@ -47,7 +49,7 @@ public class PlayerEntity extends Entity {
}
private EntityPathfindingContext pathfc;
private PathFinder pathf;
private EntityRenderer renderer;
private final PlayerAi ai = new PlayerAi(this);
@ -65,24 +67,24 @@ public class PlayerEntity extends Entity {
@Override
public PathFindingContext getPathfindingContext()
public PathFinder getPathFinder()
{
if (pathfc == null) {
pathfc = new SimpleEntityPathFindingContext(this) {
if (pathf == null) {
pathf = new EntityPathFinder(this) {
@Override
public int getCost(Coord from, Coord to)
{
if (!getLevel().getTile(pos.getCoord()).isExplored()) { return 1000; }
return super.getCost(from, to);
{
if (!getLevel().getTile(pos.getCoord()).isExplored()) {
return 1000;
}
return super.getCost(from, to);
};
};
}
return pathfc;
return pathf;
}

@ -0,0 +1,59 @@
package mightypork.rogue.world.entity.entities;
import mightypork.rogue.world.entity.Entity;
public class RatAi extends MonsterAi {
public RatAi(Entity entity)
{
super(entity);
setAttackTime(1);
setScanTime(2);
setSleepTime(100);
}
@Override
protected double getScanRadius()
{
return isSleeping() ? 2 + rand.nextInt(3) : 4 + rand.nextInt(3);
}
@Override
protected double getAttackDistance()
{
return 1.42;
}
@Override
protected int getAttackStrength()
{
return 1 + rand.nextInt(2);
}
@Override
protected int getPreyAbandonDistance()
{
return 8 + rand.nextInt(4);
}
@Override
protected boolean shouldSkipScan()
{
return false;//rand.nextInt(3) == 0;
}
@Override
protected boolean shouldRandomlyAbandonPrey()
{
return false;//rand.nextInt(8) == 0;
}
}

@ -0,0 +1,59 @@
package mightypork.rogue.world.entity.entities;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.rogue.world.entity.*;
import mightypork.rogue.world.entity.renderers.EntityRenderer;
import mightypork.rogue.world.entity.renderers.EntityRendererMobLR;
public class RatEntity extends Entity {
/** Navigation PFC */
private PathFinder pathf;
private final RatAi ai = new RatAi(this);
private EntityRenderer renderer;
public RatEntity(EntityModel model, int eid)
{
super(model, eid);
addModule("ai", ai);
pos.addMoveListener(ai);
pos.setStepTime(0.5);
}
@Override
public PathFinder getPathFinder()
{
if (pathf == null) {
pathf = new EntityPathFinder(this);
}
return pathf;
}
@Override
public EntityType getType()
{
return EntityType.MONSTER;
}
@Override
protected EntityRenderer getRenderer()
{
if (renderer == null) {
renderer = new EntityRendererMobLR(this, "sprite.player");
}
return renderer;
}
}

@ -1,41 +0,0 @@
package mightypork.rogue.world.entity.entities;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContext;
import mightypork.rogue.world.entity.*;
public abstract class SimpleMonster extends Entity {
/** Navigation PFC */
private EntityPathfindingContext pathfc;
private final EntityModule ai = new MonsterAi(this);
public SimpleMonster(EntityModel model, int eid)
{
super(model, eid);
addModule("ai", ai);
}
@Override
public PathFindingContext getPathfindingContext()
{
if (pathfc == null) {
pathfc = new SimpleEntityPathFindingContext(this);
}
return pathfc;
}
@Override
public EntityType getType()
{
return EntityType.MONSTER;
}
}

@ -94,5 +94,11 @@ public class EntityModuleHealth extends EntityModule {
{
setHealth(health - attackStrength);
}
public void fill()
{
setHealth(maxHealth);
}
}

@ -12,7 +12,6 @@ import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContext;
import mightypork.gamecore.util.math.constraints.vect.VectConst;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityModule;
@ -67,7 +66,7 @@ public class EntityModulePosition extends EntityModule {
}
public void setPosition(Coord coord)
public void setCoord(Coord coord)
{
entityPos.setTo(coord);
lastPos.setTo(coord);
@ -87,7 +86,6 @@ public class EntityModulePosition extends EntityModule {
if (walking && entityPos.isFinished()) {
walking = false;
entity.getLevel().freeTile(lastPos);
for (final EntityMoveListener l : moveListeners) {
l.onStepFinished();
@ -123,6 +121,7 @@ public class EntityModulePosition extends EntityModule {
if (step.y() != 0) this.lastYDir = step.y();
lastPos.setTo(entityPos.getCoord());
entity.getLevel().freeTile(lastPos);//
entityPos.walk(step, stepTime);
entity.getLevel().occupyTile(planned);
}
@ -151,8 +150,7 @@ public class EntityModulePosition extends EntityModule {
public boolean navigateTo(Coord target)
{
if (target.equals(getCoord())) return true;
final PathFindingContext pfc = entity.getPathfindingContext();
final List<Step> newPath = PathFinder.findPathRelative(pfc, entityPos.getCoord(), target);
final List<Step> newPath = entity.getPathFinder().findPathRelative(entityPos.getCoord(), target);
if (newPath == null) return false;
cancelPath();

@ -5,16 +5,7 @@ import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.level.render.MapRenderContext;
public abstract class EntityRenderer {
protected final Entity entity;
public EntityRenderer(Entity entity)
{
this.entity = entity;
}
public abstract class EntityRenderer {
public abstract void render(MapRenderContext context);

@ -22,11 +22,13 @@ public class EntityRendererMobLR extends EntityRenderer {
private final TxSheet sheet;
protected final Entity entity;
public EntityRendererMobLR(Entity entity, String sheetKey)
{
super(entity);
this.sheet = Res.getTxSheet(sheetKey);
this.entity = entity;
this.sheet = Res.sheet(sheetKey);
}

@ -4,6 +4,9 @@ package mightypork.rogue.world.gen;
import java.util.Random;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.gen.rooms.DeadEndRoom;
import mightypork.rogue.world.gen.rooms.Rooms;
import mightypork.rogue.world.gen.themes.ThemeBrick;
@ -15,7 +18,7 @@ public class LevelGenerator {
public static final MapTheme DUNGEON_THEME = new ThemeBrick();
public static Level build(long seed, int complexity, MapTheme theme)
public static Level build(World world, long seed, int complexity, MapTheme theme)
{
final Random rand = new Random(seed + 13);
@ -39,6 +42,22 @@ public class LevelGenerator {
map.writeToLevel(lvl);
// TODO tmp
// spawn rats
Coord pos = Coord.make(0,0);
for(int i=0; i<1;i++) { // 4+complexity + rand.nextInt(1+complexity)
Entity e = Entities.RAT.createEntity(world);
for(int j=0; j<20;j++) {
pos.x = rand.nextInt(lvl.getWidth());
pos.y = rand.nextInt(lvl.getHeight());
if(lvl.addEntity(e, pos)) break;
}
}
return lvl;
}
}

@ -14,7 +14,6 @@ import mightypork.gamecore.util.math.algo.Sides;
import mightypork.gamecore.util.math.algo.Step;
import mightypork.gamecore.util.math.algo.pathfinding.Heuristic;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.gamecore.util.math.algo.pathfinding.PathFindingContext;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel;
@ -37,7 +36,7 @@ public class ScratchMap {
/** Coords to connect with corridors */
private final List<Coord> nodes = new ArrayList<>();
private final PathFindingContext pfc = new PathFindingContext() {
private final PathFinder pathf = new PathFinder() {
@Override
public boolean isAccessible(Coord pos)
@ -92,7 +91,7 @@ public class ScratchMap {
@Override
public Step[] getWalkSides()
{
return Sides.cardinalSides;
return Sides.CARDINAL_SIDES;
}
};
@ -291,7 +290,7 @@ public class ScratchMap {
private void buildCorridor(Coord node1, Coord node2)
{
Log.f3("Building corridor " + node1 + " -> " + node2);
final List<Coord> steps = PathFinder.findPath(pfc, node1, node2);
final List<Coord> steps = pathf.findPath(node1, node2);
if (steps == null) {
Log.w("Could not build corridor " + node1 + "->" + node2);
@ -442,29 +441,29 @@ public class ScratchMap {
break;
}
if (isFloor && (nils & Sides.CARDINAL) != 0) {
if (isFloor && (nils & Sides.MASK_CARDINAL) != 0) {
toWall = true; // floor with adjacent cardinal null
break;
}
if (isNull && (floors & Sides.DIAGONAL) != 0) {
if (isNull && (floors & Sides.MASK_DIAGONAL) != 0) {
toWall = true; // null with adjacent diagonal floor
break;
}
if (isDoor) {
if (countBits((byte) (floors & Sides.CARDINAL)) < 2) {
if (countBits((byte) (floors & Sides.MASK_CARDINAL)) < 2) {
toWall = true;
break;
}
if (countBits((byte) (walls & Sides.CARDINAL)) > 2) {
if (countBits((byte) (walls & Sides.MASK_CARDINAL)) > 2) {
toWall = true;
break;
}
if (countBits((byte) (floors & Sides.CARDINAL)) > 2) {
if (countBits((byte) (floors & Sides.MASK_CARDINAL)) > 2) {
toFloor = true;
break;
}

@ -72,7 +72,7 @@ public abstract class AbstractRectRoom implements RoomBuilder {
break;
}
if ((map.findDoors(door) & Sides.CARDINAL) == 0) {
if ((map.findDoors(door) & Sides.MASK_CARDINAL) == 0) {
map.set(door, getDoorType(theme, rand));
i++; // increment pointer
}

@ -43,7 +43,7 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL
public MapView()
{
this.tileSize = height().min(width()).div(8).max(32).mul(Num.make(1).sub(zoom.mul(0.66)));
this.tileSize = height().min(width()).div(12).max(32).mul(Num.make(1).sub(zoom.mul(0.66)));
this.worldRenderer = new WorldRenderer(this, tileSize);
pc = WorldProvider.get().getPlayerControl();
pc.addMoveListener(this);

@ -173,7 +173,7 @@ public class Level implements MapAccess, IonObjBinary {
// prepare entities
for (final Entity ent : entitySet) {
ent.setLevel(this);
occupyTile(ent.pos.getCoord());
occupyTile(ent.getCoord());
entityMap.put(ent.getEntityId(), ent);
}
}
@ -241,6 +241,25 @@ public class Level implements MapAccess, IonObjBinary {
}
/**
* Try to add entity at given pos
* @param entity the entity
* @param pos pos
* @return true if added (false if void, wall etc)
*/
public boolean addEntity(Entity entity, Coord pos)
{
Tile t = getTile(pos);
if (!t.isWalkable()) return false;
addEntity(entity);
entity.setCoord(pos);
return true;
}
public void addEntity(Entity entity)
{
if (entityMap.containsKey(entity.getEntityId())) {
@ -353,7 +372,7 @@ public class Level implements MapAccess, IonObjBinary {
@Override
public Step[] getSpreadSides()
{
return Sides.allSides;
return Sides.ALL_SIDES;
}

@ -4,6 +4,7 @@ package mightypork.rogue.world.tile;
import java.io.IOException;
import java.util.Random;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonObjBlob;
@ -22,14 +23,11 @@ import mightypork.rogue.world.level.render.TileRenderContext;
public abstract class Tile implements IonObjBlob {
// tmp extras
public final TileRenderData renderData = new TileRenderData();
public final TileGenData genData = new TileGenData();
/** RNG for random stuff in tiles */
protected static final Random rand = new Random();
protected final TileRenderer renderer;
public final TileModel model;
// temporary flag for map.
@ -37,10 +35,9 @@ public abstract class Tile implements IonObjBlob {
protected boolean explored;
public Tile(TileModel model, TileRenderer renderer)
public Tile(TileModel model)
{
this.model = model;
this.renderer = renderer;
}
@ -52,14 +49,23 @@ public abstract class Tile implements IonObjBlob {
{
if (!isExplored()) return;
renderer.renderTile(context);
TileRenderer r = getRenderer();
if (r == null) {
Log.e("Tile with no renderer: " + Log.str(this));
return;
}
r.renderTile(context);
if (doesReceiveShadow()) renderer.renderShadows(context);
if (doesReceiveShadow()) r.renderShadows(context);
renderer.renderUnexploredFog(context);
r.renderUnexploredFog(context);
}
protected abstract TileRenderer getRenderer();
/**
* Render extra stuff (ie. dropped items).<br>
* Called after the whole map is rendered using renderTile.
@ -137,6 +143,7 @@ public abstract class Tile implements IonObjBlob {
@DefaultImpl
public void update(Level level, double delta)
{
getRenderer().update(delta);
}

@ -16,15 +16,13 @@ public final class TileModel {
/** Model ID */
public final int id;
public final TileRenderer renderer;
public final Class<? extends Tile> tileClass;
public TileModel(int id, Class<? extends Tile> tile, TileRenderer renderer)
public TileModel(int id, Class<? extends Tile> tile)
{
Tiles.register(id, this);
this.id = id;
this.renderer = renderer;
this.tileClass = tile;
}
@ -32,10 +30,10 @@ public final class TileModel {
/**
* @return new tile of this type
*/
public Tile createTile()
public <T extends Tile> T createTile()
{
try {
return tileClass.getConstructor(TileModel.class, TileRenderer.class).newInstance(this, renderer);
return (T) tileClass.getConstructor(TileModel.class).newInstance(this);
} catch (final Exception e) {
throw new RuntimeException("Could not instantiate a tile.", e);
}
@ -52,6 +50,8 @@ public final class TileModel {
public void saveTile(IonOutput out, Tile tile) throws IOException
{
if (tileClass != tile.getClass()) throw new RuntimeException("Tile class mismatch.");
tile.save(out);
}
}

@ -1,14 +0,0 @@
package mightypork.rogue.world.tile;
/**
* Data storage for tile renderer
*
* @author MightyPork
*/
public class TileRenderData {
public byte shadows;
public boolean shadowsComputed;
}

@ -1,30 +1,45 @@
package mightypork.rogue.world.tile;
import mightypork.gamecore.eventbus.events.Updateable;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.gamecore.util.math.algo.Sides;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.Res;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.renderers.NullTileRenderer;
/**
* Renderer for a tile model, in client
* Renderer for a tile; each tile has own renderer.
*
* @author MightyPork
*/
public abstract class TileRenderer {
public abstract class TileRenderer implements Updateable {
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 UFOG_N, UFOG_S, UFOG_E, UFOG_W, UFOG_NW, UFOG_NE, UFOG_SW, UFOG_SE;
private static boolean inited;
// data
public byte shadows;
public boolean shadowsComputed;
protected final Tile tile;
protected Tile getTile() {
return tile;
}
public TileRenderer()
public TileRenderer(Tile tile)
{
this.tile = tile;
if (!inited) {
SH_N = Res.getTxQuad("tile.shadow.n");
SH_S = Res.getTxQuad("tile.shadow.s");
@ -51,48 +66,44 @@ public abstract class TileRenderer {
public void renderShadows(TileRenderContext context)
{
final TileRenderData trd = context.getTile().renderData;
if (!trd.shadowsComputed) {
{
if (!shadowsComputed) {
// no shadows computed yet
trd.shadows = 0; // reset the mask
shadows = 0; // reset the mask
for (int i = 0; i < 8; i++) {
final Tile t2 = context.getAdjacentTile(Sides.get(i));
if (!t2.isNull() && t2.doesCastShadow()) {
trd.shadows |= Sides.bit(i);
shadows |= Sides.bit(i);
}
}
trd.shadowsComputed = true;
shadowsComputed = true;
}
if (trd.shadows == 0) return;
if (shadows == 0) return;
final Rect rect = context.getRect();
if ((trd.shadows & Sides.NW_CORNER) == Sides.MASK_NW) Render.quadTextured(rect, SH_NW);
if ((trd.shadows & Sides.MASK_N) != 0) Render.quadTextured(rect, SH_N);
if ((trd.shadows & Sides.NE_CORNER) == Sides.MASK_NE) Render.quadTextured(rect, SH_NE);
if ((shadows & Sides.NW_CORNER) == Sides.MASK_NW) Render.quadTextured(rect, SH_NW);
if ((shadows & Sides.MASK_N) != 0) Render.quadTextured(rect, SH_N);
if ((shadows & Sides.NE_CORNER) == Sides.MASK_NE) Render.quadTextured(rect, SH_NE);
if ((trd.shadows & Sides.MASK_W) != 0) Render.quadTextured(rect, SH_W);
if ((trd.shadows & Sides.MASK_E) != 0) Render.quadTextured(rect, SH_E);
if ((shadows & Sides.MASK_W) != 0) Render.quadTextured(rect, SH_W);
if ((shadows & Sides.MASK_E) != 0) Render.quadTextured(rect, SH_E);
if ((trd.shadows & Sides.SW_CORNER) == Sides.MASK_SW) Render.quadTextured(rect, SH_SW);
if ((trd.shadows & Sides.MASK_S) != 0) Render.quadTextured(rect, SH_S);
if ((trd.shadows & Sides.SE_CORNER) == Sides.MASK_SE) Render.quadTextured(rect, SH_SE);
if ((shadows & Sides.SW_CORNER) == Sides.MASK_SW) Render.quadTextured(rect, SH_SW);
if ((shadows & Sides.MASK_S) != 0) Render.quadTextured(rect, SH_S);
if ((shadows & Sides.SE_CORNER) == Sides.MASK_SE) Render.quadTextured(rect, SH_SE);
}
public void renderUnexploredFog(TileRenderContext context)
{
// TODO cache in tile, update neighbouring tiles upon "explored" flag changed.
// TODO cache values, update neighbouring tiles upon "explored" flag changed.
byte ufog = 0;
ufog = 0; // reset the mask
for (int i = 0; i < 8; i++) {
final Tile t2 = context.getAdjacentTile(Sides.get(i));
if (t2.isNull() || !t2.isExplored()) {
@ -114,4 +125,9 @@ public abstract class TileRenderer {
if ((ufog & Sides.MASK_S) != 0) Render.quadTextured(rect, UFOG_S);
if ((ufog & Sides.SE_CORNER) == Sides.MASK_SE) Render.quadTextured(rect, UFOG_SE);
}
@Override
public void update(double delta)
{
}
}

@ -6,10 +6,14 @@ import java.io.IOException;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.tile.renderers.BasicTileRenderer;
import mightypork.rogue.world.tile.renderers.DoorRenderer;
import mightypork.rogue.world.tile.renderers.LockedDoorRenderer;
import mightypork.rogue.world.tile.renderers.DoorTileRenderer;
import mightypork.rogue.world.tile.renderers.NullTileRenderer;
import mightypork.rogue.world.tile.tiles.*;
import mightypork.rogue.world.tile.tiles.brick.TileBrickDoor;
import mightypork.rogue.world.tile.tiles.brick.TileBrickFloor;
import mightypork.rogue.world.tile.tiles.brick.TileBrickPassage;
import mightypork.rogue.world.tile.tiles.brick.TileBrickSecretDoor;
import mightypork.rogue.world.tile.tiles.brick.TileBrickWall;
/**
@ -21,13 +25,13 @@ public final class Tiles {
private static final TileModel[] tiles = new TileModel[256];
public static final TileModel NULL = new TileModel(0, NullTile.class, new NullTileRenderer());
public static final TileModel NULL = new TileModel(0, NullTile.class);
public static final TileModel BRICK_FLOOR = new TileModel(10, FloorTile.class, new BasicTileRenderer("tile.brick.floor"));
public static final TileModel BRICK_WALL = new TileModel(11, WallTile.class, new BasicTileRenderer("tile.brick.wall"));
public static final TileModel BRICK_DOOR = new TileModel(12, DoorTile.class, new DoorRenderer("tile.brick.door.closed", "tile.brick.door.open"));
public static final TileModel BRICK_PASSAGE = new TileModel(13, WallPassageTile.class, new BasicTileRenderer("tile.brick.passage"));
public static final TileModel BRICK_HIDDEN_DOOR = new TileModel(14, SecretDoorTile.class, new LockedDoorRenderer("tile.brick.door.secret", "tile.brick.door.closed", "tile.brick.door.open"));
public static final TileModel BRICK_FLOOR = new TileModel(10, TileBrickFloor.class);
public static final TileModel BRICK_WALL = new TileModel(11, TileBrickWall.class);
public static final TileModel BRICK_DOOR = new TileModel(12, TileBrickDoor.class);
public static final TileModel BRICK_PASSAGE = new TileModel(13, TileBrickPassage.class);
public static final TileModel BRICK_HIDDEN_DOOR = new TileModel(14, TileBrickSecretDoor.class);
public static void register(int id, TileModel model)

@ -4,8 +4,8 @@ package mightypork.rogue.world.tile.renderers;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.Res;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileRenderer;
@ -14,9 +14,10 @@ public class BasicTileRenderer extends TileRenderer {
private final TxSheet sheet;
public BasicTileRenderer(String sheetKey)
public BasicTileRenderer(Tile tile, TxSheet sheet)
{
this.sheet = Res.getTxSheet(sheetKey);
super(tile);
this.sheet = sheet;
}

@ -1,39 +0,0 @@
package mightypork.rogue.world.tile.renderers;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.Res;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileRenderer;
public class DoorRenderer extends TileRenderer {
private final TxSheet closed;
private final TxSheet open;
public DoorRenderer(String quadClosed, String quadOpen)
{
this.closed = Res.getTxSheet(quadClosed);
this.open = Res.getTxSheet(quadOpen);
}
@Override
public void renderTile(TileRenderContext context)
{
final Tile t = context.getTile();
final Rect rect = context.getRect();
if (t.isOccupied()) {
Render.quadTextured(rect, open.getRandomQuad(context.getTileNoise()));
} else {
Render.quadTextured(rect, closed.getRandomQuad(context.getTileNoise()));
}
}
}

@ -0,0 +1,70 @@
package mightypork.rogue.world.tile.renderers;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.gamecore.util.math.timing.TimedTask;
import mightypork.rogue.Res;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.tiles.TileBaseDoor;
public class DoorTileRenderer extends TileRenderer {
private final TxSheet locked;
private final TxSheet closed;
private final TxSheet open;
private boolean visuallyOpen = false;
private final TimedTask closeTask = new TimedTask() {
@Override
public void run()
{
System.out.println("CLOSEDOOR + "+ ((TileBaseDoor) tile).isOpen());
visuallyOpen = ((TileBaseDoor) tile).isOpen();
}
};
public DoorTileRenderer(TileBaseDoor doorTile, TxSheet locked, TxSheet closed, TxSheet open)
{
super(doorTile);
this.locked = locked;
this.closed = closed;
this.open = open;
}
@Override
public void renderTile(TileRenderContext context)
{
final Rect rect = context.getRect();
if (!visuallyOpen && ((TileBaseDoor) tile).isOpen()) visuallyOpen = true;
if (visuallyOpen && !((TileBaseDoor) tile).isOpen()) {
if(!closeTask.isRunning()) closeTask.start(0.4);
}
if (visuallyOpen) {
Render.quadTextured(rect, open.getRandomQuad(context.getTileNoise()));
} else {
TxSheet sheet = (((TileBaseDoor) tile).isLocked() ? locked : closed);
Render.quadTextured(rect, sheet.getRandomQuad(context.getTileNoise()));
}
}
@Override
public void update(double delta)
{
closeTask.update(delta);
}
}

@ -1,38 +0,0 @@
package mightypork.rogue.world.tile.renderers;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.Res;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileRenderer;
public class LockedDoorRenderer extends DoorRenderer {
private final TxSheet locked;
public LockedDoorRenderer(String sheetLocked, String sheetClosed, String sheetOpen)
{
super(sheetClosed, sheetOpen);
this.locked = Res.getTxSheet(sheetLocked);
}
@Override
public void renderTile(TileRenderContext context)
{
final Tile t = context.getTile();
if (!t.isWalkable()) {
final Rect rect = context.getRect();
Render.quadTextured(rect, locked.getRandomQuad(context.getTileNoise()));
} else {
super.renderTile(context);
}
}
}

@ -2,14 +2,44 @@ package mightypork.rogue.world.tile.renderers;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileRenderer;
/**
* Do-nothing tile renderer
*
* @author MightyPork
*/
public class NullTileRenderer extends TileRenderer {
public NullTileRenderer()
{
super(null);
}
@Override
public void renderTile(TileRenderContext context)
{
}
@Override
public void renderShadows(TileRenderContext context)
{
}
@Override
public void renderUnexploredFog(TileRenderContext context)
{
}
@Override
public void update(double delta)
{
}
}

@ -1,29 +0,0 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
public class DoorTile extends SolidTile {
public DoorTile(TileModel model, TileRenderer renderer)
{
super(model, renderer);
}
@Override
public boolean isWalkable()
{
return true;
}
@Override
public TileType getType()
{
return TileType.DOOR;
}
}

@ -1,22 +0,0 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
public class FloorTile extends GroundTile {
public FloorTile(TileModel model, TileRenderer renderer)
{
super(model, renderer);
}
@Override
public TileType getType()
{
return TileType.FLOOR;
}
}

@ -1,44 +0,0 @@
package mightypork.rogue.world.tile.tiles;
import java.io.IOException;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
public class LockedDoorTile extends DoorTile {
public boolean locked = true;
public LockedDoorTile(TileModel model, TileRenderer renderer)
{
super(model, renderer);
}
@Override
public boolean isWalkable()
{
return !locked;
}
@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);
}
}

@ -12,9 +12,15 @@ import mightypork.rogue.world.tile.TileType;
public class NullTile extends Tile {
public NullTile(TileModel model, TileRenderer renderer)
public NullTile(TileModel model)
{
super(model, renderer);
super(model);
}
@Override
protected TileRenderer getRenderer()
{
return TileRenderer.NONE;
}

@ -0,0 +1,82 @@
package mightypork.rogue.world.tile.tiles;
import java.io.IOException;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.renderers.DoorTileRenderer;
public abstract class TileBaseDoor extends TileSolid {
private final DoorTileRenderer renderer;
protected boolean locked = false;
public TileBaseDoor(TileModel model, TxSheet locked, TxSheet closed, TxSheet open)
{
super(model);
this.renderer = new DoorTileRenderer(this, locked, closed, open);
}
@Override
protected TileRenderer getRenderer()
{
return renderer;
}
@Override
public boolean isWalkable()
{
return !locked;
}
@Override
public TileType getType()
{
return TileType.DOOR;
}
@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);
}
/**
* @return true if the door appears open
*/
public boolean isOpen()
{
return isOccupied();
}
/**
* @return true if the door is locked
*/
public boolean isLocked()
{
return locked;
}
}

@ -0,0 +1,34 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.renderers.BasicTileRenderer;
public abstract class TileBaseFloor extends TileWalkable {
private BasicTileRenderer renderer;
public TileBaseFloor(TileModel model, TxSheet sheet)
{
super(model);
this.renderer = new BasicTileRenderer(this, sheet);
}
@Override
protected TileRenderer getRenderer()
{
return renderer;
}
@Override
public TileType getType()
{
return TileType.FLOOR;
}
}

@ -0,0 +1,49 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.renderers.BasicTileRenderer;
/**
* Collapsed wall that's walk-through
*
* @author MightyPork
*/
public abstract class TileBasePassage extends TileSolid {
private BasicTileRenderer renderer;
public TileBasePassage(TileModel model, TxSheet sheet)
{
super(model);
this.renderer = new BasicTileRenderer(this, sheet);
}
@Override
protected TileRenderer getRenderer()
{
return renderer;
}
@Override
public TileType getType()
{
return TileType.PASSAGE;
}
@Override
public boolean isWalkable()
{
return true;
}
}

@ -3,24 +3,27 @@ package mightypork.rogue.world.tile.tiles;
import java.io.IOException;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.color.pal.RGB;
import mightypork.gamecore.util.math.timing.TimedTask;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.renderers.DoorTileRenderer;
public class SecretDoorTile extends LockedDoorTile {
public abstract class TileBaseSecretDoor extends TileBaseDoor {
private int clicks = 2 + rand.nextInt(2);
public SecretDoorTile(TileModel model, TileRenderer renderer)
public TileBaseSecretDoor(TileModel model, TxSheet secret, TxSheet closed, TxSheet open)
{
super(model, renderer);
super(model, secret, closed, open);
}
@ -41,7 +44,7 @@ public class SecretDoorTile extends LockedDoorTile {
public Color getMapColor()
{
if (locked) return TileType.WALL.getMapColor();
return super.getMapColor();
return RGB.PINK;
}

@ -0,0 +1,35 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.renderers.BasicTileRenderer;
public abstract class TileBaseWall extends TileSolid {
private BasicTileRenderer renderer;
public TileBaseWall(TileModel model, TxSheet sheet)
{
super(model);
this.renderer = new BasicTileRenderer(this, sheet);
}
public BasicTileRenderer getRenderer()
{
return renderer;
}
@Override
public TileType getType()
{
return TileType.WALL;
}
}

@ -7,11 +7,11 @@ import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
public abstract class SolidTile extends Tile {
public abstract class TileSolid extends Tile {
public SolidTile(TileModel model, TileRenderer renderer)
public TileSolid(TileModel model)
{
super(model, renderer);
super(model);
}

@ -15,16 +15,16 @@ import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
public abstract class GroundTile extends Tile {
public abstract class TileWalkable extends Tile {
private final DroppedItemRenderer itemRenderer = new DroppedItemRenderer();
protected final Stack<Item> items = new Stack<>();
public GroundTile(TileModel model, TileRenderer renderer)
public TileWalkable(TileModel model)
{
super(model, renderer);
super(model);
}
@ -40,6 +40,7 @@ public abstract class GroundTile extends Tile {
@Override
public void update(Level level, double delta)
{
super.update(level, delta);
itemRenderer.update(delta);
}

@ -1,35 +0,0 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
/**
* Collapsed wall that's walk-through
*
* @author MightyPork
*/
public class WallPassageTile extends SolidTile {
public WallPassageTile(TileModel model, TileRenderer renderer)
{
super(model, renderer);
}
@Override
public TileType getType()
{
return TileType.PASSAGE;
}
@Override
public boolean isWalkable()
{
return true;
}
}

@ -1,22 +0,0 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
public class WallTile extends SolidTile {
public WallTile(TileModel model, TileRenderer renderer)
{
super(model, renderer);
}
@Override
public TileType getType()
{
return TileType.WALL;
}
}

@ -0,0 +1,22 @@
package mightypork.rogue.world.tile.tiles.brick;
import mightypork.rogue.Res;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.tiles.TileBaseDoor;
public class TileBrickDoor extends TileBaseDoor {
public TileBrickDoor(TileModel model)
{
//@formatter:off
super(
model,
Res.sheet("tile.brick.door.locked"),
Res.sheet("tile.brick.door.closed"),
Res.sheet("tile.brick.door.open")
);
//@formatter:on
}
}

@ -0,0 +1,16 @@
package mightypork.rogue.world.tile.tiles.brick;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.rogue.Res;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.tiles.TileBaseFloor;
public class TileBrickFloor extends TileBaseFloor {
public TileBrickFloor(TileModel model)
{
super(model, Res.sheet("tile.brick.floor"));
}
}

@ -0,0 +1,17 @@
package mightypork.rogue.world.tile.tiles.brick;
import mightypork.rogue.Res;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.tiles.TileBaseDoor;
import mightypork.rogue.world.tile.tiles.TileBasePassage;
public class TileBrickPassage extends TileBasePassage {
public TileBrickPassage(TileModel model)
{
super(model, Res.sheet("tile.brick.passage"));
}
}

@ -0,0 +1,26 @@
package mightypork.rogue.world.tile.tiles.brick;
import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.color.pal.RGB;
import mightypork.rogue.Res;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.tiles.TileBaseDoor;
import mightypork.rogue.world.tile.tiles.TileBaseSecretDoor;
public class TileBrickSecretDoor extends TileBaseSecretDoor {
public TileBrickSecretDoor(TileModel model)
{
//@formatter:off
super(
model,
Res.sheet("tile.brick.door.secret"),
Res.sheet("tile.brick.door.closed"),
Res.sheet("tile.brick.door.open")
);
//@formatter:on
locked = true; // hide it
}
}

@ -0,0 +1,16 @@
package mightypork.rogue.world.tile.tiles.brick;
import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.rogue.Res;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.tiles.TileBaseWall;
public class TileBrickWall extends TileBaseWall {
public TileBrickWall(TileModel model)
{
super(model, Res.sheet("tile.brick.wall"));
}
}
Loading…
Cancel
Save