From 1121c31509d6dcbd19b15985a8513894871cfe59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 9 May 2014 22:23:42 +0200 Subject: [PATCH] +PK event, + graphics for stairs --- res/img/dudes.xcf | Bin 9195 -> 10500 bytes res/img/tiles16.png | Bin 9904 -> 8928 bytes res/img/tiles16.xcf | Bin 20916 -> 22740 bytes .../gamecore/eventbus/EventBus.java | 9 +- .../gui/components/painters/ImagePainter.java | 2 +- .../util/math/constraints/rect/Rect.java | 7 +- src/mightypork/rogue/App.java | 1 - .../rogue/screens/game/HeartBar.java | 10 +- .../rogue/screens/game/HudLayer.java | 4 +- .../rogue/screens/menu/MenuLayer.java | 7 +- src/mightypork/rogue/world/PlayerControl.java | 8 +- src/mightypork/rogue/world/World.java | 45 ++++++- src/mightypork/rogue/world/WorldCreator.java | 13 +- src/mightypork/rogue/world/WorldProvider.java | 5 +- src/mightypork/rogue/world/WorldRenderer.java | 6 +- src/mightypork/rogue/world/entity/Entity.java | 30 ++++- .../world/entity/entities/MonsterAi.java | 4 +- .../world/entity/entities/PlayerEntity.java | 28 ++-- .../world/entity/entities/RatEntity.java | 4 +- .../entity/modules/EntityModuleHealth.java | 2 +- .../{renderers => render}/EntityRenderer.java | 2 +- .../EntityRendererMobLR.java | 16 +-- .../rogue/world/events/PlayerKilledEvent.java | 14 ++ .../world/events/PlayerKilledListener.java | 7 + .../rogue/world/gen/LevelGenerator.java | 19 +-- .../rogue/world/gen/ScratchMap.java | 4 +- src/mightypork/rogue/world/gui/MapView.java | 13 +- src/mightypork/rogue/world/gui/Minimap.java | 4 +- .../rogue/world/gui/interaction/MIPMouse.java | 2 +- src/mightypork/rogue/world/item/Item.java | 6 +- .../rogue/world/item/ItemModel.java | 2 +- .../rogue/world/item/items/ItemMeat.java | 11 +- .../{rendr => render}/QuadItemRenderer.java | 8 +- src/mightypork/rogue/world/level/Level.java | 116 +++++++++------- .../rogue/world/level/LevelAccess.java | 109 +++++++++++++++ .../rogue/world/level/LevelReadAccess.java | 127 ++++++++++++++++++ .../rogue/world/level/MapAccess.java | 47 ------- .../level/render/EntityRenderContext.java | 4 +- .../world/level/render/MapRenderContext.java | 10 +- .../world/level/render/TileRenderContext.java | 4 +- .../rogue/world/tile/DroppedItemRenderer.java | 5 +- src/mightypork/rogue/world/tile/Tile.java | 34 ++++- .../rogue/world/tile/TileRenderer.java | 2 +- .../BasicTileRenderer.java | 2 +- .../DoorTileRenderer.java | 2 +- .../NullTileRenderer.java | 2 +- .../rogue/world/tile/tiles/NullTile.java | 3 +- .../rogue/world/tile/tiles/TileBaseDoor.java | 2 +- .../rogue/world/tile/tiles/TileBaseFloor.java | 2 +- .../world/tile/tiles/TileBasePassage.java | 2 +- .../world/tile/tiles/TileBaseSecretDoor.java | 3 +- .../rogue/world/tile/tiles/TileBaseWall.java | 2 +- .../rogue/world/tile/tiles/TileWithItems.java | 6 +- 53 files changed, 541 insertions(+), 236 deletions(-) rename src/mightypork/rogue/world/entity/{renderers => render}/EntityRenderer.java (77%) rename src/mightypork/rogue/world/entity/{renderers => render}/EntityRendererMobLR.java (75%) create mode 100644 src/mightypork/rogue/world/events/PlayerKilledEvent.java create mode 100644 src/mightypork/rogue/world/events/PlayerKilledListener.java rename src/mightypork/rogue/world/item/{rendr => render}/QuadItemRenderer.java (79%) create mode 100644 src/mightypork/rogue/world/level/LevelAccess.java create mode 100644 src/mightypork/rogue/world/level/LevelReadAccess.java delete mode 100644 src/mightypork/rogue/world/level/MapAccess.java rename src/mightypork/rogue/world/tile/{renderers => render}/BasicTileRenderer.java (93%) rename src/mightypork/rogue/world/tile/{renderers => render}/DoorTileRenderer.java (97%) rename src/mightypork/rogue/world/tile/{renderers => render}/NullTileRenderer.java (92%) diff --git a/res/img/dudes.xcf b/res/img/dudes.xcf index 62218e1c6f99150a4b91026383529465215cbb58..1937c0d4eacd965ae8d77617328f13d1af14945b 100644 GIT binary patch delta 1268 zcmcJPL1+^}6ozM;CL4=|3Q9H5W=KUNvSKR)ETVXj;z0-&yvin-Y(_S_ad)E09^9=I zyo!5N^eiYMy(oeQy(pr1DT*iYROm%Kh$q*7b~mO)svh*gxAW$I@6EoMOm=-?`Rw)M z%GHM_n##eagk+})$-N__xSf#wt7K>t?gUUk#`D70N>Ay8ONB{)2}%Ksf)TI_NvAPR z7`)xl1nUXS)ceeVB&!vzEHzs4ywZWOa?`fpR~_cMbW!MzpmSAvhBbJ%JqT+q_ZXe6 z96B6ZS`@2V*IML)c6g7OE&{qGxNdUYrIwAUsar-@HyAC|U9BF!uco_9YjB6v1-C6~ z3I}<0+q4~;44PxqZYV|nLe~|%*{3FJ3Z&HRp4PS-j5hJEMk-w94bh@U=7ycgv=-w= zOKfUb%3W(?r!9_FEra$M`j$tNTINmS_=LidCysN?d`iTDmiZ#*=gD}q11K9%NjBOB zRHCNiR`c;F6X$KNKRH;{|3AzA^{Rfdi$V8)=r)?fUiN@r$K;GI$^#2ha0|)UImZ>3 zbUHJO3CRI@e;z@{Gl61jv~)jD#YKi;-3}7J>y;u8V~Q4iurui_VmW{`{Ak*R@7^9 zbFd%<8&~h(%ON#sL4t}yn7Ts9^hfY{<@QK+_k8ggV$y;X)D}PBi}O;7uppuMm5_Z4 u(C>oBG7vtPDy>9?X1-EhmUCE;f;Gywz&9zvf`sxTXfMEfuom8&sr~>=&@(Rp delta 234 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 Cf7dhs literal 9904 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

j=IbEwYqlsRfo=!p` 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 oYNn`E>|rgwU3`k096>fQEix!u!i$5y#<+pgmB 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 diff --git a/src/mightypork/gamecore/eventbus/EventBus.java b/src/mightypork/gamecore/eventbus/EventBus.java index ae95174..57b5497 100644 --- a/src/mightypork/gamecore/eventbus/EventBus.java +++ b/src/mightypork/gamecore/eventbus/EventBus.java @@ -22,7 +22,7 @@ import mightypork.gamecore.logging.Log; * * @author MightyPork */ -final public class EventBus implements Destroyable { +final public class EventBus implements Destroyable, BusAccess { /** * Queued event holder @@ -384,4 +384,11 @@ final public class EventBus implements Destroyable { return true; } + + @Override + public EventBus getEventBus() + { + return this; // just for compatibility use-case + } + } diff --git a/src/mightypork/gamecore/gui/components/painters/ImagePainter.java b/src/mightypork/gamecore/gui/components/painters/ImagePainter.java index 2195adf..d676fd8 100644 --- a/src/mightypork/gamecore/gui/components/painters/ImagePainter.java +++ b/src/mightypork/gamecore/gui/components/painters/ImagePainter.java @@ -17,7 +17,7 @@ public class ImagePainter extends VisualComponent { private final TxQuad txQuad; private boolean aspratio = false; - private Rect asprRect; + private final Rect asprRect; /** diff --git a/src/mightypork/gamecore/util/math/constraints/rect/Rect.java b/src/mightypork/gamecore/util/math/constraints/rect/Rect.java index 8e2d400..e05b351 100644 --- a/src/mightypork/gamecore/util/math/constraints/rect/Rect.java +++ b/src/mightypork/gamecore/util/math/constraints/rect/Rect.java @@ -914,12 +914,13 @@ public abstract class Rect implements RectBound, Digestable { return p_edge_b != null ? p_edge_b : (p_edge_b = bottomLeft().expand(Num.ZERO, width(), Num.ZERO, Num.ZERO)); } - + public Rect axisV() { return p_axis_v != null ? p_axis_v : (p_axis_v = topCenter().expand(Num.ZERO, Num.ZERO, Num.ZERO, height())); } - + + public Rect axisH() { return p_axis_h != null ? p_axis_h : (p_axis_h = centerLeft().expand(Num.ZERO, width(), Num.ZERO, Num.ZERO)); @@ -1058,6 +1059,6 @@ public abstract class Rect implements RectBound, Digestable { // overflow || intersect return ((rw < rx || rw > tx) && (rh < ry || rh > ty) && (tw < tx || tw > rx) && (th < ty || th > ry)); } - + } diff --git a/src/mightypork/rogue/App.java b/src/mightypork/rogue/App.java index ff9109c..7502336 100644 --- a/src/mightypork/rogue/App.java +++ b/src/mightypork/rogue/App.java @@ -25,7 +25,6 @@ import mightypork.rogue.screens.game.ScreenGame; import mightypork.rogue.screens.menu.ScreenMainMenu; import mightypork.rogue.screens.test_bouncyboxes.ScreenTestBouncy; import mightypork.rogue.world.WorldProvider; -import mightypork.rogue.world.item.Item; import mightypork.rogue.world.level.Level; diff --git a/src/mightypork/rogue/screens/game/HeartBar.java b/src/mightypork/rogue/screens/game/HeartBar.java index eac6229..348bffa 100644 --- a/src/mightypork/rogue/screens/game/HeartBar.java +++ b/src/mightypork/rogue/screens/game/HeartBar.java @@ -15,13 +15,13 @@ public class HeartBar extends VisualComponent { private final TxQuad img_on; private final TxQuad img_off; private final TxQuad img_half; - private Num total; - private Num active; + private final Num total; + private final Num active; NumVar index = new NumVar(0); Rect heart; - + /** * @param total * @param active @@ -63,9 +63,9 @@ public class HeartBar extends VisualComponent { for (int i = 0; i < total.value(); i++) { index.setTo(i); - double rem = active.value()-i; + final double rem = active.value() - i; - Render.quadTextured(heart, (rem>0.6 ? img_on : rem>0.25 ? img_half: img_off)); + Render.quadTextured(heart, (rem > 0.6 ? img_on : rem > 0.25 ? img_half : img_off)); } } diff --git a/src/mightypork/rogue/screens/game/HudLayer.java b/src/mightypork/rogue/screens/game/HudLayer.java index e4f120c..42a4be0 100644 --- a/src/mightypork/rogue/screens/game/HudLayer.java +++ b/src/mightypork/rogue/screens/game/HudLayer.java @@ -17,7 +17,7 @@ import mightypork.rogue.world.gui.Minimap; public class HudLayer extends ScreenLayer { - private Num playerHealthTotal = new Num() { + private final Num playerHealthTotal = new Num() { @Override public double value() @@ -26,7 +26,7 @@ public class HudLayer extends ScreenLayer { } }; - private Num playerHealthActive = new Num() { + private final Num playerHealthActive = new Num() { @Override public double value() diff --git a/src/mightypork/rogue/screens/menu/MenuLayer.java b/src/mightypork/rogue/screens/menu/MenuLayer.java index 2ad5c8b..a1fc611 100644 --- a/src/mightypork/rogue/screens/menu/MenuLayer.java +++ b/src/mightypork/rogue/screens/menu/MenuLayer.java @@ -2,21 +2,16 @@ package mightypork.rogue.screens.menu; import mightypork.gamecore.gui.Action; -import mightypork.gamecore.gui.AlignX; import mightypork.gamecore.gui.components.layout.GridLayout; import mightypork.gamecore.gui.components.painters.ImagePainter; import mightypork.gamecore.gui.components.painters.QuadPainter; -import mightypork.gamecore.gui.components.painters.TextPainter; import mightypork.gamecore.gui.events.CrossfadeRequest; import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.ScreenLayer; import mightypork.gamecore.util.math.color.Color; -import mightypork.gamecore.util.math.color.pal.COMMODORE; import mightypork.gamecore.util.math.color.pal.PAL16; -import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.num.Num; import mightypork.gamecore.util.math.constraints.rect.Rect; -import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.rogue.Res; @@ -44,7 +39,7 @@ class MenuLayer extends ScreenLayer { root.add(layout); int r = 0; - ImagePainter ip = new ImagePainter(Res.getTxQuad("logo")); + final ImagePainter ip = new ImagePainter(Res.getTxQuad("logo")); ip.keepAspectRatio(); layout.put(ip, r, 0, 5, 1); r += 6; diff --git a/src/mightypork/rogue/world/PlayerControl.java b/src/mightypork/rogue/world/PlayerControl.java index be1603e..e0607d7 100644 --- a/src/mightypork/rogue/world/PlayerControl.java +++ b/src/mightypork/rogue/world/PlayerControl.java @@ -8,7 +8,7 @@ import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Step; import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.modules.EntityMoveListener; -import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.level.LevelAccess; public abstract class PlayerControl { @@ -35,7 +35,7 @@ public abstract class PlayerControl { return newWorld; - }; + } public Entity getPlayerEntity() @@ -86,7 +86,7 @@ public abstract class PlayerControl { } - public Level getLevel() + public LevelAccess getLevel() { return getWorld().getCurrentLevel(); } @@ -114,7 +114,7 @@ public abstract class PlayerControl { { if (pos.dist(getCoord()) > 8) return false; // too far - return getLevel().getTile(pos).onClick(getWorld()); + return getLevel().getTile(pos).onClick(); } diff --git a/src/mightypork/rogue/world/World.java b/src/mightypork/rogue/world/World.java index e82fbbc..fdbea3f 100644 --- a/src/mightypork/rogue/world/World.java +++ b/src/mightypork/rogue/world/World.java @@ -4,12 +4,15 @@ package mightypork.rogue.world; import java.io.IOException; import java.util.ArrayList; +import mightypork.gamecore.eventbus.BusAccess; +import mightypork.gamecore.eventbus.EventBus; import mightypork.gamecore.eventbus.events.Updateable; 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.level.Level; +import mightypork.rogue.world.level.LevelAccess; /** @@ -17,13 +20,15 @@ import mightypork.rogue.world.level.Level; * * @author MightyPork */ -public class World implements IonObjBundled, Updateable { +public class World implements BusAccess, IonObjBundled, Updateable { private final ArrayList levels = new ArrayList<>(); private final PlayerInfo playerInfo = new PlayerInfo(); private Entity playerEntity; + private BusAccess bus; + /** World seed */ private long seed; @@ -34,8 +39,8 @@ public class World implements IonObjBundled, Updateable { @Override public void load(IonBundle in) throws IOException { - seed = in.get("seed", 0L); - eid = in.get("next_eid", 0); + seed = in.get("seed", seed); + eid = in.get("next_eid", eid); in.loadSequence("levels", levels); // join levels to world @@ -46,7 +51,9 @@ public class World implements IonObjBundled, Updateable { in.loadBundled("player", playerInfo); playerEntity = levels.get(playerInfo.getLevel()).getEntity(playerInfo.getEID()); - if (playerEntity == null) throw new RuntimeException("Player entity not found in the world."); + if (playerEntity == null) { + throw new RuntimeException("Player entity not found in the world."); + } } @@ -104,16 +111,21 @@ public class World implements IonObjBundled, Updateable { // make entity final int playerEid = getNewEID(); + final Level floor = levels.get(level); + if (floor == null) { + throw new IndexOutOfBoundsException("No such level: " + level); + } + playerEntity = Entities.PLAYER.createEntity(playerEid); - playerEntity.setCoord(levels.get(level).getEnterPoint()); - levels.get(level).addEntity(playerEntity); + floor.addEntity(playerEntity, floor.getEnterPoint()); + floor.explore(playerEntity.getCoord()); playerInfo.setLevel(level); playerInfo.setEID(playerEid); } - public Level getCurrentLevel() + public LevelAccess getCurrentLevel() { return levels.get(playerInfo.getLevel()); } @@ -124,4 +136,23 @@ public class World implements IonObjBundled, Updateable { return playerEntity; } + + /** + * Attach to an event bus + * + * @param bus event bus + */ + public void assignBus(BusAccess bus) + { + this.bus = bus; + } + + + @Override + public EventBus getEventBus() + { + if (bus == null) throw new NullPointerException("World doesn't have a bus assigned."); + return bus.getEventBus(); + } + } diff --git a/src/mightypork/rogue/world/WorldCreator.java b/src/mightypork/rogue/world/WorldCreator.java index 4ffa354..9f405d3 100644 --- a/src/mightypork/rogue/world/WorldCreator.java +++ b/src/mightypork/rogue/world/WorldCreator.java @@ -19,14 +19,11 @@ public class WorldCreator { final World w = new World(); w.setSeed(seed); - - Level l; - - // TODO real algorithm - - // first level - l = LevelGenerator.build(w, rand.nextLong(), 1, LevelGenerator.DUNGEON_THEME); // - w.addLevel(l); + + for(int i=0; i<7; i++) { + Level l = LevelGenerator.build(w, rand.nextLong(), i, LevelGenerator.DUNGEON_THEME); + w.addLevel(l); + } w.createPlayer(0); diff --git a/src/mightypork/rogue/world/WorldProvider.java b/src/mightypork/rogue/world/WorldProvider.java index e4b8239..751563c 100644 --- a/src/mightypork/rogue/world/WorldProvider.java +++ b/src/mightypork/rogue/world/WorldProvider.java @@ -8,7 +8,7 @@ import mightypork.gamecore.eventbus.BusAccess; import mightypork.gamecore.eventbus.clients.RootBusNode; import mightypork.gamecore.util.ion.Ion; import mightypork.rogue.world.entity.Entity; -import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.level.LevelAccess; public class WorldProvider extends RootBusNode { @@ -67,6 +67,7 @@ public class WorldProvider extends RootBusNode { if (world != null) removeChildClient(world); world = newWorld; + world.assignBus(this); // connect to bus (for event dispatching) addChildClient(world); } @@ -84,7 +85,7 @@ public class WorldProvider extends RootBusNode { } - public Level getCurrentLevel() + public LevelAccess getCurrentLevel() { return getWorld().getCurrentLevel(); } diff --git a/src/mightypork/rogue/world/WorldRenderer.java b/src/mightypork/rogue/world/WorldRenderer.java index 35779d6..af53bf6 100644 --- a/src/mightypork/rogue/world/WorldRenderer.java +++ b/src/mightypork/rogue/world/WorldRenderer.java @@ -12,7 +12,7 @@ import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.VectConst; import mightypork.rogue.Res; import mightypork.rogue.world.entity.Entity; -import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.level.LevelAccess; import mightypork.rogue.world.level.render.TileRenderContext; @@ -29,7 +29,7 @@ public class WorldRenderer extends RectProxy { // can be changed private RectConst mapRect; - private Level activeLevel; + private LevelAccess activeLevel; private final Rect rightShadow; private final Rect leftShadow; @@ -57,7 +57,7 @@ public class WorldRenderer extends RectProxy { private void prepareRenderContextIfNeeded() { - final Level level = WorldProvider.get().getCurrentLevel(); + final LevelAccess level = WorldProvider.get().getCurrentLevel(); if (activeLevel == level) return; diff --git a/src/mightypork/rogue/world/entity/Entity.java b/src/mightypork/rogue/world/entity/Entity.java index 1428192..f00c966 100644 --- a/src/mightypork/rogue/world/entity/Entity.java +++ b/src/mightypork/rogue/world/entity/Entity.java @@ -17,8 +17,8 @@ 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; -import mightypork.rogue.world.entity.renderers.EntityRenderer; -import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.entity.render.EntityRenderer; +import mightypork.rogue.world.level.LevelAccess; import mightypork.rogue.world.level.render.MapRenderContext; @@ -29,7 +29,7 @@ import mightypork.rogue.world.level.render.MapRenderContext; */ public abstract class Entity implements IonObjBundled, Updateable { - private Level level; + private LevelAccess level; private final EntityModel model; protected final Random rand = new Random(); @@ -120,7 +120,7 @@ public abstract class Entity implements IonObjBundled, Updateable { } - public void setLevel(Level level) + public void setLevel(LevelAccess level) { if (level != null) level.freeTile(getCoord()); @@ -130,7 +130,7 @@ public abstract class Entity implements IonObjBundled, Updateable { } - public final Level getLevel() + public final LevelAccess getLevel() { return level; } @@ -225,6 +225,15 @@ public abstract class Entity implements IonObjBundled, Updateable { } + /** + * Called after the corpse has been cleaned from level. + */ + @DefaultImpl + public void onCorpseRemoved() + { + } + + /** * Receive damage from an attacker.
* The entity can decide whether to dodge, reduce damage etc. @@ -239,9 +248,20 @@ public abstract class Entity implements IonObjBundled, Updateable { } + /** + * Set how long after being killed is the corpse elligible for removal + * + * @param despawnDelay (secs) + */ public void setDespawnDelay(double despawnDelay) { this.despawnDelay = despawnDelay; } + + public double getDespawnDelay() + { + return despawnDelay; + } + } diff --git a/src/mightypork/rogue/world/entity/entities/MonsterAi.java b/src/mightypork/rogue/world/entity/entities/MonsterAi.java index 15411fd..e6b90ab 100644 --- a/src/mightypork/rogue/world/entity/entities/MonsterAi.java +++ b/src/mightypork/rogue/world/entity/entities/MonsterAi.java @@ -179,7 +179,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener { if (chasing && !entity.pos.isMoving()) { final Entity prey = getPreyEntity(); - if(prey==null) { + if (prey == null) { // prey killed and cleaned from level stopChasing(); return; @@ -219,7 +219,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener { } startChasing(prey); - } + } } diff --git a/src/mightypork/rogue/world/entity/entities/PlayerEntity.java b/src/mightypork/rogue/world/entity/entities/PlayerEntity.java index 3d2b9ef..aa7c725 100644 --- a/src/mightypork/rogue/world/entity/entities/PlayerEntity.java +++ b/src/mightypork/rogue/world/entity/entities/PlayerEntity.java @@ -9,9 +9,9 @@ import mightypork.rogue.world.entity.EntityModule; import mightypork.rogue.world.entity.EntityPathFinder; import mightypork.rogue.world.entity.EntityType; import mightypork.rogue.world.entity.modules.EntityMoveListener; -import mightypork.rogue.world.entity.renderers.EntityRenderer; -import mightypork.rogue.world.entity.renderers.EntityRendererMobLR; -import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.entity.render.EntityRenderer; +import mightypork.rogue.world.entity.render.EntityRendererMobLR; +import mightypork.rogue.world.events.PlayerKilledEvent; public class PlayerEntity extends Entity { @@ -82,7 +82,7 @@ public class PlayerEntity extends Entity { public int getCost(Coord from, Coord to) { if (!getLevel().getTile(pos.getCoord()).isExplored()) { - return 1000; + return 1000; // avoid unexplored, but allow them if there's no other way } return super.getCost(from, to); @@ -94,14 +94,6 @@ public class PlayerEntity extends Entity { } - @Override - public void setLevel(Level level) - { - super.setLevel(level); - ai.onStepFinished(); // explore start area - } - - @Override protected EntityRenderer getRenderer() { @@ -119,9 +111,11 @@ public class PlayerEntity extends Entity { return EntityType.PLAYER; } -// @Override -// public void receiveAttack(Entity attacker, int attackStrength) -// { -// // FIXME ignore attack -// } + + @Override + public void onKilled() + { + // send kill event to listeners (GUI?) + getWorld().getEventBus().sendDelayed(new PlayerKilledEvent(), getDespawnDelay()); + } } diff --git a/src/mightypork/rogue/world/entity/entities/RatEntity.java b/src/mightypork/rogue/world/entity/entities/RatEntity.java index dabbf1f..7eb6058 100644 --- a/src/mightypork/rogue/world/entity/entities/RatEntity.java +++ b/src/mightypork/rogue/world/entity/entities/RatEntity.java @@ -6,8 +6,8 @@ import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.EntityModel; import mightypork.rogue.world.entity.EntityPathFinder; import mightypork.rogue.world.entity.EntityType; -import mightypork.rogue.world.entity.renderers.EntityRenderer; -import mightypork.rogue.world.entity.renderers.EntityRendererMobLR; +import mightypork.rogue.world.entity.render.EntityRenderer; +import mightypork.rogue.world.entity.render.EntityRendererMobLR; public class RatEntity extends Entity { diff --git a/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java b/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java index 59f5570..6c10706 100644 --- a/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java +++ b/src/mightypork/rogue/world/entity/modules/EntityModuleHealth.java @@ -108,7 +108,7 @@ public class EntityModuleHealth extends EntityModule { @Override public void update(double delta) { - if(timeSinceLastDamage < 3600) timeSinceLastDamage += delta; + if (timeSinceLastDamage < 3600) timeSinceLastDamage += delta; } diff --git a/src/mightypork/rogue/world/entity/renderers/EntityRenderer.java b/src/mightypork/rogue/world/entity/render/EntityRenderer.java similarity index 77% rename from src/mightypork/rogue/world/entity/renderers/EntityRenderer.java rename to src/mightypork/rogue/world/entity/render/EntityRenderer.java index b7aeade..c35243b 100644 --- a/src/mightypork/rogue/world/entity/renderers/EntityRenderer.java +++ b/src/mightypork/rogue/world/entity/render/EntityRenderer.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world.entity.renderers; +package mightypork.rogue.world.entity.render; import mightypork.rogue.world.level.render.MapRenderContext; diff --git a/src/mightypork/rogue/world/entity/renderers/EntityRendererMobLR.java b/src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java similarity index 75% rename from src/mightypork/rogue/world/entity/renderers/EntityRendererMobLR.java rename to src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java index 8ed3aa5..0ebd9ba 100644 --- a/src/mightypork/rogue/world/entity/renderers/EntityRendererMobLR.java +++ b/src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java @@ -1,16 +1,12 @@ -package mightypork.rogue.world.entity.renderers; +package mightypork.rogue.world.entity.render; import mightypork.gamecore.render.Render; import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.resources.textures.TxSheet; import mightypork.gamecore.util.math.Calc; -import mightypork.gamecore.util.math.Easing; import mightypork.gamecore.util.math.color.Color; -import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.num.Num; -import mightypork.gamecore.util.math.constraints.num.NumConst; -import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated; import mightypork.gamecore.util.math.constraints.num.mutable.NumVar; import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.vect.Vect; @@ -31,9 +27,9 @@ public class EntityRendererMobLR extends EntityRenderer { protected final Entity entity; - private NumVar animRedVar = Num.makeVar(0); + private final NumVar animRedVar = Num.makeVar(0); - private Color hue = Color.rgb(Num.ONE, animRedVar, animRedVar); + private final Color hue = Color.rgb(Num.ONE, animRedVar, animRedVar); public EntityRendererMobLR(Entity entity, String sheetKey) @@ -46,7 +42,7 @@ public class EntityRendererMobLR extends EntityRenderer { @Override public void render(MapRenderContext context) { - double hurtTime = entity.health.getTimeSinceLastDamage(); + final double hurtTime = entity.health.getTimeSinceLastDamage(); TxQuad q = sheet.getQuad(Calc.frag(entity.pos.getProgress())); @@ -56,7 +52,7 @@ public class EntityRendererMobLR extends EntityRenderer { final double w = tileRect.width().value(); final Vect visualPos = entity.pos.getVisualPos(); - double hurtOffset = (1 - Calc.clamp(hurtTime / 0.1, 0, 1)) * (entity.isDead() ? 0.3 : 0.05); + final double hurtOffset = (1 - Calc.clamp(hurtTime / 0.1, 0, 1)) * (entity.isDead() ? 0.3 : 0.05); Rect spriteRect = Rect.make(visualPos.x() * w, (visualPos.y() - hurtOffset) * w, w, w); @@ -72,7 +68,7 @@ public class EntityRendererMobLR extends EntityRenderer { Render.rotateZ(Calc.clamp(hurtTime / 0.3, 0, 1) * 90); } - double hw = spriteRect.width().half().value(); + final double hw = spriteRect.width().half().value(); Render.quadTextured(Vect.ZERO.expand(hw, hw, hw, hw), q, hue.withAlpha(entity.isDead() ? 1 - hurtTime / 3 : 1)); Render.popMatrix(); diff --git a/src/mightypork/rogue/world/events/PlayerKilledEvent.java b/src/mightypork/rogue/world/events/PlayerKilledEvent.java new file mode 100644 index 0000000..12ae850 --- /dev/null +++ b/src/mightypork/rogue/world/events/PlayerKilledEvent.java @@ -0,0 +1,14 @@ +package mightypork.rogue.world.events; + + +import mightypork.gamecore.eventbus.BusEvent; + + +public class PlayerKilledEvent extends BusEvent { + + @Override + protected void handleBy(PlayerKilledListener handler) + { + handler.onPlayerKilled(); + } +} diff --git a/src/mightypork/rogue/world/events/PlayerKilledListener.java b/src/mightypork/rogue/world/events/PlayerKilledListener.java new file mode 100644 index 0000000..226e445 --- /dev/null +++ b/src/mightypork/rogue/world/events/PlayerKilledListener.java @@ -0,0 +1,7 @@ +package mightypork.rogue.world.events; + + +public interface PlayerKilledListener { + + void onPlayerKilled(); +} diff --git a/src/mightypork/rogue/world/gen/LevelGenerator.java b/src/mightypork/rogue/world/gen/LevelGenerator.java index c88c790..22f1960 100644 --- a/src/mightypork/rogue/world/gen/LevelGenerator.java +++ b/src/mightypork/rogue/world/gen/LevelGenerator.java @@ -3,6 +3,7 @@ package mightypork.rogue.world.gen; import java.util.Random; +import mightypork.gamecore.logging.Log; import mightypork.gamecore.util.math.algo.Coord; import mightypork.rogue.world.World; import mightypork.rogue.world.entity.Entities; @@ -22,6 +23,8 @@ public class LevelGenerator { public static Level build(World world, long seed, int complexity, MapTheme theme) { + Log.f3("Generating level of complexity: "+complexity); + final Random rand = new Random(seed + 13); final int max_size = 128; @@ -31,7 +34,7 @@ public class LevelGenerator { // start map.addRoom(Rooms.BASIC); - for (int i = 0; i < 2 + complexity / 2 + rand.nextInt((int) (1 + complexity * 0.3)); i++) { + for (int i = 0; i < 1 + complexity / 2 + rand.nextInt((int) (1 + complexity * 0.3)); i++) { map.addRoom(Rooms.BASIC); if (rand.nextInt(7) > 0) map.addRoom(Rooms.SECRET); if (rand.nextInt(6) > 0) map.addRoom(Rooms.DEAD_END); @@ -48,8 +51,8 @@ public class LevelGenerator { // spawn rats final Coord pos = Coord.make(0, 0); - for (int i = 0; i < 4+complexity + rand.nextInt(1+complexity); i++) { - + for (int i = 0; i < 3 + complexity + rand.nextInt(1 + complexity); i++) { + final Entity e = Entities.RAT.createEntity(world); for (int j = 0; j < 20; j++) { @@ -59,17 +62,17 @@ public class LevelGenerator { if (lvl.addEntity(e, pos)) break; } } - - for (int i = 0; i < 4+complexity + rand.nextInt(1+complexity); i++) { + + for (int i = 0; i < 4 + complexity + rand.nextInt(1 + complexity); i++) { - Item meat = Items.MEAT.createItem(); + final Item meat = Items.MEAT.createItem(); for (int j = 0; j < 20; j++) { pos.x = rand.nextInt(lvl.getWidth()); pos.y = rand.nextInt(lvl.getHeight()); - Tile t = lvl.getTile(pos); - if(t.dropItem(meat)) break; + final Tile t = lvl.getTile(pos); + if (t.dropItem(meat)) break; } } diff --git a/src/mightypork/rogue/world/gen/ScratchMap.java b/src/mightypork/rogue/world/gen/ScratchMap.java index e657dae..b1ca65b 100644 --- a/src/mightypork/rogue/world/gen/ScratchMap.java +++ b/src/mightypork/rogue/world/gen/ScratchMap.java @@ -14,7 +14,7 @@ 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.rogue.world.level.Level; +import mightypork.rogue.world.level.LevelAccess; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.Tiles; @@ -410,7 +410,7 @@ public class ScratchMap { } - public void writeToLevel(Level level) + public void writeToLevel(LevelAccess level) { // make sure no walkable are at edges. final Coord c = Coord.make(0, 0); diff --git a/src/mightypork/rogue/world/gui/MapView.java b/src/mightypork/rogue/world/gui/MapView.java index d4dd2d9..2d81064 100644 --- a/src/mightypork/rogue/world/gui/MapView.java +++ b/src/mightypork/rogue/world/gui/MapView.java @@ -35,6 +35,7 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL private final Set plugins = new LinkedHashSet<>(); private final NumAnimated zoom = new NumAnimated(0, Easing.SINE_BOTH); + private boolean zoom_in = true; private final Num tileSize; @@ -112,9 +113,11 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL final int delta = event.getWheelDelta(); if (!zoom.isFinished()) return; if (delta < 0) { - zoom.fadeOut(); - } else { zoom.fadeIn(); + zoom_in = false; + } else { + zoom.fadeOut(); + zoom_in = true; } } } @@ -127,11 +130,13 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL if (p.onKey(this, pc, event.getKey(), event.isDown())) break; } - if (event.getKey() == Keys.Z) { - if (event.isDown()) { + if (event.getKey() == Keys.Z && event.isDown()) { + if (zoom_in) { zoom.fadeIn(); + zoom_in = false; } else { zoom.fadeOut(); + zoom_in = true; } } diff --git a/src/mightypork/rogue/world/gui/Minimap.java b/src/mightypork/rogue/world/gui/Minimap.java index 3a5200f..524956a 100644 --- a/src/mightypork/rogue/world/gui/Minimap.java +++ b/src/mightypork/rogue/world/gui/Minimap.java @@ -14,7 +14,7 @@ import mightypork.gamecore.util.math.constraints.rect.mutable.RectMutable; import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.rogue.world.WorldProvider; import mightypork.rogue.world.entity.Entity; -import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.level.LevelReadAccess; import mightypork.rogue.world.tile.Tile; import org.lwjgl.opengl.GL11; @@ -33,7 +33,7 @@ public class Minimap extends InputComponent implements MouseButtonListener { { Color.pushAlpha(translucency); - final Level lvl = WorldProvider.get().getCurrentLevel(); + final LevelReadAccess lvl = WorldProvider.get().getCurrentLevel(); unit = (int) Math.min(Math.max(2, Math.ceil((height().value() / 2) / (lvl.getHeight() + 2))), 10); final Entity e = WorldProvider.get().getPlayerEntity(); diff --git a/src/mightypork/rogue/world/gui/interaction/MIPMouse.java b/src/mightypork/rogue/world/gui/interaction/MIPMouse.java index 31f4b80..1621f31 100644 --- a/src/mightypork/rogue/world/gui/interaction/MIPMouse.java +++ b/src/mightypork/rogue/world/gui/interaction/MIPMouse.java @@ -39,7 +39,7 @@ public class MIPMouse implements MapInteractionPlugin { final Coord pos = view.toWorldPos(mouse); final Tile t = pc.getLevel().getTile(pos); - if (t.onClick(pc.getWorld())) return true; + if (t.onClick()) return true; if (!down && t.isWalkable()) { if (troToNav(view, pc, mouse)) return true; diff --git a/src/mightypork/rogue/world/item/Item.java b/src/mightypork/rogue/world/item/Item.java index 01e7b4e..2fb41bf 100644 --- a/src/mightypork/rogue/world/item/Item.java +++ b/src/mightypork/rogue/world/item/Item.java @@ -8,7 +8,6 @@ import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonObjBlob; import mightypork.gamecore.util.ion.IonOutput; import mightypork.gamecore.util.math.constraints.rect.Rect; -import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; public abstract class Item implements IonObjBlob { @@ -17,7 +16,8 @@ public abstract class Item implements IonObjBlob { private ItemRenderer renderer; - public Item(ItemModel model) { + public Item(ItemModel model) + { this.model = model; } @@ -29,7 +29,7 @@ public abstract class Item implements IonObjBlob { } renderer.render(rect); - }; + } protected abstract ItemRenderer makeRenderer(); diff --git a/src/mightypork/rogue/world/item/ItemModel.java b/src/mightypork/rogue/world/item/ItemModel.java index c0b385e..b04dd05 100644 --- a/src/mightypork/rogue/world/item/ItemModel.java +++ b/src/mightypork/rogue/world/item/ItemModel.java @@ -6,6 +6,7 @@ import java.io.IOException; import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonOutput; + /** * Item model (builder) * @@ -54,4 +55,3 @@ public final class ItemModel { tile.save(out); } } - diff --git a/src/mightypork/rogue/world/item/items/ItemMeat.java b/src/mightypork/rogue/world/item/items/ItemMeat.java index 3182230..f616305 100644 --- a/src/mightypork/rogue/world/item/items/ItemMeat.java +++ b/src/mightypork/rogue/world/item/items/ItemMeat.java @@ -1,18 +1,21 @@ package mightypork.rogue.world.item.items; + import mightypork.rogue.Res; import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.ItemModel; import mightypork.rogue.world.item.ItemRenderer; -import mightypork.rogue.world.item.rendr.QuadItemRenderer; +import mightypork.rogue.world.item.render.QuadItemRenderer; public class ItemMeat extends Item { - - public ItemMeat(ItemModel model) { + + public ItemMeat(ItemModel model) + { super(model); } - + + @Override protected ItemRenderer makeRenderer() { diff --git a/src/mightypork/rogue/world/item/rendr/QuadItemRenderer.java b/src/mightypork/rogue/world/item/render/QuadItemRenderer.java similarity index 79% rename from src/mightypork/rogue/world/item/rendr/QuadItemRenderer.java rename to src/mightypork/rogue/world/item/render/QuadItemRenderer.java index dd3c96b..2d59ee5 100644 --- a/src/mightypork/rogue/world/item/rendr/QuadItemRenderer.java +++ b/src/mightypork/rogue/world/item/render/QuadItemRenderer.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world.item.rendr; +package mightypork.rogue.world.item.render; import mightypork.gamecore.render.Render; @@ -13,12 +13,14 @@ public class QuadItemRenderer extends ItemRenderer { private final TxQuad txq; - public QuadItemRenderer(TxQuad txq) { + public QuadItemRenderer(TxQuad txq) + { this.txq = txq; } - public QuadItemRenderer(TxSheet txs) { + public QuadItemRenderer(TxSheet txs) + { this.txq = txs.getQuad(0); } diff --git a/src/mightypork/rogue/world/level/Level.java b/src/mightypork/rogue/world/level/Level.java index 87c6daa..1bc9e9d 100644 --- a/src/mightypork/rogue/world/level/Level.java +++ b/src/mightypork/rogue/world/level/Level.java @@ -4,8 +4,8 @@ package mightypork.rogue.world.level; import java.io.IOException; import java.util.*; -import javax.print.attribute.standard.MediaSize.ISO; - +import mightypork.gamecore.eventbus.BusAccess; +import mightypork.gamecore.eventbus.EventBus; import mightypork.gamecore.logging.Log; import mightypork.gamecore.util.ion.IonBundle; import mightypork.gamecore.util.ion.IonInput; @@ -31,7 +31,7 @@ import mightypork.rogue.world.tile.Tiles; * * @author MightyPork */ -public class Level implements MapAccess, IonObjBinary { +public class Level implements BusAccess, LevelAccess, IonObjBinary { public static final int ION_MARK = 53; @@ -70,12 +70,7 @@ public class Level implements MapAccess, IonObjBinary { } - public void fill(short id) - { - fill(Tiles.get(id)); - } - - + @Override public void fill(TileModel model) { for (final Coord c = Coord.zero(); c.x < size.x; c.x++) { @@ -95,18 +90,7 @@ public class Level implements MapAccess, IonObjBinary { } - public final void setTile(Coord pos, TileModel model) - { - setTile(pos, model.createTile()); - } - - - public final void setTile(Coord pos, int tileId) - { - setTile(pos, Tiles.create(tileId)); - } - - + @Override public final void setTile(Coord pos, Tile tile) { if (!pos.isInRange(0, 0, size.x - 1, size.y - 1)) { @@ -115,6 +99,9 @@ public class Level implements MapAccess, IonObjBinary { } tiles[pos.y][pos.x] = tile; + + // assign level (tile logic may need it) + tile.setLevel(this); } @@ -132,6 +119,7 @@ public class Level implements MapAccess, IonObjBinary { } + @Override public void setSeed(long seed) { this.seed = seed; @@ -207,23 +195,24 @@ public class Level implements MapAccess, IonObjBinary { } + @Override public void update(double delta) { // just update them all for (final Coord c = Coord.zero(); c.x < size.x; c.x++) { for (c.y = 0; c.y < size.y; c.y++) { - getTile(c).update(this, delta); + getTile(c).update(delta); } } - List toRemove = new ArrayList<>(); + final List toRemove = new ArrayList<>(); for (final Entity e : entitySet) { e.update(delta); if (e.isDead() && e.canRemoveCorpse()) toRemove.add(e); } - for (Entity e : toRemove) { + for (final Entity e : toRemove) { removeEntity(e); } } @@ -240,37 +229,22 @@ public class Level implements MapAccess, IonObjBinary { } + @Override public Entity getEntity(int eid) { return entityMap.get(eid); } - /** - * Try to add entity at given pos - * - * @param entity the entity - * @param pos pos - * @return true if added (false if void, wall etc) - */ + @Override public boolean addEntity(Entity entity, Coord pos) { final Tile t = getTile(pos); - if (!t.isWalkable() || isOccupied(pos)) return false; - - addEntity(entity); + if (!t.isWalkable() || t.isOccupied()) return false; - entity.setCoord(pos); - - return true; - } - - - public void addEntity(Entity entity) - { if (entityMap.containsKey(entity.getEntityId())) { Log.w("Entity already in level."); - return; + return false; } entityMap.put(entity.getEntityId(), entity); @@ -279,15 +253,21 @@ public class Level implements MapAccess, IonObjBinary { // join to level & world entity.setLevel(this); occupyTile(entity.getCoord()); + + entity.setCoord(pos); + + return true; } + @Override public void removeEntity(Entity entity) { removeEntity(entity.getEntityId()); } + @Override public void removeEntity(int eid) { final Entity removed = entityMap.remove(eid); @@ -296,6 +276,7 @@ public class Level implements MapAccess, IonObjBinary { } + @Override public boolean isWalkable(Coord pos) { final Tile t = getTile(pos); @@ -307,6 +288,7 @@ public class Level implements MapAccess, IonObjBinary { /** * Mark tile as occupied by an entity */ + @Override public void occupyTile(Coord pos) { getTile(pos).setOccupied(true); @@ -316,52 +298,56 @@ public class Level implements MapAccess, IonObjBinary { /** * Mark tile as free (no longet occupied) */ + @Override public void freeTile(Coord pos) { getTile(pos).setOccupied(false); } - /** - * @param pos tile coord - * @return true if something is standing there. - */ + @Override public boolean isOccupied(Coord pos) { return getTile(pos).isOccupied(); } + @Override public Collection getEntities() { return entitySet; } + @Override public void setEnterPoint(Coord pos) { this.enterPoint.setTo(pos); } + @Override public Coord getEnterPoint() { return enterPoint; } + @Override public World getWorld() { return world; } + @Override public void setWorld(World world) { this.world = world; } + @Override public void explore(Coord center) { final Collection filled = new HashSet<>(); @@ -413,6 +399,7 @@ public class Level implements MapAccess, IonObjBinary { }; + @Override public Entity getClosestEntity(Entity self, EntityType type, double radius) { Entity closest = null; @@ -436,8 +423,43 @@ public class Level implements MapAccess, IonObjBinary { } + public void forceFreeTile(Coord pos) + { + if (getTile(pos).isOccupied()) { + final Set toButcher = new HashSet<>(); + for (final Entity e : entitySet) { + if (e.getCoord().equals(pos)) { + toButcher.add(e); + break; + } + } + + for (final Entity e : toButcher) { + removeEntity(e); + freeTile(pos); + } + } + + } + + + @Override public boolean isEntityPresent(Entity entity) { return entitySet.contains(entity); } + + + @Override + public boolean isEntityPresent(int eid) + { + return entityMap.containsKey(eid); + } + + + @Override + public EventBus getEventBus() + { + return world.getEventBus(); + } } diff --git a/src/mightypork/rogue/world/level/LevelAccess.java b/src/mightypork/rogue/world/level/LevelAccess.java new file mode 100644 index 0000000..29dee0d --- /dev/null +++ b/src/mightypork/rogue/world/level/LevelAccess.java @@ -0,0 +1,109 @@ +package mightypork.rogue.world.level; + + +import mightypork.gamecore.eventbus.events.Updateable; +import mightypork.gamecore.util.math.algo.Coord; +import mightypork.rogue.world.World; +import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.tile.Tile; +import mightypork.rogue.world.tile.TileModel; + + +/** + * Level full access + * + * @author MightyPork + */ +public interface LevelAccess extends LevelReadAccess, Updateable { + + + /** + * Mark tile and surrounding area as explored + * + * @param center center the explored tile + */ + public abstract void explore(Coord center); + + + /** + * Assign a world + * + * @param world new world + */ + public abstract void setWorld(World world); + + + /** + * Set level entry point + * + * @param pos pos where the player enters + */ + public abstract void setEnterPoint(Coord pos); + + + /** + * Mark tile as free (entity left) + * + * @param pos tile pos + */ + public abstract void freeTile(Coord pos); + + + /** + * Mark tile as occupied (entity entered) + * + * @param pos tile pos + */ + public abstract void occupyTile(Coord pos); + + + /** + * Remove an entity from the level, if present + * + * @param eid entity id + */ + public abstract void removeEntity(int eid); + + + /** + * Remove an entity from the level, if present + * + * @param entity entity + */ + public abstract void removeEntity(Entity entity); + + + /** + * Set level seed (used for visuals; the seed used for generation) + * + * @param seed seed + */ + public abstract void setSeed(long seed); + + + /** + * Set tile at pos + * + * @param pos tile pos + * @param tile the tile instance to set + */ + public abstract void setTile(Coord pos, Tile tile); + + + /** + * Fill whole map with tile type + * + * @param model tile model + */ + public abstract void fill(TileModel model); + + + /** + * Try to add entity at given pos + * + * @param entity the entity + * @param pos pos + * @return true if added (false if void, wall etc) + */ + public abstract boolean addEntity(Entity entity, Coord pos); +} diff --git a/src/mightypork/rogue/world/level/LevelReadAccess.java b/src/mightypork/rogue/world/level/LevelReadAccess.java new file mode 100644 index 0000000..e9b34ed --- /dev/null +++ b/src/mightypork/rogue/world/level/LevelReadAccess.java @@ -0,0 +1,127 @@ +package mightypork.rogue.world.level; + + +import java.util.Collection; + +import mightypork.gamecore.util.math.algo.Coord; +import mightypork.gamecore.util.math.noise.NoiseGen; +import mightypork.rogue.world.World; +import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.entity.EntityType; +import mightypork.rogue.world.tile.Tile; + + +public interface LevelReadAccess { + + /** + * Ge tile at X,Y + * + * @param pos + * @return tile + */ + Tile getTile(Coord pos); + + + /** + * @return map width in tiles + */ + int getWidth(); + + + /** + * @return map height in tiles + */ + int getHeight(); + + + /** + * @return map seed + */ + long getSeed(); + + + /** + * @return level-specific noise generator + */ + NoiseGen getNoiseGen(); + + + /** + * Check if entity is in the level + * + * @param entity entity + * @return is present + */ + boolean isEntityPresent(Entity entity); + + + /** + * Check if entity is in the level + * + * @param eid entity ID + * @return true if present + */ + boolean isEntityPresent(int eid); + + + /** + * Get entity of type closest to coord + * + * @param self the querying entity - to provide position, and to be excluded + * from the search. + * @param type wanted entity type + * @param radius search radius; -1 for unlimited. + * @return + */ + Entity getClosestEntity(Entity self, EntityType type, double radius); + + + /** + * Get the level's world + * + * @return world + */ + World getWorld(); + + + /** + * Get location where the player enters the level + * + * @return pos + */ + Coord getEnterPoint(); + + + /** + * Check entity on tile + * + * @param pos tile coord + * @return true if some entity is standing there + */ + boolean isOccupied(Coord pos); + + + /** + * Check tile walkability + * + * @param pos tile coord + * @return true if the tile is walkable by entity + */ + boolean isWalkable(Coord pos); + + + /** + * Get entity by ID + * + * @param eid entity ID + * @return the entity, or null + */ + Entity getEntity(int eid); + + + /** + * @return all entities + */ + Collection getEntities(); + +} diff --git a/src/mightypork/rogue/world/level/MapAccess.java b/src/mightypork/rogue/world/level/MapAccess.java deleted file mode 100644 index bff3f2c..0000000 --- a/src/mightypork/rogue/world/level/MapAccess.java +++ /dev/null @@ -1,47 +0,0 @@ -package mightypork.rogue.world.level; - - -import mightypork.gamecore.util.math.algo.Coord; -import mightypork.gamecore.util.math.noise.NoiseGen; -import mightypork.rogue.world.tile.Tile; - - -/** - * Access interface for a level map. - * - * @author MightyPork - */ -public interface MapAccess { - - /** - * Ge tile at X,Y - * - * @param pos - * @return tile - */ - Tile getTile(Coord pos); - - - /** - * @return map width in tiles - */ - int getWidth(); - - - /** - * @return map height in tiles - */ - int getHeight(); - - - /** - * @return map seed - */ - long getSeed(); - - - /** - * @return level-specific noise generator - */ - NoiseGen getNoiseGen(); -} diff --git a/src/mightypork/rogue/world/level/render/EntityRenderContext.java b/src/mightypork/rogue/world/level/render/EntityRenderContext.java index 696e70b..cd183a9 100644 --- a/src/mightypork/rogue/world/level/render/EntityRenderContext.java +++ b/src/mightypork/rogue/world/level/render/EntityRenderContext.java @@ -2,12 +2,12 @@ package mightypork.rogue.world.level.render; import mightypork.gamecore.util.math.constraints.rect.Rect; -import mightypork.rogue.world.level.MapAccess; +import mightypork.rogue.world.level.LevelReadAccess; public class EntityRenderContext extends MapRenderContext { - public EntityRenderContext(MapAccess map, Rect drawArea) + public EntityRenderContext(LevelReadAccess map, Rect drawArea) { super(map, drawArea); } diff --git a/src/mightypork/rogue/world/level/render/MapRenderContext.java b/src/mightypork/rogue/world/level/render/MapRenderContext.java index 4d8a6e5..a08b70a 100644 --- a/src/mightypork/rogue/world/level/render/MapRenderContext.java +++ b/src/mightypork/rogue/world/level/render/MapRenderContext.java @@ -4,18 +4,18 @@ package mightypork.rogue.world.level.render; import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.rect.builders.TiledRect; -import mightypork.rogue.world.level.MapAccess; +import mightypork.rogue.world.level.LevelReadAccess; import mightypork.rogue.world.tile.Tile; public abstract class MapRenderContext { - protected final MapAccess map; + protected final LevelReadAccess map; protected final TiledRect tiler; private final Rect mapRect; - public MapRenderContext(MapAccess map, Rect drawArea) + public MapRenderContext(LevelReadAccess map, Rect drawArea) { this.map = map; @@ -35,7 +35,9 @@ public abstract class MapRenderContext { return mapRect; } - public Tile getTile(Coord pos) { + + public Tile getTile(Coord pos) + { return map.getTile(pos); } } diff --git a/src/mightypork/rogue/world/level/render/TileRenderContext.java b/src/mightypork/rogue/world/level/render/TileRenderContext.java index 5d2c2cf..f2472fd 100644 --- a/src/mightypork/rogue/world/level/render/TileRenderContext.java +++ b/src/mightypork/rogue/world/level/render/TileRenderContext.java @@ -6,7 +6,7 @@ import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; import mightypork.gamecore.util.math.noise.NoiseGen; -import mightypork.rogue.world.level.MapAccess; +import mightypork.rogue.world.level.LevelReadAccess; import mightypork.rogue.world.tile.Tile; @@ -21,7 +21,7 @@ public final class TileRenderContext extends MapRenderContext implements RectBou private final NoiseGen noise; - public TileRenderContext(MapAccess map, Rect drawArea) + public TileRenderContext(LevelReadAccess map, Rect drawArea) { super(map, drawArea); diff --git a/src/mightypork/rogue/world/tile/DroppedItemRenderer.java b/src/mightypork/rogue/world/tile/DroppedItemRenderer.java index 92c3628..9abb8fd 100644 --- a/src/mightypork/rogue/world/tile/DroppedItemRenderer.java +++ b/src/mightypork/rogue/world/tile/DroppedItemRenderer.java @@ -16,9 +16,8 @@ public class DroppedItemRenderer { // prepared constraints, to avoid re-building each frame private final RectBoundAdapter tileRectAdapter = new RectBoundAdapter(); - private final Rect itemRect = tileRectAdapter - .shrink(tileRectAdapter.height().perc(10)) - .moveY(itemAnim.neg().mul(tileRectAdapter.height().mul(0.2))); + private final Rect itemRect = tileRectAdapter.shrink(tileRectAdapter.height().perc(10)).moveY(itemAnim.neg().mul(tileRectAdapter.height().mul(0.2))); + public Animator getItemAnim() { diff --git a/src/mightypork/rogue/world/tile/Tile.java b/src/mightypork/rogue/world/tile/Tile.java index 62f34dd..406ee4d 100644 --- a/src/mightypork/rogue/world/tile/Tile.java +++ b/src/mightypork/rogue/world/tile/Tile.java @@ -12,7 +12,7 @@ import mightypork.gamecore.util.ion.IonOutput; import mightypork.gamecore.util.math.color.Color; import mightypork.rogue.world.World; import mightypork.rogue.world.item.Item; -import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.level.LevelAccess; import mightypork.rogue.world.level.render.TileRenderContext; @@ -34,7 +34,9 @@ public abstract class Tile implements IonObjBlob { // temporary flag for map. protected boolean occupied; protected boolean explored; - + + protected LevelAccess level; + private TileRenderer renderer; @@ -46,6 +48,8 @@ public abstract class Tile implements IonObjBlob { /** * Render the tile, using the main texture sheet. + * + * @param context rendering ctx */ @DefaultImpl public void renderTile(TileRenderContext context) @@ -56,8 +60,8 @@ public abstract class Tile implements IonObjBlob { renderer = makeRenderer(); } - if(renderer == null) { - Log.w("No renderer for tile "+Log.str(this)); + if (renderer == null) { + Log.w("No renderer for tile " + Log.str(this)); return; } @@ -147,7 +151,7 @@ public abstract class Tile implements IonObjBlob { @DefaultImpl - public void update(Level level, double delta) + public void update(double delta) { makeRenderer().update(delta); } @@ -226,9 +230,27 @@ public abstract class Tile implements IonObjBlob { * @return true if the tile is interactive and did something. */ @DefaultImpl - public boolean onClick(World world) + public boolean onClick() { return false; } + + public void setLevel(LevelAccess level) + { + this.level = level; + } + + + public LevelAccess getLevel() + { + return level; + } + + + protected World getWorld() + { + return level.getWorld(); + } + } diff --git a/src/mightypork/rogue/world/tile/TileRenderer.java b/src/mightypork/rogue/world/tile/TileRenderer.java index eabd571..8a304dc 100644 --- a/src/mightypork/rogue/world/tile/TileRenderer.java +++ b/src/mightypork/rogue/world/tile/TileRenderer.java @@ -8,7 +8,7 @@ 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; +import mightypork.rogue.world.tile.render.NullTileRenderer; /** diff --git a/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java b/src/mightypork/rogue/world/tile/render/BasicTileRenderer.java similarity index 93% rename from src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java rename to src/mightypork/rogue/world/tile/render/BasicTileRenderer.java index d7665da..63d4db0 100644 --- a/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java +++ b/src/mightypork/rogue/world/tile/render/BasicTileRenderer.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world.tile.renderers; +package mightypork.rogue.world.tile.render; import mightypork.gamecore.render.Render; diff --git a/src/mightypork/rogue/world/tile/renderers/DoorTileRenderer.java b/src/mightypork/rogue/world/tile/render/DoorTileRenderer.java similarity index 97% rename from src/mightypork/rogue/world/tile/renderers/DoorTileRenderer.java rename to src/mightypork/rogue/world/tile/render/DoorTileRenderer.java index 5babd0e..c61d480 100644 --- a/src/mightypork/rogue/world/tile/renderers/DoorTileRenderer.java +++ b/src/mightypork/rogue/world/tile/render/DoorTileRenderer.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world.tile.renderers; +package mightypork.rogue.world.tile.render; import mightypork.gamecore.render.Render; diff --git a/src/mightypork/rogue/world/tile/renderers/NullTileRenderer.java b/src/mightypork/rogue/world/tile/render/NullTileRenderer.java similarity index 92% rename from src/mightypork/rogue/world/tile/renderers/NullTileRenderer.java rename to src/mightypork/rogue/world/tile/render/NullTileRenderer.java index bf7fe60..5aa7d56 100644 --- a/src/mightypork/rogue/world/tile/renderers/NullTileRenderer.java +++ b/src/mightypork/rogue/world/tile/render/NullTileRenderer.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world.tile.renderers; +package mightypork.rogue.world.tile.render; import mightypork.rogue.world.level.render.TileRenderContext; diff --git a/src/mightypork/rogue/world/tile/tiles/NullTile.java b/src/mightypork/rogue/world/tile/tiles/NullTile.java index 087ae1b..5d1241e 100644 --- a/src/mightypork/rogue/world/tile/tiles/NullTile.java +++ b/src/mightypork/rogue/world/tile/tiles/NullTile.java @@ -2,7 +2,6 @@ package mightypork.rogue.world.tile.tiles; import mightypork.rogue.world.item.Item; -import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.render.TileRenderContext; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.TileModel; @@ -26,7 +25,7 @@ public class NullTile extends Tile { @Override - public void update(Level level, double delta) + public void update(double delta) { } diff --git a/src/mightypork/rogue/world/tile/tiles/TileBaseDoor.java b/src/mightypork/rogue/world/tile/tiles/TileBaseDoor.java index 58a21fb..dc22eda 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileBaseDoor.java +++ b/src/mightypork/rogue/world/tile/tiles/TileBaseDoor.java @@ -9,7 +9,7 @@ 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; +import mightypork.rogue.world.tile.render.DoorTileRenderer; public abstract class TileBaseDoor extends TileSolid { diff --git a/src/mightypork/rogue/world/tile/tiles/TileBaseFloor.java b/src/mightypork/rogue/world/tile/tiles/TileBaseFloor.java index 806ff51..c8bb699 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileBaseFloor.java +++ b/src/mightypork/rogue/world/tile/tiles/TileBaseFloor.java @@ -5,7 +5,7 @@ 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; +import mightypork.rogue.world.tile.render.BasicTileRenderer; public abstract class TileBaseFloor extends TileWithItems { diff --git a/src/mightypork/rogue/world/tile/tiles/TileBasePassage.java b/src/mightypork/rogue/world/tile/tiles/TileBasePassage.java index 152e6cf..103ca2e 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileBasePassage.java +++ b/src/mightypork/rogue/world/tile/tiles/TileBasePassage.java @@ -5,7 +5,7 @@ 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; +import mightypork.rogue.world.tile.render.BasicTileRenderer; /** diff --git a/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java b/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java index bf287ef..ebfaa4d 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java +++ b/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java @@ -8,7 +8,6 @@ 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.rogue.world.World; import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileType; @@ -25,7 +24,7 @@ public abstract class TileBaseSecretDoor extends TileBaseDoor { @Override - public boolean onClick(World world) + public boolean onClick() { if (!locked) return false; diff --git a/src/mightypork/rogue/world/tile/tiles/TileBaseWall.java b/src/mightypork/rogue/world/tile/tiles/TileBaseWall.java index 8edcd5f..6d4e61b 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileBaseWall.java +++ b/src/mightypork/rogue/world/tile/tiles/TileBaseWall.java @@ -4,7 +4,7 @@ package mightypork.rogue.world.tile.tiles; import mightypork.gamecore.resources.textures.TxSheet; import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileType; -import mightypork.rogue.world.tile.renderers.BasicTileRenderer; +import mightypork.rogue.world.tile.render.BasicTileRenderer; public abstract class TileBaseWall extends TileSolid { diff --git a/src/mightypork/rogue/world/tile/tiles/TileWithItems.java b/src/mightypork/rogue/world/tile/tiles/TileWithItems.java index 355e266..88c9e52 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileWithItems.java +++ b/src/mightypork/rogue/world/tile/tiles/TileWithItems.java @@ -8,8 +8,6 @@ import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonOutput; import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Items; -import mightypork.rogue.world.item.items.ItemMeat; -import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.render.TileRenderContext; import mightypork.rogue.world.tile.DroppedItemRenderer; import mightypork.rogue.world.tile.Tile; @@ -39,9 +37,9 @@ public abstract class TileWithItems extends Tile { @Override - public void update(Level level, double delta) + public void update(double delta) { - super.update(level, delta); + super.update(delta); itemRenderer.update(delta); }