first monster, remade tile renderer system etc
This commit is contained in:
@@ -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
-6
@@ -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)
|
||||
{
|
||||
|
||||
+9
-6
@@ -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 int targetId = -1;
|
||||
private PathFinder noDoorPf;
|
||||
|
||||
/** 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,123 +86,43 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private void lookForTarget()
|
||||
{
|
||||
if (rand.nextInt(3) == 0) return; // not hungry right now
|
||||
|
||||
final Entity prey = entity.getLevel().getClosestEntity(entity, EntityType.PLAYER, getScanRadius());
|
||||
if (prey != null) {
|
||||
|
||||
// check if reachable without leaving room
|
||||
final List<Coord> noDoorPath = PathFinder.findPath(pathfcNoDoor, entity.getCoord(), prey.getCoord());
|
||||
|
||||
if (noDoorPath == null) { return; // cant reach, give up
|
||||
}
|
||||
|
||||
startChasing(prey);
|
||||
}
|
||||
timerAttack.start();
|
||||
timerFindPrey.start();
|
||||
timerSleepStart.start();
|
||||
}
|
||||
|
||||
|
||||
private void startChasing(Entity prey)
|
||||
{
|
||||
// TODO if too close, attack directly
|
||||
|
||||
targetId = prey.getEntityId();
|
||||
chasing = true;
|
||||
sleeping = false;
|
||||
|
||||
// not good to take a nap while chasing
|
||||
timerSleepStart.pause();
|
||||
|
||||
// follow this one prey
|
||||
timerFindPrey.pause();
|
||||
|
||||
onStepFinished(); // go towards prey
|
||||
}
|
||||
|
||||
|
||||
private void stopChasing()
|
||||
{
|
||||
chasing = false;
|
||||
targetId = -1;
|
||||
timerSleepStart.restart();
|
||||
timerFindPrey.restart();
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
//System.out.println("monster ai step finished.");
|
||||
if (chasing) {
|
||||
final Entity prey = entity.getLevel().getEntity(targetId);
|
||||
if (prey == null || prey.isDead()) {
|
||||
//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;
|
||||
}
|
||||
|
||||
stepTowardsPrey(prey);
|
||||
|
||||
// TODO if close enough, attack.
|
||||
if (isPreyInAttackRange(prey)) {
|
||||
//System.out.println("prey in attack range");
|
||||
return; // attacking
|
||||
} else {
|
||||
stepTowardsPrey(prey);
|
||||
}
|
||||
} else {
|
||||
//System.out.println("not chasing.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void stepTowardsPrey(Entity prey)
|
||||
{
|
||||
// if close enough
|
||||
final Coord preyPos = prey.getCoord();
|
||||
if (preyPos.dist(entity.getCoord()) <= 1.5) {
|
||||
attackPrey(prey);
|
||||
return;
|
||||
}
|
||||
|
||||
final List<Step> preyPath = getPathToPrey(prey);
|
||||
|
||||
if (preyPath.size() > getPreyAbandonDistance()) {
|
||||
stopChasing();
|
||||
return;
|
||||
}
|
||||
|
||||
entity.pos.addStep(preyPath.get(0));
|
||||
}
|
||||
|
||||
|
||||
private void attackPrey(Entity prey)
|
||||
{
|
||||
prey.receiveAttack(entity, getAttackStrength());
|
||||
}
|
||||
|
||||
|
||||
protected int getAttackStrength()
|
||||
{
|
||||
return 1; // For override
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPathFinished()
|
||||
{
|
||||
@@ -199,6 +140,12 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
{
|
||||
bundle.putBundled("tscan", timerFindPrey);
|
||||
bundle.putBundled("tsleep", timerSleepStart);
|
||||
bundle.putBundled("tattack", timerAttack);
|
||||
|
||||
bundle.put("chasing", chasing);
|
||||
bundle.put("sleeping", sleeping);
|
||||
|
||||
bundle.put("prey", preyId);
|
||||
}
|
||||
|
||||
|
||||
@@ -207,6 +154,12 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +175,201 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
{
|
||||
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 (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 = noDoorPf.findPath(entity.getCoord(), prey.getCoord(), true);
|
||||
|
||||
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)
|
||||
{
|
||||
//System.out.println("start chasing");
|
||||
|
||||
preyId = prey.getEntityId();
|
||||
chasing = true;
|
||||
sleeping = false;
|
||||
|
||||
// not good to take a nap while chasing
|
||||
timerSleepStart.pause();
|
||||
|
||||
// follow this one prey
|
||||
timerFindPrey.pause();
|
||||
|
||||
onStepFinished(); // go towards prey
|
||||
}
|
||||
|
||||
|
||||
private void stopChasing()
|
||||
{
|
||||
//System.out.println("stop chasing.");
|
||||
chasing = false;
|
||||
preyId = -1;
|
||||
timerSleepStart.restart();
|
||||
timerFindPrey.restart();
|
||||
}
|
||||
|
||||
|
||||
private List<Step> getPathToPrey(Entity prey)
|
||||
{
|
||||
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
|
||||
if (isPreyInAttackRange(prey)) {
|
||||
//System.out.println("attack");
|
||||
attackPrey(prey);
|
||||
return;
|
||||
}
|
||||
|
||||
final List<Step> preyPath = getPathToPrey(prey);
|
||||
|
||||
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 void setSleepTime(double secs)
|
||||
{
|
||||
timerSleepStart.setDuration(secs);
|
||||
}
|
||||
|
||||
|
||||
protected void setAttackTime(double secs)
|
||||
{
|
||||
timerAttack.setDuration(secs);
|
||||
}
|
||||
|
||||
|
||||
protected void setScanTime(double secs)
|
||||
{
|
||||
timerFindPrey.setDuration(secs);
|
||||
}
|
||||
|
||||
|
||||
@DefaultImpl
|
||||
protected double getScanRadius()
|
||||
{
|
||||
return sleeping ? 1 + rand.nextInt(3) : 4 + rand.nextInt(4); // For override
|
||||
}
|
||||
|
||||
|
||||
@DefaultImpl
|
||||
protected int getPreyAbandonDistance()
|
||||
{
|
||||
return 5 + rand.nextInt(4); // For override
|
||||
}
|
||||
|
||||
|
||||
@DefaultImpl
|
||||
protected double getAttackDistance()
|
||||
{
|
||||
return 1.6;
|
||||
}
|
||||
|
||||
|
||||
@DefaultImpl
|
||||
protected int getAttackStrength()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (doesReceiveShadow()) renderer.renderShadows(context);
|
||||
r.renderTile(context);
|
||||
|
||||
renderer.renderUnexploredFog(context);
|
||||
if (doesReceiveShadow()) r.renderShadows(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;
|
||||
|
||||
public TileRenderer()
|
||||
protected Tile getTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
+7
-4
@@ -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;
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user