+ rats & improvements; damaged items;

v5stable
Ondřej Hruška 11 years ago
parent 8509794eeb
commit 49b327b951
  1. BIN
      res/img/sprites.png
  2. BIN
      res/img/sprites.xcf
  3. 3
      src/mightypork/gamecore/gui/components/BaseComponent.java
  4. 4
      src/mightypork/gamecore/gui/components/LayoutComponent.java
  5. 18
      src/mightypork/gamecore/gui/components/painters/TextPainter.java
  6. 10
      src/mightypork/gamecore/gui/screens/Overlay.java
  7. 6
      src/mightypork/gamecore/resources/fonts/FontRenderer.java
  8. 14
      src/mightypork/gamecore/resources/fonts/impl/CachedFont.java
  9. 2
      src/mightypork/gamecore/util/math/Calc.java
  10. 4
      src/mightypork/gamecore/util/math/constraints/num/proxy/NumBoundAdapter.java
  11. 2
      src/mightypork/gamecore/util/math/timing/Animator.java
  12. 1
      src/mightypork/rogue/Config.java
  13. 5
      src/mightypork/rogue/Res.java
  14. 3
      src/mightypork/rogue/screens/game/HeartBar.java
  15. 17
      src/mightypork/rogue/screens/game/HudLayer.java
  16. 41
      src/mightypork/rogue/screens/game/InvLayer.java
  17. 27
      src/mightypork/rogue/screens/game/InvSlot.java
  18. 2
      src/mightypork/rogue/screens/game/NavButton.java
  19. 20
      src/mightypork/rogue/screens/game/ScreenGame.java
  20. 17
      src/mightypork/rogue/screens/game/WorldConsoleRenderer.java
  21. 14
      src/mightypork/rogue/world/Inventory.java
  22. 12
      src/mightypork/rogue/world/PlayerControl.java
  23. 2
      src/mightypork/rogue/world/PlayerInfo.java
  24. 15
      src/mightypork/rogue/world/World.java
  25. 16
      src/mightypork/rogue/world/WorldConsole.java
  26. 14
      src/mightypork/rogue/world/WorldCreator.java
  27. 8
      src/mightypork/rogue/world/entity/Entities.java
  28. 7
      src/mightypork/rogue/world/entity/Entity.java
  29. 12
      src/mightypork/rogue/world/entity/EntityModel.java
  30. 48
      src/mightypork/rogue/world/entity/entities/BossRatAi.java
  31. 37
      src/mightypork/rogue/world/entity/entities/BrownRatAi.java
  32. 92
      src/mightypork/rogue/world/entity/entities/EntityBossRat.java
  33. 92
      src/mightypork/rogue/world/entity/entities/EntityBrownRat.java
  34. 34
      src/mightypork/rogue/world/entity/entities/EntityGrayRat.java
  35. 4
      src/mightypork/rogue/world/entity/entities/GrayRatAi.java
  36. 6
      src/mightypork/rogue/world/entity/entities/PlayerEntity.java
  37. 62
      src/mightypork/rogue/world/gen/LevelGenerator.java
  38. 2
      src/mightypork/rogue/world/gen/RoomBuilder.java
  39. 116
      src/mightypork/rogue/world/gen/ScratchMap.java
  40. 34
      src/mightypork/rogue/world/gen/WorldGenError.java
  41. 36
      src/mightypork/rogue/world/gen/rooms/BossRoom.java
  42. 1
      src/mightypork/rogue/world/gen/rooms/Rooms.java
  43. 8
      src/mightypork/rogue/world/gen/rooms/SecretRoom.java
  44. 2
      src/mightypork/rogue/world/gui/MapView.java
  45. 17
      src/mightypork/rogue/world/item/Item.java
  46. 17
      src/mightypork/rogue/world/item/ItemModel.java
  47. 5
      src/mightypork/rogue/world/item/ItemRenderer.java
  48. 2
      src/mightypork/rogue/world/item/items/ItemBaseFood.java
  49. 1
      src/mightypork/rogue/world/item/items/ItemBaseWeapon.java
  50. 8
      src/mightypork/rogue/world/item/items/weapons/ItemBone.java
  51. 8
      src/mightypork/rogue/world/item/items/weapons/ItemClub.java
  52. 8
      src/mightypork/rogue/world/item/items/weapons/ItemHammer.java
  53. 8
      src/mightypork/rogue/world/item/items/weapons/ItemStone.java
  54. 10
      src/mightypork/rogue/world/item/items/weapons/ItemSword.java
  55. 28
      src/mightypork/rogue/world/item/render/QuadItemRenderer.java
  56. 38
      src/mightypork/rogue/world/level/Level.java
  57. 27
      src/mightypork/rogue/world/tile/DroppedItemRenderer.java
  58. 2
      src/mightypork/rogue/world/tile/TileRenderer.java
  59. 5
      src/mightypork/rogue/world/tile/tiles/TileWithItems.java

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

@ -27,7 +27,8 @@ public abstract class BaseComponent extends AbstractRectCache implements Compone
private int disableLevel = 0;
public BaseComponent() {
public BaseComponent()
{
enableCaching(false);
}

@ -105,15 +105,17 @@ public abstract class LayoutComponent extends BaseComponent implements ClientHub
subModule.removeChildClient(client);
}
@Override
public void enable(boolean yes)
{
super.enable(yes);
for(Component c : components) {
for (final Component c : components) {
c.enable(yes);
}
}
// @Override
// public void enable(boolean yes)
// {

@ -41,7 +41,8 @@ public class TextPainter extends BaseComponent {
/**
* @param font font to use
*/
public TextPainter(GLFont font) {
public TextPainter(GLFont font)
{
this(font, AlignX.LEFT, RGB.WHITE);
}
@ -54,7 +55,8 @@ public class TextPainter extends BaseComponent {
* @param color default color
* @param text drawn text
*/
public TextPainter(GLFont font, AlignX align, Color color, String text) {
public TextPainter(GLFont font, AlignX align, Color color, String text)
{
this(font, align, color, new StringWrapper(text));
}
@ -67,7 +69,8 @@ public class TextPainter extends BaseComponent {
* @param color default color
* @param text text provider
*/
public TextPainter(GLFont font, AlignX align, Color color, StringProvider text) {
public TextPainter(GLFont font, AlignX align, Color color, StringProvider text)
{
this.font = new FontRenderer(font);
this.color = color;
this.align = align;
@ -80,7 +83,8 @@ public class TextPainter extends BaseComponent {
* @param align text align
* @param color default color
*/
public TextPainter(GLFont font, AlignX align, Color color) {
public TextPainter(GLFont font, AlignX align, Color color)
{
this(font, align, color, (StringProvider) null);
}
@ -92,8 +96,8 @@ public class TextPainter extends BaseComponent {
final String str = text.getString();
Num shrX = height().perc(xPaddingPerc);
Num shrY = height().perc(yPaddingPerc);
final Num shrX = height().perc(xPaddingPerc);
final Num shrY = height().perc(yPaddingPerc);
final Rect rect = getRect().shrink(shrX, shrY);
@ -101,7 +105,7 @@ public class TextPainter extends BaseComponent {
font.draw(str, rect.round(), align, shadowColor);
}
Rect r = (shadow ? rect.move(shadowOffset.neg()) : rect).round();
final Rect r = (shadow ? rect.move(shadowOffset.neg()) : rect).round();
font.draw(str, r, align, color);
if (Config.DEBUG_FONT_RENDER) Render.quadColor(r, RGB.PINK.withAlpha(0.4));

@ -25,7 +25,8 @@ import mightypork.gamecore.util.math.constraints.vect.Vect;
*
* @author MightyPork
*/
public abstract class Overlay extends AppSubModule implements Comparable<Overlay>, Updateable, Renderable, KeyBinder, Hideable, Enableable, LayoutChangeListener {
public abstract class Overlay extends AppSubModule implements Comparable<Overlay>, Updateable, Renderable, KeyBinder, Hideable, Enableable,
LayoutChangeListener {
private boolean visible = true;
private boolean enabled = true;
@ -87,6 +88,7 @@ public abstract class Overlay extends AppSubModule implements Comparable<Overlay
root.setVisible(visible);
}
@Override
public void enable(boolean yes)
{
@ -94,12 +96,14 @@ public abstract class Overlay extends AppSubModule implements Comparable<Overlay
root.enable(yes);
}
@Override
public boolean isEnabled()
{
return enabled;
}
/**
* Get rendering layer
*
@ -126,7 +130,7 @@ public abstract class Overlay extends AppSubModule implements Comparable<Overlay
@Override
public void render()
{
if(!isVisible()) return;
if (!isVisible()) return;
for (final Renderable r : rendered) {
r.render();
@ -137,7 +141,7 @@ public abstract class Overlay extends AppSubModule implements Comparable<Overlay
@Override
public void update(double delta)
{
if(!isEnabled()) return;
if (!isEnabled()) return;
for (final Updateable u : updated) {
u.update(delta);

@ -24,7 +24,8 @@ public class FontRenderer {
/**
* @param font used font
*/
public FontRenderer(GLFont font) {
public FontRenderer(GLFont font)
{
this(font, RGB.WHITE);
}
@ -33,7 +34,8 @@ public class FontRenderer {
* @param font used font
* @param color drawing color
*/
public FontRenderer(GLFont font, Color color) {
public FontRenderer(GLFont font, Color color)
{
this.font = font;
this.color = color;
}

@ -90,7 +90,8 @@ public class CachedFont implements GLFont {
* @param filter used Gl filter
* @param chars chars to load
*/
public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, String chars) {
public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, String chars)
{
this(font, antialias, filter, (" " + chars).toCharArray());
}
@ -103,7 +104,8 @@ public class CachedFont implements GLFont {
* @param filter used Gl filter
* @param chars chars to load
*/
public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, char[] chars) {
public CachedFont(java.awt.Font font, boolean antialias, FilterMode filter, char[] chars)
{
GLUtils.checkGLContext();
this.font = font;
@ -163,7 +165,8 @@ public class CachedFont implements GLFont {
public int height;
public LoadedGlyph(char c, BufferedImage image) {
public LoadedGlyph(char c, BufferedImage image)
{
this.image = image;
this.c = c;
this.width = image.getWidth();
@ -299,7 +302,8 @@ public class CachedFont implements GLFont {
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI);
} else {
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData());
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder())
.put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData());
}
byteBuffer.flip();
@ -413,7 +417,7 @@ public class CachedFont implements GLFont {
final float tymin = chtx.texPosY;
final float draw_width = minx + chtx.width - minx;
final float draw_height = chtx.height;
final float drawy0 = (float) (0f - draw_height*discardTop);
final float drawy0 = (float) (0f - draw_height * discardTop);
final float txmin01 = txmin / textureWidth;
final float tymin01 = tymin / textureHeight;

@ -671,7 +671,7 @@ public class Calc {
public static int randInt(Random rand, int low, int high)
{
int range = high - low + 1;
if(range < 1) range = 1;
if (range < 1) range = 1;
return low + rand.nextInt(range);
}

@ -21,9 +21,9 @@ public class NumBoundAdapter extends NumAdapter implements PluggableNumBound {
@Override
public void setNum(NumBound rect)
public void setNum(NumBound num)
{
this.backing = rect;
this.backing = num;
}

@ -122,7 +122,7 @@ public abstract class Animator extends Num implements Updateable, Pauseable {
{
final double target = numAnim.getEnd();
numAnim.setTo(Calc.clamp(value, lowValue, highValue));
numAnim.animate(target, numAnim.getDefaultDuration());
numAnim.animate((target < value ? highValue : lowValue), target, numAnim.getDefaultDuration());
}

@ -26,7 +26,6 @@ public final class Config {
private static final String PK_START_IN_FS = "cfg.start_in_fullscreen";
/**
* Prepare config manager and load user settings
*/

@ -108,7 +108,10 @@ public final class Res {
texture = textures.loadTexture("/res/img/sprites.png", FilterMode.NEAREST, WrapMode.CLAMP);
grid = texture.grid(8, 8);
textures.add("sprite.player", grid.makeSheet(0, 0, 4, 1));
textures.add("sprite.rat", grid.makeSheet(0, 1, 4, 1));
textures.add("sprite.rat.gray", grid.makeSheet(0, 1, 4, 1));
textures.add("sprite.rat.brown", grid.makeSheet(0, 2, 4, 1));
textures.add("sprite.rat.boss", grid.makeSheet(0, 3, 4, 1));
textures.add("sprite.zzz", grid.makeQuad(0, 7)); // sleep thingy
// logo

@ -30,7 +30,8 @@ public class HeartBar extends BaseComponent {
* @param img_off
* @param align
*/
public HeartBar(Num total, Num active, TxQuad img_on, TxQuad img_half, TxQuad img_off, AlignX align) {
public HeartBar(Num total, Num active, TxQuad img_on, TxQuad img_half, TxQuad img_off, AlignX align)
{
super();
this.total = total;
this.active = active;

@ -39,7 +39,8 @@ public class HudLayer extends ScreenLayer {
private final ScreenGame gameScreen;
public HudLayer(ScreenGame screen) {
public HudLayer(ScreenGame screen)
{
super(screen);
this.gameScreen = screen;
@ -55,13 +56,13 @@ public class HudLayer extends ScreenLayer {
private void buildConsole()
{
Num rh = root.height();
Num rw = root.width();
Rect consoleRect = root.shrink(rw.perc(2), Num.ZERO, rh.perc(6), rh.perc(16));
final Num rh = root.height();
final Num rw = root.width();
final Rect consoleRect = root.shrink(rw.perc(2), Num.ZERO, rh.perc(6), rh.perc(16));
Num perRow = consoleRect.height().div(20).max(12).min(32);
final Num perRow = consoleRect.height().div(20).max(12).min(32);
WorldConsoleRenderer wcr = new WorldConsoleRenderer(perRow);
final WorldConsoleRenderer wcr = new WorldConsoleRenderer(perRow);
wcr.setRect(consoleRect);
root.add(wcr);
}
@ -103,7 +104,7 @@ public class HudLayer extends ScreenLayer {
}
});
levelText.setRect(hearts_box.moveY(hearts_box.height().mul(1/7D)));
levelText.setRect(hearts_box.moveY(hearts_box.height().mul(1 / 7D)));
root.add(levelText);
}
@ -117,7 +118,7 @@ public class HudLayer extends ScreenLayer {
NavButton btn;
nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.inventory")));
btn.setAction(gameScreen.actionInv);
btn.setAction(gameScreen.actionToggleInv);
nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.eat")));
btn.setAction(gameScreen.actionEat);

@ -87,12 +87,15 @@ public class InvLayer extends ScreenLayer {
}
public InvLayer(final ScreenGame screen) {
public InvLayer(final ScreenGame screen)
{
super(screen);
final Rect fg = root.shrink(root.height().perc(15));
final QuadPainter qp = new QuadPainter(RGB.BLACK_30, RGB.BLACK_30, RGB.BLACK_80, RGB.BLACK_80);
// darker down to cover console.
final QuadPainter qp = new QuadPainter(RGB.BLACK_30, RGB.BLACK_30, RGB.BLACK_90, RGB.BLACK_90);
qp.setRect(root);
root.add(qp);
@ -137,19 +140,7 @@ public class InvLayer extends ScreenLayer {
gl.put(txp2, pos, 0, 1, 1);
txp2.setPaddingHPerc(0, 25);
final Runnable leaveInv = new Runnable() {
@Override
public void run()
{
if(!isEnabled()) return;
screen.setState(GScrState.WORLD);
}
};
bindKey(new KeyStroke(Keys.ESCAPE), leaveInv);
//bindKey(new KeyStroke(Keys.I), leaveInv);
bindKey(new KeyStroke(Keys.ESCAPE), screen.actionToggleInv);
// TODO needs some rewrite of keys system
bindKey(new KeyStroke(Keys.E), new Runnable() {
@ -157,7 +148,7 @@ public class InvLayer extends ScreenLayer {
@Override
public void run()
{
if(!isEnabled()) return;
if (!isEnabled()) return;
if (WorldProvider.get().getPlayer().isDead()) return;
@ -198,7 +189,7 @@ public class InvLayer extends ScreenLayer {
@Override
public void run()
{
if(!isEnabled()) return;
if (!isEnabled()) return;
final int selected = getSelectedSlot();
if (selected != -1) {
@ -229,9 +220,9 @@ public class InvLayer extends ScreenLayer {
@Override
public void run()
{
if(!isEnabled()) return;
if (!isEnabled()) return;
int sel = getSelectedSlot();
final int sel = getSelectedSlot();
if (sel == -1) {
selectSlot(0);
return;
@ -246,9 +237,9 @@ public class InvLayer extends ScreenLayer {
@Override
public void run()
{
if(!isEnabled()) return;
if (!isEnabled()) return;
int sel = getSelectedSlot();
final int sel = getSelectedSlot();
if (sel == -1) {
selectSlot(0);
return;
@ -263,9 +254,9 @@ public class InvLayer extends ScreenLayer {
@Override
public void run()
{
if(!isEnabled()) return;
if (!isEnabled()) return;
int sel = getSelectedSlot();
final int sel = getSelectedSlot();
if (sel == -1) {
selectSlot(0);
return;
@ -280,9 +271,9 @@ public class InvLayer extends ScreenLayer {
@Override
public void run()
{
if(!isEnabled()) return;
if (!isEnabled()) return;
int sel = getSelectedSlot();
final int sel = getSelectedSlot();
if (sel == -1) {
selectSlot(0);
return;

@ -8,8 +8,10 @@ import mightypork.gamecore.gui.components.painters.TextPainter;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.gamecore.util.math.Calc;
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.rect.Rect;
import mightypork.gamecore.util.math.constraints.rect.caching.RectCache;
import mightypork.rogue.Res;
import mightypork.rogue.world.World.PlayerFacade;
@ -41,8 +43,12 @@ public class InvSlot extends ClickableComponent {
private final RectCache rbTxRect;
private final RectCache rtTxRect;
private final Rect usesRect;
private final Num hAlpha = Num.make(0.7);
public InvSlot(int index, InvSlot[] allSlots) {
public InvSlot(int index, InvSlot[] allSlots)
{
super();
this.txBase = Res.txq("inv.slot.base");
this.txSelected = Res.txq("inv.slot.selected");
@ -53,6 +59,8 @@ public class InvSlot extends ClickableComponent {
this.uiRect = getRect().shrink(height().perc(16)).cached();
this.itemRect = uiRect.shrink(Num.ZERO, height().perc(14), height().perc(14), Num.ZERO).cached();
this.usesRect = uiRect.topLeft().startRect().grow(Num.ZERO, uiRect.width().perc(40), Num.ZERO, uiRect.height().perc(8));
//@formatter:off
this.rbTxRect = uiRect.bottomEdge()
.moveY(uiRect.height().perc(1*(30/7D)))
@ -134,11 +142,26 @@ public class InvSlot extends ClickableComponent {
rtTxP.render();
} else if (itm.getType() == ItemType.WEAPON) {
int atk = itm.getAttackPoints();
final int atk = itm.getAttackPoints();
rtTxP.setText((atk >= 0 ? "+" : "") + atk);
rtTxP.setColor(RGB.CYAN);
rtTxP.render();
}
if (itm.isDamageable()) {
Color.pushAlpha(hAlpha);
Render.quadColor(usesRect, RGB.BLACK);
final double useRatio = (itm.getRemainingUses() / (double) itm.getMaxUses());
final Color barColor = (useRatio > 0.6 ? RGB.GREEN : useRatio > 0.2 ? RGB.ORANGE : RGB.RED);
Render.quadColor(usesRect.shrinkRight(usesRect.width().value() * (1 - useRatio)), barColor);
Color.popAlpha();
}
}
}

@ -40,7 +40,7 @@ public class NavButton extends ClickableComponent {
bg = base;
}
if(!isEnabled()) bg = base; // override effects
if (!isEnabled()) bg = base; // override effects
Render.quadTextured(this, bg);
Render.quadTextured(this, fg);

@ -4,12 +4,14 @@ package mightypork.rogue.screens.game;
import java.util.Random;
import mightypork.gamecore.app.AppAccess;
import mightypork.gamecore.eventbus.events.Updateable;
import mightypork.gamecore.gui.Action;
import mightypork.gamecore.gui.ActionGroup;
import mightypork.gamecore.gui.screens.LayeredScreen;
import mightypork.gamecore.input.KeyStroke;
import mightypork.gamecore.input.Keys;
import mightypork.rogue.Config;
import mightypork.rogue.world.World.PlayerFacade;
import mightypork.rogue.world.WorldProvider;
import mightypork.rogue.world.events.WorldPauseRequest;
import mightypork.rogue.world.events.WorldPauseRequest.PauseAction;
@ -31,6 +33,8 @@ public class ScreenGame extends LayeredScreen {
private InvLayer invLayer;
private HudLayer hudLayer;
private WorldLayer worldLayer;
private GScrState state = GScrState.WORLD;
private final ActionGroup worldActions = new ActionGroup();
@ -40,16 +44,18 @@ public class ScreenGame extends LayeredScreen {
@Override
public void execute()
{
WorldProvider.get().getPlayer().tryToEatSomeFood();
final PlayerFacade pl = WorldProvider.get().getPlayer();
if (pl.isDead()) return;
pl.tryToEatSomeFood();
}
};
public Action actionInv = new Action() {
public Action actionToggleInv = new Action() {
@Override
public void execute()
{
setState(GScrState.INV);
setState(getState() == GScrState.INV ? GScrState.WORLD : GScrState.INV);
}
};
@ -80,8 +86,6 @@ public class ScreenGame extends LayeredScreen {
}
};
private WorldLayer worldLayer;
/**
* Set gui state (overlay)
@ -122,7 +126,8 @@ public class ScreenGame extends LayeredScreen {
}
public ScreenGame(AppAccess app) {
public ScreenGame(AppAccess app)
{
super(app);
addLayer(invLayer = new InvLayer(this));
@ -152,7 +157,7 @@ public class ScreenGame extends LayeredScreen {
bindKey(new KeyStroke(Keys.PAUSE), actionTogglePause);
bindKey(new KeyStroke(Keys.SPACE), actionTogglePause);
bindKey(new KeyStroke(Keys.I), actionInv);
bindKey(new KeyStroke(Keys.I), actionToggleInv);
bindKey(new KeyStroke(Keys.E), actionEat);
bindKey(new KeyStroke(Keys.M), actionToggleMinimap);
bindKey(new KeyStroke(Keys.Z), actionToggleZoom);
@ -162,7 +167,6 @@ public class ScreenGame extends LayeredScreen {
worldActions.add(hudLayer);
worldActions.add(actionEat);
worldActions.add(actionInv);
worldActions.add(actionToggleMinimap);
worldActions.add(actionTogglePause);
worldActions.add(actionToggleZoom);

@ -3,8 +3,6 @@ package mightypork.rogue.screens.game;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.LinkedList;
import java.util.List;
import mightypork.gamecore.gui.AlignX;
import mightypork.gamecore.gui.components.BaseComponent;
@ -17,7 +15,6 @@ import mightypork.gamecore.util.math.constraints.num.mutable.NumVar;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.Res;
import mightypork.rogue.world.WorldConsole;
import mightypork.rogue.world.WorldConsole.Entry;
import mightypork.rogue.world.WorldProvider;
@ -37,25 +34,25 @@ public class WorldConsoleRenderer extends BaseComponent {
@Override
protected void renderComponent()
{
double rh = rowHeight.value();
final double rh = rowHeight.value();
Rect lowRow = bottomEdge().growUp(rowHeight);
final Rect lowRow = bottomEdge().growUp(rowHeight);
Collection<WorldConsole.Entry> entries = WorldProvider.get().getWorld().getConsole().getEntries();
final Collection<WorldConsole.Entry> entries = WorldProvider.get().getWorld().getConsole().getEntries();
int cnt = 0;
NumVar alph = Num.makeVar();
final NumVar alph = Num.makeVar();
Color.pushAlpha(alph);
try {
for (WorldConsole.Entry entry : entries) {
for (final WorldConsole.Entry entry : entries) {
alph.setTo(entry.getAlpha());
Rect rrr = lowRow.moveY(-rh * cnt);
final Rect rrr = lowRow.moveY(-rh * cnt);
fr.draw(entry.getMessage(), rrr.move(rh / 12, rh / 12), AlignX.LEFT, RGB.BLACK_60);
fr.draw(entry.getMessage(), rrr, AlignX.LEFT, RGB.WHITE);
@ -63,7 +60,7 @@ public class WorldConsoleRenderer extends BaseComponent {
cnt++;
}
} catch (ConcurrentModificationException e) {
} catch (final ConcurrentModificationException e) {
Log.e(e); // this should not happen anymore
}

@ -16,12 +16,14 @@ public class Inventory implements IonObjBinary {
private Item[] items;
public Inventory(int size) {
public Inventory(int size)
{
this.items = new Item[size];
}
public Inventory() {
public Inventory()
{
// ION constructor
}
@ -158,7 +160,7 @@ public class Inventory implements IonObjBinary {
public void clean()
{
for (int i = 0; i < getSize(); i++) {
Item itm = getItem(i);
final Item itm = getItem(i);
if (itm == null) continue;
if (itm.isEmpty()) setItem(i, null);
}
@ -175,10 +177,8 @@ public class Inventory implements IonObjBinary {
s += i + ": ";
final Item itm = getItem(i);
if (itm == null)
s += "<null>";
else
s += itm;
if (itm == null) s += "<null>";
else s += itm;
}
s += "]";
return s;

@ -12,6 +12,7 @@ import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityType;
import mightypork.rogue.world.entity.modules.EntityMoveListener;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
public abstract class PlayerControl {
@ -115,15 +116,20 @@ public abstract class PlayerControl {
private boolean doClickTile(Vect pos)
{
// 1st try to hit entity
//try to click tile
if (getLevel().getTile(Coord.fromVect(pos)).onClick()) return true;
final Tile t = getLevel().getTile(Coord.fromVect(pos));
if (!t.isPotentiallyWalkable()) return false; // no point in attacking entity thru wall, right?
//try to hit entity
final Entity prey = getLevel().getClosestEntity(pos, EntityType.MONSTER, 1);
if (prey != null) {
getPlayer().attack(prey);
return true;
}
//2nd try to click tile
return getLevel().getTile(Coord.fromVect(pos)).onClick();
return false;
}

@ -106,7 +106,7 @@ public class PlayerInfo implements IonObjBundled {
public void selectWeapon(int selectedWeapon)
{
if(selectedWeapon<0||selectedWeapon>=getInventory().getSize()) {
if (selectedWeapon < 0 || selectedWeapon >= getInventory().getSize()) {
selectedWeapon = NO_WEAPON;
}

@ -229,7 +229,7 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
public void tryToEatSomeFood()
{
List<Item> foods = new ArrayList<>();
final List<Item> foods = new ArrayList<>();
for (int i = 0; i < getInventory().getSize(); i++) {
final Item itm = getInventory().getItem(i);
if (itm != null && itm.getType() == ItemType.FOOD) {
@ -247,14 +247,14 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
}
});
for (Item itm : foods) {
for (final Item itm : foods) {
if (eatFood(itm)) {
getInventory().clean();
return;
}
}
if(getHealth()<getHealthMax()) {
if (getHealth() < getHealthMax()) {
msgNoMoreFood();
} else {
msgNotHungry();
@ -264,7 +264,7 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
public void attack(Entity prey)
{
int attackPoints = getAttackStrength();
final int attackPoints = getAttackStrength();
prey.receiveAttack(getPlayer().getEntity(), attackPoints);
@ -272,7 +272,7 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
msgKill(prey);
}
Item wpn = getSelectedWeapon();
final Item wpn = getSelectedWeapon();
if (wpn != null) {
wpn.use();
@ -293,7 +293,7 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
{
if (getSelectedWeapon() != null) return;
List<Item> wpns = new ArrayList<>();
final List<Item> wpns = new ArrayList<>();
for (int i = 0; i < getInventory().getSize(); i++) {
final Item itm = getInventory().getItem(i);
if (itm != null && itm.getType() == ItemType.WEAPON) {
@ -311,7 +311,7 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
}
});
for (Item itm : wpns) {
for (final Item itm : wpns) {
for (int i = 0; i < getInventory().getSize(); i++) {
final Item itm2 = getInventory().getItem(i);
if (itm2 == itm) {
@ -584,6 +584,7 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea
console.addMessage("You don't have any food!");
}
public void msgNotHungry()
{
console.addMessage("You are not hungry.");

@ -1,9 +1,10 @@
package mightypork.rogue.world;
import java.util.*;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import mightypork.gamecore.eventbus.events.Updateable;
import mightypork.gamecore.util.math.Easing;
@ -22,7 +23,8 @@ public class WorldConsole implements Updateable {
private double elapsed = 0;
private Entry(String text) {
private Entry(String text)
{
this.text = text;
this.fadeout = new NumAnimated(1, Easing.LINEAR);
this.fadeout.setDefaultDuration(0.5);
@ -76,8 +78,8 @@ public class WorldConsole implements Updateable {
@Override
public void update(double delta)
{
for (Iterator<Entry> iter = entries.iterator(); iter.hasNext();) {
Entry e = iter.next();
for (final Iterator<Entry> iter = entries.iterator(); iter.hasNext();) {
final Entry e = iter.next();
e.update(delta);
@ -99,7 +101,9 @@ public class WorldConsole implements Updateable {
return entries;
}
public void clear() {
public void clear()
{
entries.clear();
}
}

@ -4,7 +4,6 @@ package mightypork.rogue.world;
import java.util.Random;
import mightypork.rogue.world.gen.LevelGenerator;
import mightypork.rogue.world.level.Level;
public class WorldCreator {
@ -20,12 +19,15 @@ public class WorldCreator {
final World w = new World();
w.setSeed(seed);
final int count = 7;
// final int count = 7;
//
// for (int i = 1; i <= count; i++) {
// final Level l = LevelGenerator.build(w, rand.nextLong(), i, LevelGenerator.DUNGEON_THEME, i == count);
// w.addLevel(l);
// }
for (int i = 1; i <= count; i++) {
final Level l = LevelGenerator.build(w, rand.nextLong(), i, LevelGenerator.DUNGEON_THEME, i == count);
w.addLevel(l);
}
w.addLevel(LevelGenerator.build(w, rand.nextLong(), 6, LevelGenerator.DUNGEON_THEME, false));
w.addLevel(LevelGenerator.build(w, rand.nextLong(), 7, LevelGenerator.DUNGEON_THEME, true));
w.createPlayer();

@ -6,8 +6,10 @@ import java.util.Collection;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.entity.entities.EntityBossRat;
import mightypork.rogue.world.entity.entities.EntityBrownRat;
import mightypork.rogue.world.entity.entities.EntityGrayRat;
import mightypork.rogue.world.entity.entities.PlayerEntity;
import mightypork.rogue.world.entity.entities.RatEntity;
/**
@ -20,7 +22,9 @@ public final class Entities {
private static final EntityModel[] entities = new EntityModel[256];
public static final EntityModel PLAYER = new EntityModel(1, PlayerEntity.class);
public static final EntityModel RAT = new EntityModel(2, RatEntity.class);
public static final EntityModel RAT_GRAY = new EntityModel(2, EntityGrayRat.class);
public static final EntityModel RAT_BROWN = new EntityModel(3, EntityBrownRat.class);
public static final EntityModel RAT_BOSS = new EntityModel(4, EntityBossRat.class);
public static void register(int id, EntityModel model)

@ -35,7 +35,7 @@ public abstract class Entity implements IonObjBundled, Updateable {
protected final Random rand = new Random();
/** Entity ID */
private int entityId;
private int entityId = -1;
private final Map<String, EntityModule> modules = new HashMap<>();
@ -123,6 +123,10 @@ public abstract class Entity implements IonObjBundled, Updateable {
public void setLevel(Level level)
{
if (level != null && entityId < 0) {
entityId = level.getWorld().getNewEID();
}
if (level != null) level.freeTile(getCoord());
this.level = level;
@ -266,5 +270,6 @@ public abstract class Entity implements IonObjBundled, Updateable {
return despawnDelay;
}
public abstract String getVisualName();
}

@ -45,6 +45,18 @@ public final class EntityModel {
}
/**
* Create entitiy without EID. EID will be assigned when the entity is added
* to a level.
*
* @return entity.
*/
public Entity createEntity()
{
return createEntity(-1);
}
public Entity loadEntity(IonInput in) throws IOException
{
final IonBundle bundle = in.readBundle();

@ -0,0 +1,48 @@
package mightypork.rogue.world.entity.entities;
import mightypork.rogue.world.entity.AiTimer;
import mightypork.rogue.world.entity.Entity;
public class BossRatAi extends GrayRatAi {
private final AiTimer healTimer = new AiTimer(0.5) {
@Override
public void run()
{
entity.health.addHealth(1); // heal
}
};
public BossRatAi(Entity entity)
{
super(entity);
setAttackTime(0.6);
}
@Override
protected int getAttackStrength()
{
return 5 + rand.nextInt(4);
}
@Override
protected int getPreyAbandonDistance()
{
return 15 + rand.nextInt(4);
}
@Override
public void update(double delta)
{
super.update(delta);
healTimer.update(delta);
}
}

@ -0,0 +1,37 @@
package mightypork.rogue.world.entity.entities;
import mightypork.rogue.world.entity.Entity;
public class BrownRatAi extends GrayRatAi {
public BrownRatAi(Entity entity)
{
super(entity);
setAttackTime(0.8);
setScanTime(1);
}
@Override
protected double getScanRadius()
{
return isSleeping() ? 3 + rand.nextInt(3) : 5 + rand.nextInt(3);
}
@Override
protected int getAttackStrength()
{
return 3 + rand.nextInt(2);
}
@Override
protected int getPreyAbandonDistance()
{
return 11 + rand.nextInt(4);
}
}

@ -0,0 +1,92 @@
package mightypork.rogue.world.entity.entities;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityModel;
import mightypork.rogue.world.entity.EntityPathFinder;
import mightypork.rogue.world.entity.EntityRenderer;
import mightypork.rogue.world.entity.EntityType;
import mightypork.rogue.world.entity.render.EntityRendererMobLR;
import mightypork.rogue.world.item.Items;
public class EntityBossRat extends Entity {
private EntityRenderer renderer;
/** Navigation PFC */
private final PathFinder pathf = new EntityPathFinder(this);
private final BossRatAi ai = new BossRatAi(this);
public EntityBossRat(EntityModel model, int eid)
{
super(model, eid);
addModule("ai", ai);
pos.addMoveListener(ai);
pos.setStepTime(0.4);
setDespawnDelay(1);
health.setMaxHealth(80);
health.setHealth(80);
health.setHitCooldownTime(0.35);
}
@Override
protected EntityRenderer getRenderer()
{
if (renderer == null) {
renderer = new EntityRendererMobLR(this, "sprite.rat.boss");
}
return renderer;
}
@Override
public EntityType getType()
{
return EntityType.MONSTER;
}
@Override
public PathFinder getPathFinder()
{
return pathf;
}
@Override
public void onCorpseRemoved()
{
// TODO drop rare stuff & fire event.
if (rand.nextInt(8) == 0) {
getLevel().dropNear(getCoord(), Items.BONE.createItem());
return;
}
if (rand.nextInt(3) == 0) {
getLevel().dropNear(getCoord(), Items.MEAT.createItem());
return;
}
if (rand.nextInt(6) == 0) {
getLevel().dropNear(getCoord(), Items.CHEESE.createItem());
return;
}
}
@Override
public String getVisualName()
{
return "Rat Boss";
}
}

@ -0,0 +1,92 @@
package mightypork.rogue.world.entity.entities;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityModel;
import mightypork.rogue.world.entity.EntityPathFinder;
import mightypork.rogue.world.entity.EntityRenderer;
import mightypork.rogue.world.entity.EntityType;
import mightypork.rogue.world.entity.render.EntityRendererMobLR;
import mightypork.rogue.world.item.Items;
public class EntityBrownRat extends Entity {
private EntityRenderer renderer;
private final PathFinder pathf = new EntityPathFinder(this);
private final BrownRatAi ai = new BrownRatAi(this);
public EntityBrownRat(EntityModel model, int eid)
{
super(model, eid);
addModule("ai", ai);
pos.addMoveListener(ai);
pos.setStepTime(0.37); // faster than gray rat
setDespawnDelay(1);
health.setMaxHealth(14);
health.setHealth(Calc.randInt(rand, 8, 14)); // tougher to kill
health.setHitCooldownTime(0.35); // a bit longer than gray rat
}
@Override
protected EntityRenderer getRenderer()
{
if (renderer == null) {
renderer = new EntityRendererMobLR(this, "sprite.rat.brown");
}
return renderer;
}
@Override
public EntityType getType()
{
return EntityType.MONSTER;
}
@Override
public PathFinder getPathFinder()
{
return pathf;
}
@Override
public void onCorpseRemoved()
{
// drop rat stuff
if (rand.nextInt(8) == 0) {
getLevel().dropNear(getCoord(), Items.BONE.createItemDamaged(10));
return;
}
if (rand.nextInt(3) == 0) {
getLevel().dropNear(getCoord(), Items.MEAT.createItem());
return;
}
if (rand.nextInt(6) == 0) {
getLevel().dropNear(getCoord(), Items.CHEESE.createItem());
return;
}
}
@Override
public String getVisualName()
{
return "Brown Rat";
}
}

@ -12,17 +12,17 @@ import mightypork.rogue.world.entity.render.EntityRendererMobLR;
import mightypork.rogue.world.item.Items;
public class RatEntity extends Entity {
public class EntityGrayRat extends Entity {
/** Navigation PFC */
private PathFinder pathf;
private final PathFinder pathf = new EntityPathFinder(this);
private final RatAi ai = new RatAi(this);
private final GrayRatAi ai = new GrayRatAi(this);
private EntityRenderer renderer;
public RatEntity(EntityModel model, int eid) {
public EntityGrayRat(EntityModel model, int eid)
{
super(model, eid);
addModule("ai", ai);
@ -32,7 +32,7 @@ public class RatEntity extends Entity {
setDespawnDelay(1);
health.setMaxHealth(5);
health.setHealth(Calc.randInt(rand, 3, 5)); // fill health bar to max
health.setHealth(Calc.randInt(rand, 3, 5));
health.setHitCooldownTime(0.3);
}
@ -40,10 +40,6 @@ public class RatEntity extends Entity {
@Override
public PathFinder getPathFinder()
{
if (pathf == null) {
pathf = new EntityPathFinder(this);
}
return pathf;
}
@ -59,41 +55,35 @@ public class RatEntity extends Entity {
protected EntityRenderer getRenderer()
{
if (renderer == null) {
renderer = new EntityRendererMobLR(this, "sprite.rat");
renderer = new EntityRendererMobLR(this, "sprite.rat.gray");
}
return renderer;
}
@Override
public void onKilled()
{
super.onKilled();
}
@Override
public void onCorpseRemoved()
{
// drop rat stuff
if(rand.nextInt(7) == 0) {
getLevel().dropNear(getCoord(), Items.BONE.createItem());
if (rand.nextInt(6) == 0) {
getLevel().dropNear(getCoord(), Items.BONE.createItemDamaged(10));
return;
}
if(rand.nextInt(3) == 0) {
if (rand.nextInt(7) == 0) {
getLevel().dropNear(getCoord(), Items.MEAT.createItem());
return;
}
if(rand.nextInt(2) == 0) {
if (rand.nextInt(3) == 0) {
getLevel().dropNear(getCoord(), Items.CHEESE.createItem());
return;
}
}
@Override
public String getVisualName()
{

@ -4,9 +4,9 @@ package mightypork.rogue.world.entity.entities;
import mightypork.rogue.world.entity.Entity;
public class RatAi extends MonsterAi {
public class GrayRatAi extends MonsterAi {
public RatAi(Entity entity)
public GrayRatAi(Entity entity)
{
super(entity);

@ -16,7 +16,8 @@ public class PlayerEntity extends Entity {
class PlayerAi extends EntityModule implements EntityMoveListener {
public PlayerAi(Entity entity) {
public PlayerAi(Entity entity)
{
super(entity);
setDespawnDelay(2);
@ -79,7 +80,8 @@ public class PlayerEntity extends Entity {
private final PlayerAi ai = new PlayerAi(this);
public PlayerEntity(EntityModel model, int eid) {
public PlayerEntity(EntityModel model, int eid)
{
super(model, eid);
pos.setStepTime(0.25);

@ -20,7 +20,7 @@ public class LevelGenerator {
@SuppressWarnings("fallthrough")
public static Level build(World world, long seed, int complexity, MapTheme theme, boolean lastLevel)
public static Level build(World world, long seed, int complexity, MapTheme theme, boolean lastLevel) throws WorldGenError
{
Log.f3("Generating level of complexity: " + complexity);
@ -31,7 +31,9 @@ public class LevelGenerator {
final ScratchMap map = new ScratchMap(max_size, theme, rand);
// start
map.addRoom(Rooms.ENTRANCE, true);
if (!map.addRoom(Rooms.ENTRANCE, true)) {
throw new WorldGenError("Could not place entrance room.");
}
for (int i = 0; i < 1 + complexity / 2 + rand.nextInt((int) (1 + complexity * 0.2)); i++) {
map.addRoom(Rooms.BASIC, false);
@ -39,50 +41,60 @@ public class LevelGenerator {
if (rand.nextInt(7) > 0) map.addRoom(Rooms.DEAD_END, false);
}
if (!lastLevel) map.addRoom(Rooms.EXIT, true);
if (!lastLevel) {
if (!map.addRoom(Rooms.EXIT, true)) {
throw new WorldGenError("Could not place exit room.");
}
}
if (lastLevel) {
if (!map.addRoom(Rooms.BOSS_ROOM, true)) {
throw new WorldGenError("Could not place boss room.");
}
}
map.buildCorridors();
switch(complexity) {
switch (complexity) {
default:
case 3:
case 2:
if(rand.nextInt(2)==0) map.dropInMap(Items.CLUB.createItem(), 50);
if (rand.nextInt(2) == 0) map.dropInMap(Items.CLUB.createItemDamaged(60), 50);
case 1:
case 0:
if(rand.nextInt(2)==0) map.dropInMap(Items.ROCK.createItem(), 50);
if (rand.nextInt(2) == 0) map.dropInMap(Items.ROCK.createItemDamaged(10), 50);
}
if(complexity == 6) {
map.dropInMap(Items.SWORD.createItem(), 200);
if (complexity == 6) {
map.dropInMap(Items.SWORD.createItemDamaged(40), 200);
}
if(complexity == 5) {
map.dropInMap(Items.HAMMER.createItem(), 100);
if (complexity == 5) {
map.dropInMap(Items.HAMMER.createItemDamaged(40), 100);
}
final Coord size = map.getNeededSize();
final Level lvl = new Level(size.x, size.y);
// entities - random rats
map.writeToLevel(lvl);
// TODO tmp
// spawn rats
for (int i = 0; i < 3 + complexity + rand.nextInt(1 + complexity); i++) {
Entity e;
// TODO entities in ScratchMap itself
if (rand.nextInt((int) (complexity / 1.5) + 1) != 0) {
e = Entities.RAT_BROWN.createEntity();
} else {
e = Entities.RAT_GRAY.createEntity();
}
final Coord pos = Coord.make(0, 0);
for (int i = 0; i < 3 + complexity + rand.nextInt(1 + complexity); i++) {
map.putEntityInMap(e, 20);
}
final Entity e = Entities.RAT.createEntity(world);
for (int j = 0; j < 20; j++) {
pos.x = rand.nextInt(lvl.getWidth());
pos.y = rand.nextInt(lvl.getHeight());
final Coord size = map.getNeededSize();
final Level lvl = new Level(size.x, size.y);
lvl.setWorld(world); // important for creating entities
if (lvl.addEntity(e, pos)) break;
}
}
map.writeToLevel(lvl);
return lvl;
}

@ -13,5 +13,5 @@ import mightypork.gamecore.util.math.algo.Coord;
*/
public interface RoomBuilder {
RoomDesc buildToFit(ScratchMap map, MapTheme theme, Random rand, Coord center);
RoomDesc buildToFit(ScratchMap map, MapTheme theme, Random rand, Coord center) throws WorldGenError;
}

@ -14,6 +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.entity.Entity;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
@ -37,6 +38,9 @@ public class ScratchMap {
/** Coords to connect with corridors */
private final List<Coord> nodes = new ArrayList<>();
private final List<Coord> occupied = new ArrayList<>();
private final List<Entity> entities = new ArrayList<>();
private final PathFinder pathf = new PathFinder() {
@Override
@ -72,7 +76,7 @@ public class ScratchMap {
return 100;
default:
throw new RuntimeException("Unknown tile type: " + t.getType());
throw new WorldGenError("Unknown tile type: " + t.getType());
}
}
@ -132,7 +136,7 @@ public class ScratchMap {
}
public void addRoom(RoomBuilder rb, boolean critical)
public boolean addRoom(RoomBuilder rb, boolean critical)
{
final Coord center = Coord.make(0, 0);
@ -150,16 +154,16 @@ public class ScratchMap {
switch (rand.nextInt(4)) {
case 0:
center.x += 1 + (failed_total / 50);
center.x += (failed_total / 35);
break;
case 1:
center.x -= 1 + (failed_total / 50);
center.x -= (failed_total / 35);
break;
case 2:
center.y += 1 + (failed_total / 50);
center.y += (failed_total / 35);
break;
case 3:
center.y -= 1 + (failed_total / 50);
center.y -= (failed_total / 35);
}
final RoomDesc rd = rb.buildToFit(this, theme, rand, center);
@ -174,14 +178,18 @@ public class ScratchMap {
clampBounds();
nodes.add(center);
Log.f3("Placed room on " + Calc.ordinal(1+failed_total) + " try.");
// Log.f3("Placed room (failed " + failed_total + " x).");
return;
return true;
} else {
failed++;
failed_total++;
if (failed > 400) {
if (failed_total > 1000) {
return false;
}
if (failed > 300) {
Log.w("Faild to build room.");
if (critical) {
@ -192,16 +200,13 @@ public class ScratchMap {
clampBounds();
failed = 0;
Log.f3("Trying again.");
continue;
} else {
return;
return false;
}
}
if (failed_total > 1000) {
throw new RuntimeException("Generation error - could not place critical room.");
}
}
}
@ -226,7 +231,7 @@ public class ScratchMap {
public Tile getTile(Coord pos)
{
if (!isIn(pos)) {
throw new IndexOutOfBoundsException("Tile not in map: " + pos);
throw new WorldGenError("Tile not in map: " + pos);
}
return map[pos.y][pos.x];
@ -242,7 +247,7 @@ public class ScratchMap {
public boolean set(Coord pos, Tile tile)
{
if (!isIn(pos)) {
throw new IndexOutOfBoundsException("Tile not in map: " + pos);
throw new WorldGenError("Tile not in map: " + pos);
}
map[pos.y][pos.x] = tile;
@ -263,7 +268,7 @@ public class ScratchMap {
public void protect(Coord min, Coord max, TileProtectLevel prot)
{
if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max);
if (!isIn(min) || !isIn(max)) throw new WorldGenError("Tile(s) not in map: " + min + " , " + max);
final Coord c = Coord.make(0, 0);
for (c.x = min.x; c.x <= max.x; c.x++)
@ -274,7 +279,7 @@ public class ScratchMap {
public void fill(Coord min, Coord max, TileModel tm)
{
if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max);
if (!isIn(min) || !isIn(max)) throw new WorldGenError("Tile(s) not in map: " + min + " , " + max);
final Coord c = Coord.make(0, 0);
for (c.x = min.x; c.x <= max.x; c.x++)
@ -285,7 +290,7 @@ public class ScratchMap {
public void border(Coord min, Coord max, TileModel tm)
{
if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max);
if (!isIn(min) || !isIn(max)) throw new WorldGenError("Tile(s) not in map: " + min + " , " + max);
final Coord c = Coord.make(0, 0);
@ -543,6 +548,21 @@ public class ScratchMap {
final Coord exit = new Coord(exitPoint.x - genMin.x, exitPoint.y - genMin.y);
level.setExitPoint(exit);
for (final Entity e : entities) {
final Coord pos = e.getCoord().add(-genMin.x, -genMin.y);
if (!level.addEntityNear(e, pos)) {
final Tile t = level.getTile(pos);
//@formatter:off
throw new WorldGenError(
"Could not put entity into a level map: e_pos=" + pos
+ ", tile: " + Log.str(t)
+ ", t.wa " + t.isWalkable()
+ ", t.oc " + t.isOccupied()
+ ", ent.. " + e.getVisualName());
//@formatter:on
}
}
}
@ -560,22 +580,64 @@ public class ScratchMap {
public boolean dropInArea(Item item, Coord min, Coord max, int tries)
{
Coord pos = Coord.zero();
final Coord pos = Coord.zero();
for(int i=0; i<tries; i++) {
pos.x = min.x+rand.nextInt(max.x-min.x);
pos.y = min.y+rand.nextInt(max.y-min.y);
for (int i = 0; i < tries; i++) {
pos.x = min.x + rand.nextInt(max.x - min.x);
pos.y = min.y + rand.nextInt(max.y - min.y);
if (!isIn(pos)) continue;
Tile t = getTile(pos);
if(t.dropItem(item)) return true;
final Tile t = getTile(pos);
if (t.dropItem(item)) return true;
}
return false;
}
public void dropInMap(Item item, int tries)
public boolean dropInMap(Item item, int tries)
{
dropInArea(item, genMin, genMax, tries);
return dropInArea(item, genMin, genMax, tries);
}
public boolean putEntityInArea(Entity entity, Coord min, Coord max, int tries)
{
final Coord pos = Coord.zero();
for (int i = 0; i < tries; i++) {
pos.x = min.x + rand.nextInt(max.x - min.x);
pos.y = min.y + rand.nextInt(max.y - min.y);
if (!isIn(pos)) continue;
if (putEntity(entity, pos)) return true;
}
return false;
}
public boolean putEntityInMap(Entity entity, int tries)
{
return putEntityInArea(entity, genMin, genMax, tries);
}
public boolean putEntity(Entity entity, Coord pos)
{
if (!isIn(pos)) return false;
if (pos.dist(enterPoint) < 5) return false; // protected distance.
final Tile t = getTile(pos);
if (!t.isWalkable()) return false;
if (occupied.contains(pos)) return false;
occupied.add(pos.copy());
entity.setCoord(pos);
entities.add(entity);
return true;
}
}

@ -0,0 +1,34 @@
package mightypork.rogue.world.gen;
/**
* Error in world generation
*
* @author MightyPork
*/
public class WorldGenError extends RuntimeException {
public WorldGenError()
{
super();
}
public WorldGenError(String message, Throwable cause)
{
super(message, cause);
}
public WorldGenError(String message)
{
super(message);
}
public WorldGenError(Throwable cause)
{
super(cause);
}
}

@ -0,0 +1,36 @@
package mightypork.rogue.world.gen.rooms;
import java.util.Random;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.gen.MapTheme;
import mightypork.rogue.world.gen.ScratchMap;
import mightypork.rogue.world.gen.WorldGenError;
public class BossRoom extends SecretRoom {
@Override
protected int getDoorCount(Random rand)
{
return 2;
}
@Override
protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max)
{
final Entity boss = Entities.RAT_BOSS.createEntity();
if (!map.putEntityInArea(boss, min, max, 100)) {
// just place it anywhere then
if (!map.putEntityInMap(boss, 100)) {
throw new WorldGenError("Could not place boss.");
}
}
}
}

@ -11,4 +11,5 @@ public class Rooms {
public static final RoomBuilder DEAD_END = new DeadEndRoom();
public static final RoomBuilder ENTRANCE = new EntranceRoom();
public static final RoomBuilder EXIT = new ExitRoom();
public static final RoomBuilder BOSS_ROOM = new BossRoom();
}

@ -43,18 +43,18 @@ public class SecretRoom extends AbstractRectRoom {
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.dropInArea(Items.BONE.createItem(), min, max, 50);
map.dropInArea(Items.BONE.createItemDamaged(20), min, max, 50);
}
for (int i = 0; i < Calc.randInt(rand, 0, 1); i++) {
map.dropInArea(Items.ROCK.createItem(), min, max, 50);
map.dropInArea(Items.ROCK.createItemDamaged(30), min, max, 50);
}
for (int i = 0; i < Calc.randInt(rand, 0, 3); i++) {
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.dropInArea(Items.MEAT.createItem(), min, max, 50);
}
for (int i = 0; i < Calc.randInt(rand, 0, 3); i++) {
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.dropInArea(Items.CHEESE.createItem(), min, max, 50);
}
}

@ -128,7 +128,7 @@ public class MapView extends InputComponent implements DelegatingClient, MouseBu
{
if (!event.isOver(this)) return;
if(event.isButtonEvent()) {
if (event.isButtonEvent()) {
for (final MapInteractionPlugin p : plugins) {
if (p.onClick(event.getPos(), event.getButton(), event.isDown())) {
event.consume();

@ -161,19 +161,26 @@ public abstract class Item implements IonObjBlob {
return Log.str(getClass()) + " x " + getAmount();
}
public int getRemainingUses() {
public int getRemainingUses()
{
return uses;
}
public abstract int getMaxUses();
public void setRemainingUses(int uses) {
public void setRemainingUses(int uses)
{
this.uses = Calc.clamp(uses, 0, getMaxUses());
}
public void use() {
if(uses>0) uses--;
if(uses==0) consume();
public void use()
{
if (uses > 0) uses--;
if (uses == 0) consume();
}

@ -2,9 +2,11 @@ package mightypork.rogue.world.item;
import java.io.IOException;
import java.util.Random;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.gamecore.util.math.Calc;
/**
@ -18,8 +20,11 @@ public final class ItemModel {
public final int id;
public final Class<? extends Item> itemClass;
public static final Random rand = new Random();
public ItemModel(int id, Class<? extends Item> item) {
public ItemModel(int id, Class<? extends Item> item)
{
Items.register(id, this);
this.id = id;
this.itemClass = item;
@ -32,7 +37,7 @@ public final class ItemModel {
public Item createItem()
{
try {
Item itm = itemClass.getConstructor(ItemModel.class).newInstance(this);
final Item itm = itemClass.getConstructor(ItemModel.class).newInstance(this);
itm.setRemainingUses(itm.getMaxUses());
@ -58,4 +63,12 @@ public final class ItemModel {
tile.save(out);
}
public Item createItemDamaged(int minimalHealthPercent)
{
final Item item = createItem();
item.setRemainingUses(Calc.randInt(rand, (int) Math.ceil(item.getMaxUses() * (minimalHealthPercent / 100D)), item.getMaxUses()));
return item;
}
}

@ -9,13 +9,12 @@ public abstract class ItemRenderer {
protected final Item item;
public ItemRenderer(Item item) {
public ItemRenderer(Item item)
{
this.item = item;
}
public abstract void render(Rect r);
}

@ -34,12 +34,14 @@ public abstract class ItemBaseFood extends Item {
return ItemType.FOOD;
}
@Override
public boolean isDamageable()
{
return false;
}
@Override
public int getMaxUses()
{

@ -34,6 +34,7 @@ public abstract class ItemBaseWeapon extends Item {
return ItemType.WEAPON;
}
@Override
public boolean isDamageable()
{

@ -1,5 +1,6 @@
package mightypork.rogue.world.item.items.weapons;
import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer;
@ -9,28 +10,33 @@ import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemBone extends ItemBaseWeapon {
public ItemBone(ItemModel model) {
public ItemBone(ItemModel model)
{
super(model);
}
@Override
protected ItemRenderer makeRenderer()
{
return new QuadItemRenderer(this, Res.txq("item.bone"));
}
@Override
public int getAttackPoints()
{
return 1;
}
@Override
public int getMaxUses()
{
return 15;
}
@Override
public String getVisualName()
{

@ -1,5 +1,6 @@
package mightypork.rogue.world.item.items.weapons;
import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer;
@ -9,28 +10,33 @@ import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemClub extends ItemBaseWeapon {
public ItemClub(ItemModel model) {
public ItemClub(ItemModel model)
{
super(model);
}
@Override
protected ItemRenderer makeRenderer()
{
return new QuadItemRenderer(this, Res.txq("item.club"));
}
@Override
public int getAttackPoints()
{
return 3;
}
@Override
public int getMaxUses()
{
return 25;
}
@Override
public String getVisualName()
{

@ -1,5 +1,6 @@
package mightypork.rogue.world.item.items.weapons;
import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer;
@ -9,28 +10,33 @@ import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemHammer extends ItemBaseWeapon {
public ItemHammer(ItemModel model) {
public ItemHammer(ItemModel model)
{
super(model);
}
@Override
protected ItemRenderer makeRenderer()
{
return new QuadItemRenderer(this, Res.txq("item.hammer"));
}
@Override
public int getAttackPoints()
{
return 4;
}
@Override
public int getMaxUses()
{
return 50;
}
@Override
public String getVisualName()
{

@ -1,5 +1,6 @@
package mightypork.rogue.world.item.items.weapons;
import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer;
@ -9,28 +10,33 @@ import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemStone extends ItemBaseWeapon {
public ItemStone(ItemModel model) {
public ItemStone(ItemModel model)
{
super(model);
}
@Override
protected ItemRenderer makeRenderer()
{
return new QuadItemRenderer(this, Res.txq("item.stone"));
}
@Override
public int getAttackPoints()
{
return 2;
}
@Override
public int getMaxUses()
{
return 20;
}
@Override
public String getVisualName()
{

@ -1,5 +1,6 @@
package mightypork.rogue.world.item.items.weapons;
import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer;
@ -9,31 +10,36 @@ import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemSword extends ItemBaseWeapon {
public ItemSword(ItemModel model) {
public ItemSword(ItemModel model)
{
super(model);
}
@Override
protected ItemRenderer makeRenderer()
{
return new QuadItemRenderer(this, Res.txq("item.sword"));
}
@Override
public int getAttackPoints()
{
return 6;
}
@Override
public int getMaxUses()
{
return 100;
}
@Override
public String getVisualName()
{
return "Wooden Club";
return "Sword";
}
}

@ -3,11 +3,7 @@ package mightypork.rogue.world.item.render;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad;
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.rect.Rect;
import mightypork.gamecore.util.math.constraints.rect.mutable.RectVar;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.ItemRenderer;
@ -16,12 +12,9 @@ public class QuadItemRenderer extends ItemRenderer {
private final TxQuad txq;
private final RectVar rrect = Rect.makeVar();
private final Rect usesRect = rrect.topLeft().startRect().grow(Num.ZERO, rrect.width().perc(40), Num.ZERO, rrect.height().perc(8));
private final Num hAlpha = Num.make(0.7);
public QuadItemRenderer(Item item, TxQuad txq) {
public QuadItemRenderer(Item item, TxQuad txq)
{
super(item);
this.txq = txq;
}
@ -31,23 +24,6 @@ public class QuadItemRenderer extends ItemRenderer {
public void render(Rect r)
{
Render.quadTextured(r, txq);
if (item.isDamageable()) {
Color.pushAlpha(hAlpha);
rrect.setTo(r);
Render.quadColor(usesRect, RGB.BLACK);
double useRatio = (item.getRemainingUses() / (double)item.getMaxUses());
Color barColor = (useRatio > 0.6 ? RGB.GREEN : useRatio > 0.2 ? RGB.ORANGE : RGB.RED);
Render.quadColor(usesRect.shrinkRight(usesRect.width().value() * (1 - useRatio)), barColor);
Color.popAlpha();
}
}
}

@ -86,11 +86,13 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
private double timeSinceLastEntitySort;
public Level() {
public Level()
{
}
public Level(int width, int height) {
public Level(int width, int height)
{
size.setTo(width, height);
buildArray();
}
@ -308,6 +310,34 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
}
/**
* Try to add entity at given pos, then near the pos.
*
* @param entity the entity
* @param pos pos
* @return true if added
*/
public boolean addEntityNear(Entity entity, Coord pos)
{
if (addEntity(entity, pos)) return true;
// closer
for (int i = 0; i < 20; i++) {
final Coord c = pos.add(-1 + rand.nextInt(3), -1 + rand.nextInt(3));
if (addEntity(entity, c)) return true;
}
// further
for (int i = 0; i < 20; i++) {
final Coord c = pos.add(-2 + rand.nextInt(5), -2 + rand.nextInt(5));
if (addEntity(entity, c)) return true;
}
return false;
}
/**
* Try to add entity at given pos
*
@ -320,6 +350,9 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
final Tile t = getTile(pos);
if (!t.isWalkable() || t.isOccupied()) return false;
// set level to init EID
entity.setLevel(this);
if (entityMap.containsKey(entity.getEntityId())) {
Log.w("Entity already in level.");
return false;
@ -330,7 +363,6 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
if (entity instanceof PlayerEntity) playerCount++;
// join to level & world
entity.setLevel(this);
occupyTile(entity.getCoord());
entity.setCoord(pos);

@ -1,7 +1,11 @@
package mightypork.rogue.world.tile;
import java.util.Collection;
import mightypork.gamecore.util.math.Easing;
import mightypork.gamecore.util.math.constraints.num.Num;
import mightypork.gamecore.util.math.constraints.num.proxy.NumBoundAdapter;
import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.gamecore.util.math.constraints.rect.proxy.RectBoundAdapter;
import mightypork.gamecore.util.math.timing.Animator;
@ -12,27 +16,26 @@ import mightypork.rogue.world.level.render.TileRenderContext;
public class DroppedItemRenderer {
private Animator itemAnim = new AnimatorBounce(2, Easing.SINE_BOTH);
private final Animator itemAnim = new AnimatorBounce(2, Easing.SINE_BOTH);
// 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 NumBoundAdapter offsAdapter = new NumBoundAdapter();
private final Rect itemRect = tileRectAdapter.shrink(tileRectAdapter.height().perc(12)).moveY(offsAdapter.neg().mul(tileRectAdapter.height().mul(0.2)));
public Animator getItemAnim()
public void render(Collection<Item> items, TileRenderContext context)
{
if (itemAnim == null) {
itemAnim = new AnimatorBounce(2, Easing.SINE_BOTH);
}
tileRectAdapter.setRect(context);
int cnt = 0;
for (final Item i : items) {
return itemAnim;
}
offsAdapter.setNum(Num.make((itemAnim.value() + (cnt % 3) * 0.1)));
i.render(itemRect);
public void render(Item item, TileRenderContext context)
{
tileRectAdapter.setRect(context);
item.render(itemRect);
cnt++;
}
}

@ -105,7 +105,7 @@ public abstract class TileRenderer implements Updateable {
public void renderUnexploredFog(TileRenderContext context)
{
if(!Config.RENDER_UFOG) return;
if (!Config.RENDER_UFOG) return;
// TODO cache values, update neighbouring tiles upon "explored" flag changed.

@ -22,7 +22,8 @@ public abstract class TileWithItems extends Tile {
protected final Stack<Item> items = new Stack<>();
public TileWithItems(TileModel model) {
public TileWithItems(TileModel model)
{
super(model);
}
@ -31,7 +32,7 @@ public abstract class TileWithItems extends Tile {
public void renderExtra(TileRenderContext context)
{
if ((isExplored() || !Config.RENDER_UFOG) && !items.isEmpty()) {
itemRenderer.render(items.peek(), context);
itemRenderer.render(items, context);
}
}

Loading…
Cancel
Save