parent
ab1c3b3a74
commit
19d13c7903
@ -1,90 +1,102 @@ |
|||||||
package mightypork.rogue.world; |
package mightypork.rogue.world; |
||||||
|
|
||||||
|
|
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
import mightypork.rogue.world.entity.Entity; |
import mightypork.rogue.world.entity.Entity; |
||||||
import mightypork.rogue.world.entity.EntityPos; |
|
||||||
import mightypork.rogue.world.entity.PathStep; |
import mightypork.rogue.world.entity.PathStep; |
||||||
import mightypork.rogue.world.entity.models.EntityMoveListener; |
import mightypork.rogue.world.entity.modules.EntityMoveListener; |
||||||
|
import mightypork.rogue.world.entity.modules.EntityPos; |
||||||
import mightypork.rogue.world.level.Level; |
import mightypork.rogue.world.level.Level; |
||||||
|
|
||||||
|
|
||||||
public class PlayerControl { |
public abstract class PlayerControl { |
||||||
|
|
||||||
private final World world; |
protected Set<EntityMoveListener> playerMoveListeners = new HashSet<>(); |
||||||
|
|
||||||
|
private World lastWorld; |
||||||
|
|
||||||
public PlayerControl(World w) |
|
||||||
{ |
protected abstract World getWorld(); |
||||||
this.world = w; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public Entity getEntity() |
private World getWorld2() |
||||||
|
{ |
||||||
|
World newWorld = getWorld(); |
||||||
|
|
||||||
|
if (newWorld != lastWorld) { |
||||||
|
for (EntityMoveListener eml : playerMoveListeners) { |
||||||
|
newWorld.getPlayerEntity().pos.addMoveListener(eml); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
lastWorld = newWorld; |
||||||
|
|
||||||
|
return newWorld; |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
private Entity getPlayerEntity() |
||||||
{ |
{ |
||||||
return world.getPlayerEntity(); |
if(getWorld2() == null) return null; |
||||||
|
|
||||||
|
return getWorld2().getPlayerEntity(); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public void goNorth() |
public void goNorth() |
||||||
{ |
{ |
||||||
getEntity().cancelPath(); |
getPlayerEntity().pos.cancelPath(); |
||||||
getEntity().addStep(PathStep.NORTH); |
getPlayerEntity().pos.addStep(PathStep.NORTH); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public void goSouth() |
public void goSouth() |
||||||
{ |
{ |
||||||
getEntity().cancelPath(); |
getPlayerEntity().pos.cancelPath(); |
||||||
getEntity().addStep(PathStep.SOUTH); |
getPlayerEntity().pos.addStep(PathStep.SOUTH); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public void goEast() |
public void goEast() |
||||||
{ |
{ |
||||||
getEntity().cancelPath(); |
getPlayerEntity().pos.cancelPath(); |
||||||
getEntity().addStep(PathStep.EAST); |
getPlayerEntity().pos.addStep(PathStep.EAST); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public void goWest() |
public void goWest() |
||||||
{ |
{ |
||||||
getEntity().cancelPath(); |
getPlayerEntity().pos.cancelPath(); |
||||||
getEntity().addStep(PathStep.WEST); |
getPlayerEntity().pos.addStep(PathStep.WEST); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public void navigateTo(Coord pos) |
public void navigateTo(Coord pos) |
||||||
{ |
{ |
||||||
getEntity().navigateTo(pos); |
getPlayerEntity().pos.navigateTo(pos); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public void addMoveListener(EntityMoveListener eml) |
public void addMoveListener(EntityMoveListener eml) |
||||||
{ |
{ |
||||||
getEntity().addMoveListener(eml); |
playerMoveListeners.add(eml); |
||||||
} |
if(getPlayerEntity() != null) { |
||||||
|
getPlayerEntity().pos.addMoveListener(eml); |
||||||
|
} |
||||||
public EntityPos getPos() |
|
||||||
{ |
|
||||||
return getEntity().getPosition(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public World getWorld() |
|
||||||
{ |
|
||||||
return world; |
|
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public Level getLevel() |
public Level getLevel() |
||||||
{ |
{ |
||||||
return world.getCurrentLevel(); |
return getWorld2().getCurrentLevel(); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public Coord getCoord() |
public Coord getCoord() |
||||||
{ |
{ |
||||||
return getEntity().getCoord(); |
return getPlayerEntity().pos.getCoord(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,115 @@ |
|||||||
|
package mightypork.rogue.world; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.rogue.world.entity.modules.EntityMoveListener; |
||||||
|
import mightypork.rogue.world.level.Level; |
||||||
|
import mightypork.util.control.eventbus.BusAccess; |
||||||
|
import mightypork.util.control.eventbus.clients.BusNode; |
||||||
|
import mightypork.util.control.eventbus.clients.RootBusNode; |
||||||
|
import mightypork.util.files.ion.Ion; |
||||||
|
import mightypork.util.timing.Updateable; |
||||||
|
|
||||||
|
|
||||||
|
public class WorldProvider extends RootBusNode implements Updateable { |
||||||
|
|
||||||
|
public static synchronized void init(BusAccess busAccess) |
||||||
|
{ |
||||||
|
if (inst == null) { |
||||||
|
inst = new WorldProvider(busAccess); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public WorldProvider(BusAccess busAccess) { |
||||||
|
super(busAccess); |
||||||
|
setListening(false); |
||||||
|
} |
||||||
|
|
||||||
|
private static WorldProvider inst; |
||||||
|
|
||||||
|
|
||||||
|
public static WorldProvider get() |
||||||
|
{ |
||||||
|
if (inst == null) { |
||||||
|
throw new IllegalStateException("World provider not initialized."); |
||||||
|
} |
||||||
|
|
||||||
|
return inst; |
||||||
|
} |
||||||
|
|
||||||
|
private World world; |
||||||
|
private final PlayerControl playerControl = new PlayerControl() { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected World getWorld() |
||||||
|
{ |
||||||
|
return world; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
public void createWorld(long seed) |
||||||
|
{ |
||||||
|
if (world != null) removeChildClient(world); |
||||||
|
world = WorldCreator.createWorld(seed); |
||||||
|
addChildClient(world); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public World getWorld() |
||||||
|
{ |
||||||
|
return world; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void loadWorld(File file) throws IOException |
||||||
|
{ |
||||||
|
world = Ion.fromFile(file, World.class); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void saveWorld(File file) throws IOException |
||||||
|
{ |
||||||
|
if (world == null) throw new IllegalStateException("Trying to save a NULL world."); |
||||||
|
Ion.toFile(file, world); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Level getCurrentLevel() |
||||||
|
{ |
||||||
|
return getWorld().getCurrentLevel(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Entity getPlayerEntity() |
||||||
|
{ |
||||||
|
return getWorld().getPlayerEntity(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @return constant player control (world independent) |
||||||
|
*/ |
||||||
|
public PlayerControl getPlayerControl() |
||||||
|
{ |
||||||
|
return playerControl; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(double delta) |
||||||
|
{ |
||||||
|
world.update(delta); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected void deinit() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,48 +0,0 @@ |
|||||||
package mightypork.rogue.world.entity; |
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.LinkedList; |
|
||||||
import java.util.Queue; |
|
||||||
|
|
||||||
import mightypork.util.files.ion.IonBundle; |
|
||||||
import mightypork.util.files.ion.IonBundled; |
|
||||||
|
|
||||||
|
|
||||||
public class EntityData implements IonBundled { |
|
||||||
|
|
||||||
public int health = 1; |
|
||||||
public int maxHealth = 1; |
|
||||||
public boolean dead = false; |
|
||||||
|
|
||||||
public final IonBundle extra = new IonBundle(); |
|
||||||
public final Queue<PathStep> path = new LinkedList<>(); |
|
||||||
public final EntityPos position = new EntityPos(); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void save(IonBundle bundle) throws IOException |
|
||||||
{ |
|
||||||
bundle.put("health", health); |
|
||||||
bundle.put("max_health", maxHealth); |
|
||||||
bundle.put("dead", dead); |
|
||||||
bundle.putSequence("steps", path); |
|
||||||
bundle.putBundled("pos", position); |
|
||||||
|
|
||||||
bundle.put("extra", extra); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void load(IonBundle bundle) throws IOException |
|
||||||
{ |
|
||||||
health = bundle.get("health", health); |
|
||||||
maxHealth = bundle.get("max_health", maxHealth); |
|
||||||
dead = bundle.get("dead", dead); |
|
||||||
bundle.loadSequence("path", path); |
|
||||||
bundle.loadBundled("pos", position); |
|
||||||
|
|
||||||
bundle.loadBundle("extra", extra); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,55 @@ |
|||||||
|
package mightypork.rogue.world.entity; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import mightypork.util.files.ion.IonBundle; |
||||||
|
import mightypork.util.files.ion.IonInput; |
||||||
|
import mightypork.util.files.ion.IonOutput; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Entity model |
||||||
|
* |
||||||
|
* @author MightyPork |
||||||
|
*/ |
||||||
|
public final class EntityModel { |
||||||
|
|
||||||
|
/** Model ID */ |
||||||
|
public final int id; |
||||||
|
public final Class<? extends Entity> tileClass; |
||||||
|
|
||||||
|
|
||||||
|
public EntityModel(int id, Class<? extends Entity> entity) |
||||||
|
{ |
||||||
|
Entities.register(id, this); |
||||||
|
this.id = id; |
||||||
|
this.tileClass = entity; |
||||||
|
} |
||||||
|
|
||||||
|
public Entity createEntity(int eid) |
||||||
|
{ |
||||||
|
try { |
||||||
|
return tileClass.getConstructor(EntityModel.class, int.class).newInstance(this, eid); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException("Could not instantiate a tile.", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Entity loadEntity(IonInput in) throws IOException |
||||||
|
{ |
||||||
|
IonBundle bundle = in.readBundle(); |
||||||
|
Entity ent = createEntity(-1); |
||||||
|
ent.load(bundle); |
||||||
|
return ent; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void saveEntity(IonOutput out, Entity entity) throws IOException |
||||||
|
{ |
||||||
|
IonBundle bundle = new IonBundle(); |
||||||
|
entity.save(bundle); |
||||||
|
out.writeBundle(bundle); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
package mightypork.rogue.world.entity; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.world.Coord; |
||||||
|
import mightypork.rogue.world.Sides; |
||||||
|
import mightypork.rogue.world.pathfinding.Heuristic; |
||||||
|
import mightypork.rogue.world.pathfinding.PathFinder; |
||||||
|
import mightypork.rogue.world.pathfinding.PathFindingContext; |
||||||
|
|
||||||
|
|
||||||
|
public abstract class EntityPathfindingContext implements PathFindingContext { |
||||||
|
|
||||||
|
protected final Entity entity; |
||||||
|
|
||||||
|
|
||||||
|
public EntityPathfindingContext(Entity entity) { |
||||||
|
this.entity = entity; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isAccessible(Coord pos) |
||||||
|
{ |
||||||
|
return entity.getLevel().isWalkable(pos); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public abstract int getCost(Coord from, Coord to); |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public abstract int getMinCost(); |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public Heuristic getHeuristic() |
||||||
|
{ |
||||||
|
return PathFinder.DIAGONAL_HEURISTIC; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public Coord[] getWalkSides() |
||||||
|
{ |
||||||
|
return Sides.cardinalSides; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,14 +0,0 @@ |
|||||||
package mightypork.rogue.world.entity; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Data storage for renderer / entity. |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class EntityRenderData { |
|
||||||
|
|
||||||
public int lastXDir = 1; |
|
||||||
public int lastYDir = 1; |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,25 @@ |
|||||||
|
package mightypork.rogue.world.entity; |
||||||
|
|
||||||
|
import mightypork.rogue.world.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; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
package mightypork.rogue.world.entity.entities; |
||||||
|
|
||||||
|
|
||||||
|
import mightypork.rogue.world.Coord; |
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.rogue.world.entity.EntityModel; |
||||||
|
import mightypork.rogue.world.entity.EntityPathfindingContext; |
||||||
|
import mightypork.rogue.world.entity.SimpleEntityPathFindingContext; |
||||||
|
import mightypork.rogue.world.entity.renderers.EntityRenderer; |
||||||
|
import mightypork.rogue.world.entity.renderers.SimpleLeftRightMobRenderer; |
||||||
|
import mightypork.rogue.world.level.render.MapRenderContext; |
||||||
|
import mightypork.rogue.world.pathfinding.PathFindingContext; |
||||||
|
|
||||||
|
|
||||||
|
public class PlayerEntity extends Entity { |
||||||
|
|
||||||
|
private final EntityPathfindingContext pathfc = new SimpleEntityPathFindingContext(this) { |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCost(Coord from, Coord to) |
||||||
|
{ |
||||||
|
|
||||||
|
if (!getLevel().getTile(pos.getCoord()).isExplored()) { |
||||||
|
return 1000; |
||||||
|
} |
||||||
|
|
||||||
|
return super.getCost(from, to); |
||||||
|
|
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
private final EntityRenderer renderer = new SimpleLeftRightMobRenderer(this, "sprite.player"); |
||||||
|
|
||||||
|
|
||||||
|
public PlayerEntity(EntityModel model, int eid) { |
||||||
|
super(model, eid); |
||||||
|
|
||||||
|
// init default values
|
||||||
|
pos.setStepTime(0.25); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public PathFindingContext getPathfindingContext() |
||||||
|
{ |
||||||
|
return pathfc; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void render(MapRenderContext context) |
||||||
|
{ |
||||||
|
renderer.render(context); |
||||||
|
} |
||||||
|
} |
@ -1,108 +0,0 @@ |
|||||||
package mightypork.rogue.world.entity.models; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.Coord; |
|
||||||
import mightypork.rogue.world.entity.Entities; |
|
||||||
import mightypork.rogue.world.entity.Entity; |
|
||||||
import mightypork.rogue.world.entity.EntityData; |
|
||||||
import mightypork.rogue.world.entity.renderers.EntityRenderer; |
|
||||||
import mightypork.rogue.world.pathfinding.Heuristic; |
|
||||||
import mightypork.rogue.world.pathfinding.PathFinder; |
|
||||||
import mightypork.util.annotations.DefaultImpl; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Entity model |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public abstract class EntityModel implements EntityMoveListener { |
|
||||||
|
|
||||||
/** Model ID */ |
|
||||||
public final int id; |
|
||||||
public EntityRenderer renderer = EntityRenderer.NONE; |
|
||||||
|
|
||||||
|
|
||||||
public EntityModel(int id) { |
|
||||||
Entities.register(id, this); |
|
||||||
this.id = id; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public EntityModel setRenderer(EntityRenderer renderer) |
|
||||||
{ |
|
||||||
this.renderer = renderer; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* @return new tile of this type; if 100% invariant, can return cached one. |
|
||||||
*/ |
|
||||||
public Entity createEntity(int eid) |
|
||||||
{ |
|
||||||
return new Entity(eid, this); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Entity is idle, waiting for action. |
|
||||||
*/ |
|
||||||
public abstract void update(Entity entity, double delta); |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Get one path step duration (in seconds) |
|
||||||
*/ |
|
||||||
public abstract double getStepTime(Entity entity); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onStepFinished(Entity entity); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onPathFinished(Entity entity); |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public abstract void onPathInterrupted(Entity entity); |
|
||||||
|
|
||||||
|
|
||||||
@DefaultImpl |
|
||||||
public boolean canWalkInto(Entity entity, Coord pos) |
|
||||||
{ |
|
||||||
return entity.getLevel().canWalkInto(pos); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@DefaultImpl |
|
||||||
public int getPathMinCost() |
|
||||||
{ |
|
||||||
return 10; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@DefaultImpl |
|
||||||
public Heuristic getPathHeuristic() |
|
||||||
{ |
|
||||||
return PathFinder.DIAGONAL_HEURISTIC; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@DefaultImpl |
|
||||||
public int getPathCost(Entity entity, Coord from, Coord to) |
|
||||||
{ |
|
||||||
return 10; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public abstract void initMetadata(EntityData metadata); |
|
||||||
|
|
||||||
|
|
||||||
@DefaultImpl |
|
||||||
public void onEnteredLevel(Entity entity) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,95 +0,0 @@ |
|||||||
package mightypork.rogue.world.entity.models; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.Coord; |
|
||||||
import mightypork.rogue.world.entity.Entity; |
|
||||||
import mightypork.rogue.world.entity.EntityData; |
|
||||||
import mightypork.rogue.world.entity.renderers.PlayerRenderer; |
|
||||||
import mightypork.rogue.world.tile.Tile; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Player info |
|
||||||
* |
|
||||||
* @author MightyPork |
|
||||||
*/ |
|
||||||
public class PlayerModel extends EntityModel { |
|
||||||
|
|
||||||
private static final double STEP_TIME = 0.25; |
|
||||||
|
|
||||||
|
|
||||||
public PlayerModel(int id) { |
|
||||||
super(id); |
|
||||||
setRenderer(new PlayerRenderer("player")); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void update(Entity entity, double delta) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public double getStepTime(Entity entity) |
|
||||||
{ |
|
||||||
return STEP_TIME; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onStepFinished(Entity entity) |
|
||||||
{ |
|
||||||
exploreSurroundings(entity); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private void exploreSurroundings(Entity entity) |
|
||||||
{ |
|
||||||
entity.getLevel().explore(entity.getCoord()); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onEnteredLevel(Entity entity) |
|
||||||
{ |
|
||||||
exploreSurroundings(entity); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onPathFinished(Entity entity) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void onPathInterrupted(Entity entity) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public void initMetadata(EntityData metadata) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean canWalkInto(Entity entity, Coord pos) |
|
||||||
{ |
|
||||||
final Tile t = entity.getLevel().getTile(pos); |
|
||||||
return t.isWalkable(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public int getPathCost(Entity entity, Coord from, Coord to) |
|
||||||
{ |
|
||||||
if (!entity.getLevel().getTile(entity.getCoord()).isExplored()) { |
|
||||||
return 1000; |
|
||||||
} |
|
||||||
|
|
||||||
return super.getPathCost(entity, from, to); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,92 @@ |
|||||||
|
package mightypork.rogue.world.entity.modules; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.util.error.IllegalValueException; |
||||||
|
import mightypork.util.files.ion.IonBundle; |
||||||
|
import mightypork.util.files.ion.IonBundled; |
||||||
|
import mightypork.util.math.Calc; |
||||||
|
|
||||||
|
|
||||||
|
public class EntityHealthModule implements EntityModule { |
||||||
|
|
||||||
|
public EntityHealthModule(Entity entity) { |
||||||
|
this.entity = entity; |
||||||
|
} |
||||||
|
|
||||||
|
private final Entity entity; |
||||||
|
|
||||||
|
protected int health = 1; |
||||||
|
protected int maxHealth = 1; |
||||||
|
protected boolean dead = false; |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void load(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
health = bundle.get("health", health); |
||||||
|
maxHealth = bundle.get("max_health", maxHealth); |
||||||
|
dead = bundle.get("dead", dead); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void save(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
bundle.put("health", health); |
||||||
|
bundle.put("max_health", maxHealth); |
||||||
|
bundle.put("dead", dead); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(double delta) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public int getHealth() |
||||||
|
{ |
||||||
|
return health; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setHealth(int health) |
||||||
|
{ |
||||||
|
|
||||||
|
this.health = Calc.clamp(health, 0, maxHealth); |
||||||
|
|
||||||
|
if (health <= 0) { |
||||||
|
setDead(true); |
||||||
|
entity.onKilled(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public int getMaxHealth() |
||||||
|
{ |
||||||
|
return maxHealth; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setMaxHealth(int maxHealth) |
||||||
|
{ |
||||||
|
if (maxHealth <= 0) throw new IllegalValueException("Max health out of allowed range: " + maxHealth); |
||||||
|
this.maxHealth = maxHealth; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean isDead() |
||||||
|
{ |
||||||
|
return dead; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setDead(boolean dead) |
||||||
|
{ |
||||||
|
this.dead = dead; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package mightypork.rogue.world.entity.modules; |
||||||
|
|
||||||
|
import mightypork.util.files.ion.IonBundled; |
||||||
|
import mightypork.util.timing.Updateable; |
||||||
|
|
||||||
|
|
||||||
|
public interface EntityModule extends IonBundled, Updateable { |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -1,9 +1,10 @@ |
|||||||
package mightypork.rogue.world.entity.models; |
package mightypork.rogue.world.entity.modules; |
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.entity.Entity; |
import mightypork.rogue.world.entity.Entity; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public interface EntityMoveListener { |
public interface EntityMoveListener { |
||||||
|
|
||||||
/** |
/** |
@ -0,0 +1,199 @@ |
|||||||
|
package mightypork.rogue.world.entity.modules; |
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import mightypork.rogue.world.Coord; |
||||||
|
import mightypork.rogue.world.entity.Entity; |
||||||
|
import mightypork.rogue.world.entity.PathStep; |
||||||
|
import mightypork.rogue.world.pathfinding.PathFinder; |
||||||
|
import mightypork.rogue.world.pathfinding.PathFindingContext; |
||||||
|
import mightypork.util.files.ion.IonBundle; |
||||||
|
import mightypork.util.math.constraints.vect.VectConst; |
||||||
|
|
||||||
|
|
||||||
|
public class EntityPosModule implements EntityModule { |
||||||
|
|
||||||
|
private final Entity entity; |
||||||
|
|
||||||
|
/** Last pos, will be freed upon finishing move */ |
||||||
|
private final Coord lastPos = new Coord(0, 0); |
||||||
|
private boolean walking = false; |
||||||
|
|
||||||
|
private final Queue<PathStep> path = new LinkedList<>(); |
||||||
|
private final EntityPos entityPos = new EntityPos(); |
||||||
|
private double stepTime = 0.5; |
||||||
|
|
||||||
|
// marks for simple renderers
|
||||||
|
public int lastXDir = 1; |
||||||
|
public int lastYDir = 1; |
||||||
|
|
||||||
|
private final Set<EntityMoveListener> moveListeners = new LinkedHashSet<>(); |
||||||
|
|
||||||
|
|
||||||
|
public EntityPosModule(Entity entity) { |
||||||
|
this.entity = entity; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void save(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
bundle.putSequence("path", path); |
||||||
|
bundle.putBundled("pos", entityPos); |
||||||
|
bundle.put("step_time", stepTime); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void load(IonBundle bundle) throws IOException |
||||||
|
{ |
||||||
|
bundle.loadSequence("path", path); |
||||||
|
bundle.loadBundled("pos", entityPos); |
||||||
|
|
||||||
|
stepTime = bundle.get("step_time", stepTime); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setPosition(Coord coord) |
||||||
|
{ |
||||||
|
entityPos.setTo(coord); |
||||||
|
lastPos.setTo(coord); |
||||||
|
cancelPath(); // discard remaining steps
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* @param delta delta time |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void update(double delta) |
||||||
|
{ |
||||||
|
if (!entityPos.isFinished()) { |
||||||
|
entityPos.update(delta); |
||||||
|
} |
||||||
|
|
||||||
|
if (walking && entityPos.isFinished()) { |
||||||
|
walking = false; |
||||||
|
entity.getLevel().freeTile(lastPos); |
||||||
|
|
||||||
|
for (final EntityMoveListener l : moveListeners) { |
||||||
|
l.onStepFinished(entity); |
||||||
|
} |
||||||
|
|
||||||
|
if (path.isEmpty()) { |
||||||
|
for (final EntityMoveListener l : moveListeners) { |
||||||
|
l.onPathFinished(entity); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!walking && !path.isEmpty()) { |
||||||
|
|
||||||
|
walking = true; |
||||||
|
|
||||||
|
final PathStep step = path.poll(); |
||||||
|
|
||||||
|
final Coord planned = entityPos.getCoord().add(step.toCoord()); |
||||||
|
|
||||||
|
if (!entity.getLevel().isWalkable(planned)) { |
||||||
|
cancelPath(); |
||||||
|
|
||||||
|
for (final EntityMoveListener l : moveListeners) { |
||||||
|
l.onPathInterrupted(entity); |
||||||
|
} |
||||||
|
|
||||||
|
walking = false; |
||||||
|
} else { |
||||||
|
|
||||||
|
// tmp for renderer
|
||||||
|
if (step.x != 0) this.lastXDir = step.x; |
||||||
|
if (step.y != 0) this.lastYDir = step.y; |
||||||
|
|
||||||
|
lastPos.setTo(entityPos.getCoord()); |
||||||
|
entityPos.walk(step, stepTime); |
||||||
|
entity.getLevel().occupyTile(planned); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean isPathFinished() |
||||||
|
{ |
||||||
|
return entityPos.isFinished() && path.isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void addStep(PathStep step) |
||||||
|
{ |
||||||
|
path.add(step); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void cancelPath() |
||||||
|
{ |
||||||
|
path.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public boolean navigateTo(Coord target) |
||||||
|
{ |
||||||
|
if (target.equals(getCoord())) return true; |
||||||
|
|
||||||
|
PathFindingContext pfc = entity.getPathfindingContext(); |
||||||
|
final List<PathStep> path = PathFinder.findPathRelative(pfc, entityPos.getCoord(), target); |
||||||
|
|
||||||
|
if (path == null) return false; |
||||||
|
|
||||||
|
this.cancelPath(); |
||||||
|
this.addSteps(path); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Add a move listener. If already present, do nothing. |
||||||
|
*/ |
||||||
|
public void addMoveListener(EntityMoveListener listener) |
||||||
|
{ |
||||||
|
moveListeners.add(listener); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void addSteps(List<PathStep> path) |
||||||
|
{ |
||||||
|
path.addAll(path); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Coord getCoord() |
||||||
|
{ |
||||||
|
return entityPos.getCoord(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public double getStepTime() |
||||||
|
{ |
||||||
|
return stepTime; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public void setStepTime(double stepTime) |
||||||
|
{ |
||||||
|
this.stepTime = stepTime; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public double getProgress() |
||||||
|
{ |
||||||
|
return entityPos.getProgress(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public VectConst getVisualPos() |
||||||
|
{ |
||||||
|
return entityPos.getVisualPos(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,16 +0,0 @@ |
|||||||
package mightypork.rogue.world.entity.renderers; |
|
||||||
|
|
||||||
|
|
||||||
import mightypork.rogue.world.entity.Entity; |
|
||||||
import mightypork.rogue.world.level.render.MapRenderContext; |
|
||||||
|
|
||||||
|
|
||||||
public class NullEntityRenderer extends EntityRenderer { |
|
||||||
|
|
||||||
@Override |
|
||||||
public void render(Entity entity, MapRenderContext context) |
|
||||||
{ |
|
||||||
// hell no
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,29 @@ |
|||||||
|
package mightypork.util.error; |
||||||
|
|
||||||
|
|
||||||
|
public class IllegalValueException extends RuntimeException { |
||||||
|
|
||||||
|
public IllegalValueException() { |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public IllegalValueException(String message) { |
||||||
|
super(message); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public IllegalValueException(Throwable cause) { |
||||||
|
super(cause); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public IllegalValueException(String message, Throwable cause) { |
||||||
|
super(message, cause); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public IllegalValueException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { |
||||||
|
super(message, cause, enableSuppression, writableStackTrace); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,29 +0,0 @@ |
|||||||
package mightypork.util.error; |
|
||||||
|
|
||||||
|
|
||||||
public class YouFuckedUpException extends RuntimeException { |
|
||||||
|
|
||||||
public YouFuckedUpException() |
|
||||||
{ |
|
||||||
super(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public YouFuckedUpException(String message, Throwable cause) |
|
||||||
{ |
|
||||||
super(message, cause); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public YouFuckedUpException(String message) |
|
||||||
{ |
|
||||||
super(message); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public YouFuckedUpException(Throwable cause) |
|
||||||
{ |
|
||||||
super(cause); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
Loading…
Reference in new issue