+ rats & improvements; damaged items;

v5stable
Ondřej Hruška 10 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. 2
      src/mightypork/gamecore/gui/components/InputComponent.java
  5. 4
      src/mightypork/gamecore/gui/components/LayoutComponent.java
  6. 18
      src/mightypork/gamecore/gui/components/painters/TextPainter.java
  7. 12
      src/mightypork/gamecore/gui/screens/Overlay.java
  8. 6
      src/mightypork/gamecore/resources/fonts/FontRenderer.java
  9. 14
      src/mightypork/gamecore/resources/fonts/impl/CachedFont.java
  10. 10
      src/mightypork/gamecore/util/math/Calc.java
  11. 4
      src/mightypork/gamecore/util/math/constraints/num/proxy/NumBoundAdapter.java
  12. 2
      src/mightypork/gamecore/util/math/timing/Animator.java
  13. 1
      src/mightypork/rogue/Config.java
  14. 5
      src/mightypork/rogue/Res.java
  15. 5
      src/mightypork/rogue/screens/game/HeartBar.java
  16. 17
      src/mightypork/rogue/screens/game/HudLayer.java
  17. 41
      src/mightypork/rogue/screens/game/InvLayer.java
  18. 27
      src/mightypork/rogue/screens/game/InvSlot.java
  19. 2
      src/mightypork/rogue/screens/game/NavButton.java
  20. 22
      src/mightypork/rogue/screens/game/ScreenGame.java
  21. 17
      src/mightypork/rogue/screens/game/WorldConsoleRenderer.java
  22. 14
      src/mightypork/rogue/world/Inventory.java
  23. 14
      src/mightypork/rogue/world/PlayerControl.java
  24. 2
      src/mightypork/rogue/world/PlayerInfo.java
  25. 15
      src/mightypork/rogue/world/World.java
  26. 16
      src/mightypork/rogue/world/WorldConsole.java
  27. 14
      src/mightypork/rogue/world/WorldCreator.java
  28. 8
      src/mightypork/rogue/world/entity/Entities.java
  29. 7
      src/mightypork/rogue/world/entity/Entity.java
  30. 12
      src/mightypork/rogue/world/entity/EntityModel.java
  31. 48
      src/mightypork/rogue/world/entity/entities/BossRatAi.java
  32. 37
      src/mightypork/rogue/world/entity/entities/BrownRatAi.java
  33. 92
      src/mightypork/rogue/world/entity/entities/EntityBossRat.java
  34. 92
      src/mightypork/rogue/world/entity/entities/EntityBrownRat.java
  35. 36
      src/mightypork/rogue/world/entity/entities/EntityGrayRat.java
  36. 4
      src/mightypork/rogue/world/entity/entities/GrayRatAi.java
  37. 6
      src/mightypork/rogue/world/entity/entities/PlayerEntity.java
  38. 64
      src/mightypork/rogue/world/gen/LevelGenerator.java
  39. 2
      src/mightypork/rogue/world/gen/RoomBuilder.java
  40. 126
      src/mightypork/rogue/world/gen/ScratchMap.java
  41. 34
      src/mightypork/rogue/world/gen/WorldGenError.java
  42. 36
      src/mightypork/rogue/world/gen/rooms/BossRoom.java
  43. 1
      src/mightypork/rogue/world/gen/rooms/Rooms.java
  44. 8
      src/mightypork/rogue/world/gen/rooms/SecretRoom.java
  45. 12
      src/mightypork/rogue/world/gui/MapView.java
  46. 25
      src/mightypork/rogue/world/item/Item.java
  47. 17
      src/mightypork/rogue/world/item/ItemModel.java
  48. 9
      src/mightypork/rogue/world/item/ItemRenderer.java
  49. 2
      src/mightypork/rogue/world/item/items/ItemBaseFood.java
  50. 1
      src/mightypork/rogue/world/item/items/ItemBaseWeapon.java
  51. 2
      src/mightypork/rogue/world/item/items/food/ItemCheese.java
  52. 2
      src/mightypork/rogue/world/item/items/food/ItemMeat.java
  53. 2
      src/mightypork/rogue/world/item/items/food/ItemSandwich.java
  54. 16
      src/mightypork/rogue/world/item/items/weapons/ItemBone.java
  55. 16
      src/mightypork/rogue/world/item/items/weapons/ItemClub.java
  56. 16
      src/mightypork/rogue/world/item/items/weapons/ItemHammer.java
  57. 16
      src/mightypork/rogue/world/item/items/weapons/ItemStone.java
  58. 18
      src/mightypork/rogue/world/item/items/weapons/ItemSword.java
  59. 28
      src/mightypork/rogue/world/item/render/QuadItemRenderer.java
  60. 40
      src/mightypork/rogue/world/level/Level.java
  61. 31
      src/mightypork/rogue/world/tile/DroppedItemRenderer.java
  62. 2
      src/mightypork/rogue/world/tile/TileRenderer.java
  63. 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; private int disableLevel = 0;
public BaseComponent() { public BaseComponent()
{
enableCaching(false); enableCaching(false);
} }

@ -6,7 +6,7 @@ import mightypork.gamecore.gui.Enableable;
public abstract class InputComponent extends BaseComponent implements Enableable, ToggleableClient { public abstract class InputComponent extends BaseComponent implements Enableable, ToggleableClient {
@Override @Override
public boolean isListening() public boolean isListening()
{ {

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

@ -41,7 +41,8 @@ public class TextPainter extends BaseComponent {
/** /**
* @param font font to use * @param font font to use
*/ */
public TextPainter(GLFont font) { public TextPainter(GLFont font)
{
this(font, AlignX.LEFT, RGB.WHITE); this(font, AlignX.LEFT, RGB.WHITE);
} }
@ -54,7 +55,8 @@ public class TextPainter extends BaseComponent {
* @param color default color * @param color default color
* @param text drawn text * @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)); this(font, align, color, new StringWrapper(text));
} }
@ -67,7 +69,8 @@ public class TextPainter extends BaseComponent {
* @param color default color * @param color default color
* @param text text provider * @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.font = new FontRenderer(font);
this.color = color; this.color = color;
this.align = align; this.align = align;
@ -80,7 +83,8 @@ public class TextPainter extends BaseComponent {
* @param align text align * @param align text align
* @param color default color * @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); this(font, align, color, (StringProvider) null);
} }
@ -92,8 +96,8 @@ public class TextPainter extends BaseComponent {
final String str = text.getString(); final String str = text.getString();
Num shrX = height().perc(xPaddingPerc); final Num shrX = height().perc(xPaddingPerc);
Num shrY = height().perc(yPaddingPerc); final Num shrY = height().perc(yPaddingPerc);
final Rect rect = getRect().shrink(shrX, shrY); final Rect rect = getRect().shrink(shrX, shrY);
@ -101,7 +105,7 @@ public class TextPainter extends BaseComponent {
font.draw(str, rect.round(), align, shadowColor); 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); font.draw(str, r, align, color);
if (Config.DEBUG_FONT_RENDER) Render.quadColor(r, RGB.PINK.withAlpha(0.4)); 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 * @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 visible = true;
private boolean enabled = true; private boolean enabled = true;
@ -87,19 +88,22 @@ public abstract class Overlay extends AppSubModule implements Comparable<Overlay
root.setVisible(visible); root.setVisible(visible);
} }
@Override @Override
public void enable(boolean yes) public void enable(boolean yes)
{ {
this.enabled = yes; this.enabled = yes;
root.enable(yes); root.enable(yes);
} }
@Override @Override
public boolean isEnabled() public boolean isEnabled()
{ {
return enabled; return enabled;
} }
/** /**
* Get rendering layer * Get rendering layer
* *
@ -126,7 +130,7 @@ public abstract class Overlay extends AppSubModule implements Comparable<Overlay
@Override @Override
public void render() public void render()
{ {
if(!isVisible()) return; if (!isVisible()) return;
for (final Renderable r : rendered) { for (final Renderable r : rendered) {
r.render(); r.render();
@ -137,7 +141,7 @@ public abstract class Overlay extends AppSubModule implements Comparable<Overlay
@Override @Override
public void update(double delta) public void update(double delta)
{ {
if(!isEnabled()) return; if (!isEnabled()) return;
for (final Updateable u : updated) { for (final Updateable u : updated) {
u.update(delta); u.update(delta);

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

@ -90,7 +90,8 @@ public class CachedFont implements GLFont {
* @param filter used Gl filter * @param filter used Gl filter
* @param chars chars to load * @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()); this(font, antialias, filter, (" " + chars).toCharArray());
} }
@ -103,7 +104,8 @@ public class CachedFont implements GLFont {
* @param filter used Gl filter * @param filter used Gl filter
* @param chars chars to load * @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(); GLUtils.checkGLContext();
this.font = font; this.font = font;
@ -163,7 +165,8 @@ public class CachedFont implements GLFont {
public int height; public int height;
public LoadedGlyph(char c, BufferedImage image) { public LoadedGlyph(char c, BufferedImage image)
{
this.image = image; this.image = image;
this.c = c; this.c = c;
this.width = image.getWidth(); 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); byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI);
} else { } 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(); byteBuffer.flip();
@ -413,7 +417,7 @@ public class CachedFont implements GLFont {
final float tymin = chtx.texPosY; final float tymin = chtx.texPosY;
final float draw_width = minx + chtx.width - minx; final float draw_width = minx + chtx.width - minx;
final float draw_height = chtx.height; 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 txmin01 = txmin / textureWidth;
final float tymin01 = tymin / textureHeight; final float tymin01 = tymin / textureHeight;

@ -671,11 +671,11 @@ public class Calc {
public static int randInt(Random rand, int low, int high) public static int randInt(Random rand, int low, int high)
{ {
int range = high - low + 1; int range = high - low + 1;
if(range < 1) range = 1; if (range < 1) range = 1;
return low + rand.nextInt(range); return low + rand.nextInt(range);
} }
/** /**
* Get ordinal version of numbers (1 = 1st, 5 = 5th etc.) * Get ordinal version of numbers (1 = 1st, 5 = 5th etc.)
* *
@ -691,8 +691,8 @@ public class Calc {
} }
return number + "th"; return number + "th";
} }
/** /**
* Format number with thousands separated by a dot. * Format number with thousands separated by a dot.
* *

@ -21,9 +21,9 @@ public class NumBoundAdapter extends NumAdapter implements PluggableNumBound {
@Override @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(); final double target = numAnim.getEnd();
numAnim.setTo(Calc.clamp(value, lowValue, highValue)); numAnim.setTo(Calc.clamp(value, lowValue, highValue));
numAnim.animate(target, numAnim.getDefaultDuration()); numAnim.animate((target < value ? highValue : lowValue), target, numAnim.getDefaultDuration());
} }

@ -24,7 +24,6 @@ public final class Config {
// property keys // property keys
private static final String PK_LAST_RUN_VERSION = "status.last_run_version"; private static final String PK_LAST_RUN_VERSION = "status.last_run_version";
private static final String PK_START_IN_FS = "cfg.start_in_fullscreen"; private static final String PK_START_IN_FS = "cfg.start_in_fullscreen";
/** /**

@ -108,7 +108,10 @@ public final class Res {
texture = textures.loadTexture("/res/img/sprites.png", FilterMode.NEAREST, WrapMode.CLAMP); texture = textures.loadTexture("/res/img/sprites.png", FilterMode.NEAREST, WrapMode.CLAMP);
grid = texture.grid(8, 8); grid = texture.grid(8, 8);
textures.add("sprite.player", grid.makeSheet(0, 0, 4, 1)); 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 // logo

@ -30,7 +30,8 @@ public class HeartBar extends BaseComponent {
* @param img_off * @param img_off
* @param align * @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(); super();
this.total = total; this.total = total;
this.active = active; this.active = active;
@ -60,7 +61,7 @@ public class HeartBar extends BaseComponent {
@Override @Override
protected void renderComponent() protected void renderComponent()
{ {
for (int i = 0; i < total.value(); i++) { for (int i = 0; i < total.value(); i++) {
index.setTo(i); index.setTo(i);

@ -39,7 +39,8 @@ public class HudLayer extends ScreenLayer {
private final ScreenGame gameScreen; private final ScreenGame gameScreen;
public HudLayer(ScreenGame screen) { public HudLayer(ScreenGame screen)
{
super(screen); super(screen);
this.gameScreen = screen; this.gameScreen = screen;
@ -55,13 +56,13 @@ public class HudLayer extends ScreenLayer {
private void buildConsole() private void buildConsole()
{ {
Num rh = root.height(); final Num rh = root.height();
Num rw = root.width(); final Num rw = root.width();
Rect consoleRect = root.shrink(rw.perc(2), Num.ZERO, rh.perc(6), rh.perc(16)); 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); wcr.setRect(consoleRect);
root.add(wcr); 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); root.add(levelText);
} }
@ -117,7 +118,7 @@ public class HudLayer extends ScreenLayer {
NavButton btn; NavButton btn;
nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.inventory"))); 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"))); nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.eat")));
btn.setAction(gameScreen.actionEat); 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); super(screen);
final Rect fg = root.shrink(root.height().perc(15)); 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); qp.setRect(root);
root.add(qp); root.add(qp);
@ -137,19 +140,7 @@ public class InvLayer extends ScreenLayer {
gl.put(txp2, pos, 0, 1, 1); gl.put(txp2, pos, 0, 1, 1);
txp2.setPaddingHPerc(0, 25); txp2.setPaddingHPerc(0, 25);
final Runnable leaveInv = new Runnable() { bindKey(new KeyStroke(Keys.ESCAPE), screen.actionToggleInv);
@Override
public void run()
{
if(!isEnabled()) return;
screen.setState(GScrState.WORLD);
}
};
bindKey(new KeyStroke(Keys.ESCAPE), leaveInv);
//bindKey(new KeyStroke(Keys.I), leaveInv);
// TODO needs some rewrite of keys system // TODO needs some rewrite of keys system
bindKey(new KeyStroke(Keys.E), new Runnable() { bindKey(new KeyStroke(Keys.E), new Runnable() {
@ -157,7 +148,7 @@ public class InvLayer extends ScreenLayer {
@Override @Override
public void run() public void run()
{ {
if(!isEnabled()) return; if (!isEnabled()) return;
if (WorldProvider.get().getPlayer().isDead()) return; if (WorldProvider.get().getPlayer().isDead()) return;
@ -198,7 +189,7 @@ public class InvLayer extends ScreenLayer {
@Override @Override
public void run() public void run()
{ {
if(!isEnabled()) return; if (!isEnabled()) return;
final int selected = getSelectedSlot(); final int selected = getSelectedSlot();
if (selected != -1) { if (selected != -1) {
@ -229,9 +220,9 @@ public class InvLayer extends ScreenLayer {
@Override @Override
public void run() public void run()
{ {
if(!isEnabled()) return; if (!isEnabled()) return;
int sel = getSelectedSlot(); final int sel = getSelectedSlot();
if (sel == -1) { if (sel == -1) {
selectSlot(0); selectSlot(0);
return; return;
@ -246,9 +237,9 @@ public class InvLayer extends ScreenLayer {
@Override @Override
public void run() public void run()
{ {
if(!isEnabled()) return; if (!isEnabled()) return;
int sel = getSelectedSlot(); final int sel = getSelectedSlot();
if (sel == -1) { if (sel == -1) {
selectSlot(0); selectSlot(0);
return; return;
@ -263,9 +254,9 @@ public class InvLayer extends ScreenLayer {
@Override @Override
public void run() public void run()
{ {
if(!isEnabled()) return; if (!isEnabled()) return;
int sel = getSelectedSlot(); final int sel = getSelectedSlot();
if (sel == -1) { if (sel == -1) {
selectSlot(0); selectSlot(0);
return; return;
@ -280,9 +271,9 @@ public class InvLayer extends ScreenLayer {
@Override @Override
public void run() public void run()
{ {
if(!isEnabled()) return; if (!isEnabled()) return;
int sel = getSelectedSlot(); final int sel = getSelectedSlot();
if (sel == -1) { if (sel == -1) {
selectSlot(0); selectSlot(0);
return; return;

@ -8,8 +8,10 @@ import mightypork.gamecore.gui.components.painters.TextPainter;
import mightypork.gamecore.render.Render; import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.gamecore.util.math.Calc; 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.color.pal.RGB;
import mightypork.gamecore.util.math.constraints.num.Num; 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.gamecore.util.math.constraints.rect.caching.RectCache;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.rogue.world.World.PlayerFacade; import mightypork.rogue.world.World.PlayerFacade;
@ -41,8 +43,12 @@ public class InvSlot extends ClickableComponent {
private final RectCache rbTxRect; private final RectCache rbTxRect;
private final RectCache rtTxRect; 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(); super();
this.txBase = Res.txq("inv.slot.base"); this.txBase = Res.txq("inv.slot.base");
this.txSelected = Res.txq("inv.slot.selected"); 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.uiRect = getRect().shrink(height().perc(16)).cached();
this.itemRect = uiRect.shrink(Num.ZERO, height().perc(14), height().perc(14), Num.ZERO).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 //@formatter:off
this.rbTxRect = uiRect.bottomEdge() this.rbTxRect = uiRect.bottomEdge()
.moveY(uiRect.height().perc(1*(30/7D))) .moveY(uiRect.height().perc(1*(30/7D)))
@ -134,11 +142,26 @@ public class InvSlot extends ClickableComponent {
rtTxP.render(); rtTxP.render();
} else if (itm.getType() == ItemType.WEAPON) { } else if (itm.getType() == ItemType.WEAPON) {
int atk = itm.getAttackPoints(); final int atk = itm.getAttackPoints();
rtTxP.setText((atk >= 0 ? "+" : "") + atk); rtTxP.setText((atk >= 0 ? "+" : "") + atk);
rtTxP.setColor(RGB.CYAN); rtTxP.setColor(RGB.CYAN);
rtTxP.render(); 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; bg = base;
} }
if(!isEnabled()) bg = base; // override effects if (!isEnabled()) bg = base; // override effects
Render.quadTextured(this, bg); Render.quadTextured(this, bg);
Render.quadTextured(this, fg); Render.quadTextured(this, fg);

@ -4,12 +4,14 @@ package mightypork.rogue.screens.game;
import java.util.Random; import java.util.Random;
import mightypork.gamecore.app.AppAccess; import mightypork.gamecore.app.AppAccess;
import mightypork.gamecore.eventbus.events.Updateable;
import mightypork.gamecore.gui.Action; import mightypork.gamecore.gui.Action;
import mightypork.gamecore.gui.ActionGroup; import mightypork.gamecore.gui.ActionGroup;
import mightypork.gamecore.gui.screens.LayeredScreen; import mightypork.gamecore.gui.screens.LayeredScreen;
import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.KeyStroke;
import mightypork.gamecore.input.Keys; import mightypork.gamecore.input.Keys;
import mightypork.rogue.Config; import mightypork.rogue.Config;
import mightypork.rogue.world.World.PlayerFacade;
import mightypork.rogue.world.WorldProvider; import mightypork.rogue.world.WorldProvider;
import mightypork.rogue.world.events.WorldPauseRequest; import mightypork.rogue.world.events.WorldPauseRequest;
import mightypork.rogue.world.events.WorldPauseRequest.PauseAction; import mightypork.rogue.world.events.WorldPauseRequest.PauseAction;
@ -31,6 +33,8 @@ public class ScreenGame extends LayeredScreen {
private InvLayer invLayer; private InvLayer invLayer;
private HudLayer hudLayer; private HudLayer hudLayer;
private WorldLayer worldLayer;
private GScrState state = GScrState.WORLD; private GScrState state = GScrState.WORLD;
private final ActionGroup worldActions = new ActionGroup(); private final ActionGroup worldActions = new ActionGroup();
@ -40,16 +44,18 @@ public class ScreenGame extends LayeredScreen {
@Override @Override
public void execute() 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 @Override
public void execute() 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) * Set gui state (overlay)
@ -122,7 +126,8 @@ public class ScreenGame extends LayeredScreen {
} }
public ScreenGame(AppAccess app) { public ScreenGame(AppAccess app)
{
super(app); super(app);
addLayer(invLayer = new InvLayer(this)); addLayer(invLayer = new InvLayer(this));
@ -152,17 +157,16 @@ public class ScreenGame extends LayeredScreen {
bindKey(new KeyStroke(Keys.PAUSE), actionTogglePause); bindKey(new KeyStroke(Keys.PAUSE), actionTogglePause);
bindKey(new KeyStroke(Keys.SPACE), 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.E), actionEat);
bindKey(new KeyStroke(Keys.M), actionToggleMinimap); bindKey(new KeyStroke(Keys.M), actionToggleMinimap);
bindKey(new KeyStroke(Keys.Z), actionToggleZoom); bindKey(new KeyStroke(Keys.Z), actionToggleZoom);
// add as actions - enableables. // add as actions - enableables.
worldActions.add(worldLayer); worldActions.add(worldLayer);
worldActions.add(hudLayer); worldActions.add(hudLayer);
worldActions.add(actionEat); worldActions.add(actionEat);
worldActions.add(actionInv);
worldActions.add(actionToggleMinimap); worldActions.add(actionToggleMinimap);
worldActions.add(actionTogglePause); worldActions.add(actionTogglePause);
worldActions.add(actionToggleZoom); worldActions.add(actionToggleZoom);

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

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

@ -12,6 +12,7 @@ import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityType; import mightypork.rogue.world.entity.EntityType;
import mightypork.rogue.world.entity.modules.EntityMoveListener; import mightypork.rogue.world.entity.modules.EntityMoveListener;
import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
public abstract class PlayerControl { public abstract class PlayerControl {
@ -104,7 +105,7 @@ public abstract class PlayerControl {
public boolean clickTile(Vect pos) public boolean clickTile(Vect pos)
{ {
if (pos.dist(getPlayer().getVisualPos().add(0.5, 0.5)).value() < 1.5) { if (pos.dist(getPlayer().getVisualPos().add(0.5, 0.5)).value() < 1.5) {
return doClickTile(pos); return doClickTile(pos);
} }
@ -115,15 +116,20 @@ public abstract class PlayerControl {
private boolean doClickTile(Vect pos) 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); final Entity prey = getLevel().getClosestEntity(pos, EntityType.MONSTER, 1);
if (prey != null) { if (prey != null) {
getPlayer().attack(prey); getPlayer().attack(prey);
return true; return true;
} }
//2nd try to click tile return false;
return getLevel().getTile(Coord.fromVect(pos)).onClick();
} }

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

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

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

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

@ -6,8 +6,10 @@ import java.util.Collection;
import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput; 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.PlayerEntity;
import mightypork.rogue.world.entity.entities.RatEntity;
/** /**
@ -20,7 +22,9 @@ public final class Entities {
private static final EntityModel[] entities = new EntityModel[256]; private static final EntityModel[] entities = new EntityModel[256];
public static final EntityModel PLAYER = new EntityModel(1, PlayerEntity.class); 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) 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(); protected final Random rand = new Random();
/** Entity ID */ /** Entity ID */
private int entityId; private int entityId = -1;
private final Map<String, EntityModule> modules = new HashMap<>(); private final Map<String, EntityModule> modules = new HashMap<>();
@ -123,6 +123,10 @@ public abstract class Entity implements IonObjBundled, Updateable {
public void setLevel(Level level) public void setLevel(Level level)
{ {
if (level != null && entityId < 0) {
entityId = level.getWorld().getNewEID();
}
if (level != null) level.freeTile(getCoord()); if (level != null) level.freeTile(getCoord());
this.level = level; this.level = level;
@ -266,5 +270,6 @@ public abstract class Entity implements IonObjBundled, Updateable {
return despawnDelay; return despawnDelay;
} }
public abstract String getVisualName(); 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 public Entity loadEntity(IonInput in) throws IOException
{ {
final IonBundle bundle = in.readBundle(); 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; import mightypork.rogue.world.item.Items;
public class RatEntity extends Entity { public class EntityGrayRat extends Entity {
/** Navigation PFC */ private final PathFinder pathf = new EntityPathFinder(this);
private PathFinder pathf;
private final RatAi ai = new RatAi(this); private final GrayRatAi ai = new GrayRatAi(this);
private EntityRenderer renderer; private EntityRenderer renderer;
public RatEntity(EntityModel model, int eid) { public EntityGrayRat(EntityModel model, int eid)
{
super(model, eid); super(model, eid);
addModule("ai", ai); addModule("ai", ai);
@ -32,7 +32,7 @@ public class RatEntity extends Entity {
setDespawnDelay(1); setDespawnDelay(1);
health.setMaxHealth(5); 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); health.setHitCooldownTime(0.3);
} }
@ -40,10 +40,6 @@ public class RatEntity extends Entity {
@Override @Override
public PathFinder getPathFinder() public PathFinder getPathFinder()
{ {
if (pathf == null) {
pathf = new EntityPathFinder(this);
}
return pathf; return pathf;
} }
@ -59,41 +55,35 @@ public class RatEntity extends Entity {
protected EntityRenderer getRenderer() protected EntityRenderer getRenderer()
{ {
if (renderer == null) { if (renderer == null) {
renderer = new EntityRendererMobLR(this, "sprite.rat"); renderer = new EntityRendererMobLR(this, "sprite.rat.gray");
} }
return renderer; return renderer;
} }
@Override
public void onKilled()
{
super.onKilled();
}
@Override @Override
public void onCorpseRemoved() public void onCorpseRemoved()
{ {
// drop rat stuff // drop rat stuff
if(rand.nextInt(7) == 0) { if (rand.nextInt(6) == 0) {
getLevel().dropNear(getCoord(), Items.BONE.createItem()); getLevel().dropNear(getCoord(), Items.BONE.createItemDamaged(10));
return; return;
} }
if(rand.nextInt(3) == 0) { if (rand.nextInt(7) == 0) {
getLevel().dropNear(getCoord(), Items.MEAT.createItem()); getLevel().dropNear(getCoord(), Items.MEAT.createItem());
return; return;
} }
if(rand.nextInt(2) == 0) { if (rand.nextInt(3) == 0) {
getLevel().dropNear(getCoord(), Items.CHEESE.createItem()); getLevel().dropNear(getCoord(), Items.CHEESE.createItem());
return; return;
} }
} }
@Override @Override
public String getVisualName() public String getVisualName()
{ {

@ -4,9 +4,9 @@ package mightypork.rogue.world.entity.entities;
import mightypork.rogue.world.entity.Entity; 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); super(entity);

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

@ -20,7 +20,7 @@ public class LevelGenerator {
@SuppressWarnings("fallthrough") @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); Log.f3("Generating level of complexity: " + complexity);
@ -31,7 +31,9 @@ public class LevelGenerator {
final ScratchMap map = new ScratchMap(max_size, theme, rand); final ScratchMap map = new ScratchMap(max_size, theme, rand);
// start // 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++) { for (int i = 0; i < 1 + complexity / 2 + rand.nextInt((int) (1 + complexity * 0.2)); i++) {
map.addRoom(Rooms.BASIC, false); map.addRoom(Rooms.BASIC, false);
@ -39,51 +41,61 @@ public class LevelGenerator {
if (rand.nextInt(7) > 0) map.addRoom(Rooms.DEAD_END, false); 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(); map.buildCorridors();
switch(complexity) { switch (complexity) {
default: default:
case 3: case 3:
case 2: 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 1:
case 0: 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) { if (complexity == 6) {
map.dropInMap(Items.SWORD.createItem(), 200); map.dropInMap(Items.SWORD.createItemDamaged(40), 200);
} }
if(complexity == 5) { if (complexity == 5) {
map.dropInMap(Items.HAMMER.createItem(), 100); map.dropInMap(Items.HAMMER.createItemDamaged(40), 100);
} }
final Coord size = map.getNeededSize(); // entities - random rats
final Level lvl = new Level(size.x, size.y);
map.writeToLevel(lvl);
// TODO tmp
// spawn rats
// TODO entities in ScratchMap itself
final Coord pos = Coord.make(0, 0);
for (int i = 0; i < 3 + complexity + rand.nextInt(1 + complexity); i++) { for (int i = 0; i < 3 + complexity + rand.nextInt(1 + complexity); i++) {
Entity e;
final Entity e = Entities.RAT.createEntity(world); if (rand.nextInt((int) (complexity / 1.5) + 1) != 0) {
e = Entities.RAT_BROWN.createEntity();
for (int j = 0; j < 20; j++) { } else {
pos.x = rand.nextInt(lvl.getWidth()); e = Entities.RAT_GRAY.createEntity();
pos.y = rand.nextInt(lvl.getHeight());
if (lvl.addEntity(e, pos)) break;
} }
map.putEntityInMap(e, 20);
} }
final Coord size = map.getNeededSize();
final Level lvl = new Level(size.x, size.y);
lvl.setWorld(world); // important for creating entities
map.writeToLevel(lvl);
return lvl; return lvl;
} }
} }

@ -13,5 +13,5 @@ import mightypork.gamecore.util.math.algo.Coord;
*/ */
public interface RoomBuilder { 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.Step;
import mightypork.gamecore.util.math.algo.pathfinding.Heuristic; import mightypork.gamecore.util.math.algo.pathfinding.Heuristic;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder; import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
@ -37,6 +38,9 @@ public class ScratchMap {
/** Coords to connect with corridors */ /** Coords to connect with corridors */
private final List<Coord> nodes = new ArrayList<>(); 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() { private final PathFinder pathf = new PathFinder() {
@Override @Override
@ -72,7 +76,7 @@ public class ScratchMap {
return 100; return 100;
default: 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); final Coord center = Coord.make(0, 0);
@ -150,16 +154,16 @@ public class ScratchMap {
switch (rand.nextInt(4)) { switch (rand.nextInt(4)) {
case 0: case 0:
center.x += 1 + (failed_total / 50); center.x += (failed_total / 35);
break; break;
case 1: case 1:
center.x -= 1 + (failed_total / 50); center.x -= (failed_total / 35);
break; break;
case 2: case 2:
center.y += 1 + (failed_total / 50); center.y += (failed_total / 35);
break; break;
case 3: case 3:
center.y -= 1 + (failed_total / 50); center.y -= (failed_total / 35);
} }
final RoomDesc rd = rb.buildToFit(this, theme, rand, center); final RoomDesc rd = rb.buildToFit(this, theme, rand, center);
@ -174,14 +178,18 @@ public class ScratchMap {
clampBounds(); clampBounds();
nodes.add(center); 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 { } else {
failed++; failed++;
failed_total++; failed_total++;
if (failed > 400) { if (failed_total > 1000) {
return false;
}
if (failed > 300) {
Log.w("Faild to build room."); Log.w("Faild to build room.");
if (critical) { if (critical) {
@ -192,16 +200,13 @@ public class ScratchMap {
clampBounds(); clampBounds();
failed = 0; failed = 0;
Log.f3("Trying again.");
continue; continue;
} else { } 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) public Tile getTile(Coord pos)
{ {
if (!isIn(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]; return map[pos.y][pos.x];
@ -242,7 +247,7 @@ public class ScratchMap {
public boolean set(Coord pos, Tile tile) public boolean set(Coord pos, Tile tile)
{ {
if (!isIn(pos)) { 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; map[pos.y][pos.x] = tile;
@ -263,7 +268,7 @@ public class ScratchMap {
public void protect(Coord min, Coord max, TileProtectLevel prot) 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); final Coord c = Coord.make(0, 0);
for (c.x = min.x; c.x <= max.x; c.x++) 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) 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); final Coord c = Coord.make(0, 0);
for (c.x = min.x; c.x <= max.x; c.x++) 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) 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); final Coord c = Coord.make(0, 0);
@ -540,9 +545,24 @@ public class ScratchMap {
final Coord entrance = new Coord(enterPoint.x - genMin.x, enterPoint.y - genMin.y); final Coord entrance = new Coord(enterPoint.x - genMin.x, enterPoint.y - genMin.y);
level.setEnterPoint(entrance); level.setEnterPoint(entrance);
final Coord exit = new Coord(exitPoint.x - genMin.x, exitPoint.y - genMin.y); final Coord exit = new Coord(exitPoint.x - genMin.x, exitPoint.y - genMin.y);
level.setExitPoint(exit); 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
}
}
} }
@ -556,26 +576,68 @@ public class ScratchMap {
{ {
exitPoint.setTo(pos); exitPoint.setTo(pos);
} }
public boolean dropInArea(Item item, Coord min, Coord max, int tries) 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++) { for (int i = 0; i < tries; i++) {
pos.x = min.x+rand.nextInt(max.x-min.x); pos.x = min.x + rand.nextInt(max.x - min.x);
pos.y = min.y+rand.nextInt(max.y-min.y); pos.y = min.y + rand.nextInt(max.y - min.y);
if (!isIn(pos)) continue;
Tile t = getTile(pos); final Tile t = getTile(pos);
if(t.dropItem(item)) return true; if (t.dropItem(item)) return true;
} }
return false; return false;
} }
public void dropInMap(Item item, int tries) public boolean dropInMap(Item item, int 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)
{ {
dropInArea(item, genMin, genMax, tries); 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 DEAD_END = new DeadEndRoom();
public static final RoomBuilder ENTRANCE = new EntranceRoom(); public static final RoomBuilder ENTRANCE = new EntranceRoom();
public static final RoomBuilder EXIT = new ExitRoom(); 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++) { 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++) { 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); 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); map.dropInArea(Items.CHEESE.createItem(), min, max, 50);
} }
} }

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

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

@ -2,9 +2,11 @@ package mightypork.rogue.world.item;
import java.io.IOException; import java.io.IOException;
import java.util.Random;
import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput; 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 int id;
public final Class<? extends Item> itemClass; 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); Items.register(id, this);
this.id = id; this.id = id;
this.itemClass = item; this.itemClass = item;
@ -32,7 +37,7 @@ public final class ItemModel {
public Item createItem() public Item createItem()
{ {
try { try {
Item itm = itemClass.getConstructor(ItemModel.class).newInstance(this); final Item itm = itemClass.getConstructor(ItemModel.class).newInstance(this);
itm.setRemainingUses(itm.getMaxUses()); itm.setRemainingUses(itm.getMaxUses());
@ -58,4 +63,12 @@ public final class ItemModel {
tile.save(out); 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; protected final Item item;
public ItemRenderer(Item item)
public ItemRenderer(Item item) { {
this.item = item; this.item = item;
} }
public abstract void render(Rect r); public abstract void render(Rect r);
} }

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

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

@ -28,7 +28,7 @@ public class ItemCheese extends ItemBaseFood {
{ {
return 2; return 2;
} }
@Override @Override
public String getVisualName() public String getVisualName()

@ -28,7 +28,7 @@ public class ItemMeat extends ItemBaseFood {
{ {
return 3; return 3;
} }
@Override @Override
public String getVisualName() public String getVisualName()

@ -28,7 +28,7 @@ public class ItemSandwich extends ItemBaseFood {
{ {
return 6; return 6;
} }
@Override @Override
public String getVisualName() public String getVisualName()

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

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

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

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

@ -1,5 +1,6 @@
package mightypork.rogue.world.item.items.weapons; package mightypork.rogue.world.item.items.weapons;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel; import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer; import mightypork.rogue.world.item.ItemRenderer;
@ -8,32 +9,37 @@ import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemSword extends ItemBaseWeapon { public class ItemSword extends ItemBaseWeapon {
public ItemSword(ItemModel model) { public ItemSword(ItemModel model)
{
super(model); super(model);
} }
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.sword")); return new QuadItemRenderer(this, Res.txq("item.sword"));
} }
@Override @Override
public int getAttackPoints() public int getAttackPoints()
{ {
return 6; return 6;
} }
@Override @Override
public int getMaxUses() public int getMaxUses()
{ {
return 100; return 100;
} }
@Override @Override
public String getVisualName() 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.render.Render;
import mightypork.gamecore.resources.textures.TxQuad; 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.Rect;
import mightypork.gamecore.util.math.constraints.rect.mutable.RectVar;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.ItemRenderer; import mightypork.rogue.world.item.ItemRenderer;
@ -16,12 +12,9 @@ public class QuadItemRenderer extends ItemRenderer {
private final TxQuad txq; 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); super(item);
this.txq = txq; this.txq = txq;
} }
@ -31,23 +24,6 @@ public class QuadItemRenderer extends ItemRenderer {
public void render(Rect r) public void render(Rect r)
{ {
Render.quadTextured(r, txq); 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; private double timeSinceLastEntitySort;
public Level() { public Level()
{
} }
public Level(int width, int height) { public Level(int width, int height)
{
size.setTo(width, height); size.setTo(width, height);
buildArray(); buildArray();
} }
@ -126,7 +128,7 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
public final Tile getTile(Coord pos) public final Tile getTile(Coord pos)
{ {
if (!pos.isInRange(0, 0, size.x - 1, size.y - 1)) return Tiles.NULL.createTile(); // out of range if (!pos.isInRange(0, 0, size.x - 1, size.y - 1)) return Tiles.NULL.createTile(); // out of range
return tiles[pos.y][pos.x]; return tiles[pos.y][pos.x];
} }
@ -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 * Try to add entity at given pos
* *
@ -320,6 +350,9 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
final Tile t = getTile(pos); final Tile t = getTile(pos);
if (!t.isWalkable() || t.isOccupied()) return false; if (!t.isWalkable() || t.isOccupied()) return false;
// set level to init EID
entity.setLevel(this);
if (entityMap.containsKey(entity.getEntityId())) { if (entityMap.containsKey(entity.getEntityId())) {
Log.w("Entity already in level."); Log.w("Entity already in level.");
return false; return false;
@ -330,7 +363,6 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
if (entity instanceof PlayerEntity) playerCount++; if (entity instanceof PlayerEntity) playerCount++;
// join to level & world // join to level & world
entity.setLevel(this);
occupyTile(entity.getCoord()); occupyTile(entity.getCoord());
entity.setCoord(pos); entity.setCoord(pos);

@ -1,7 +1,11 @@
package mightypork.rogue.world.tile; package mightypork.rogue.world.tile;
import java.util.Collection;
import mightypork.gamecore.util.math.Easing; 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.Rect;
import mightypork.gamecore.util.math.constraints.rect.proxy.RectBoundAdapter; import mightypork.gamecore.util.math.constraints.rect.proxy.RectBoundAdapter;
import mightypork.gamecore.util.math.timing.Animator; import mightypork.gamecore.util.math.timing.Animator;
@ -12,27 +16,26 @@ import mightypork.rogue.world.level.render.TileRenderContext;
public class DroppedItemRenderer { 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 // prepared constraints, to avoid re-building each frame
private final RectBoundAdapter tileRectAdapter = new RectBoundAdapter(); 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);
}
return itemAnim;
}
public void render(Item item, TileRenderContext context)
{ {
tileRectAdapter.setRect(context); tileRectAdapter.setRect(context);
item.render(itemRect); int cnt = 0;
for (final Item i : items) {
offsAdapter.setNum(Num.make((itemAnim.value() + (cnt % 3) * 0.1)));
i.render(itemRect);
cnt++;
}
} }

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

Loading…
Cancel
Save