diff --git a/res/font/TinyUnicode.ttf b/res/font/TinyUnicode.ttf new file mode 100644 index 0000000..524ec80 Binary files /dev/null and b/res/font/TinyUnicode.ttf differ diff --git a/res/font/TinyUnicode2.ttf b/res/font/TinyUnicode2.ttf new file mode 100644 index 0000000..5ba2750 Binary files /dev/null and b/res/font/TinyUnicode2.ttf differ diff --git a/res/font/battlenet.ttf b/res/font/battlenet.ttf new file mode 100644 index 0000000..18f85a7 Binary files /dev/null and b/res/font/battlenet.ttf differ diff --git a/res/img/items.png b/res/img/items.png index 13f9f77..1e1111d 100644 Binary files a/res/img/items.png and b/res/img/items.png differ diff --git a/res/img/items.xcf b/res/img/items.xcf index df5c4c7..73eb70f 100644 Binary files a/res/img/items.xcf and b/res/img/items.xcf differ diff --git a/src/mightypork/gamecore/eventbus/clients/BusNode.java b/src/mightypork/gamecore/eventbus/clients/BusNode.java index 44e2430..8ab7909 100644 --- a/src/mightypork/gamecore/eventbus/clients/BusNode.java +++ b/src/mightypork/gamecore/eventbus/clients/BusNode.java @@ -48,7 +48,7 @@ public abstract class BusNode implements BusAccess, ClientHub { @Override - public boolean isListening() + public final boolean isListening() { return listening; } diff --git a/src/mightypork/gamecore/gui/components/VisualComponent.java b/src/mightypork/gamecore/gui/components/BaseComponent.java similarity index 80% rename from src/mightypork/gamecore/gui/components/VisualComponent.java rename to src/mightypork/gamecore/gui/components/BaseComponent.java index ae806e6..e1f138b 100644 --- a/src/mightypork/gamecore/gui/components/VisualComponent.java +++ b/src/mightypork/gamecore/gui/components/BaseComponent.java @@ -1,6 +1,7 @@ package mightypork.gamecore.gui.components; +import mightypork.gamecore.gui.Enableable; import mightypork.gamecore.gui.events.LayoutChangeEvent; import mightypork.gamecore.gui.events.LayoutChangeListener; import mightypork.gamecore.input.InputSystem; @@ -18,14 +19,15 @@ import mightypork.gamecore.util.math.constraints.rect.proxy.RectBoundAdapter; * * @author MightyPork */ -public abstract class VisualComponent extends AbstractRectCache implements Component, LayoutChangeListener { +public abstract class BaseComponent extends AbstractRectCache implements Component, LayoutChangeListener, Enableable { private Rect source; private boolean visible = true; + private int disableLevel = 0; - public VisualComponent() - { + + public BaseComponent() { enableCaching(false); } @@ -61,7 +63,7 @@ public abstract class VisualComponent extends AbstractRectCache implements Compo @Override public final void render() { - if (!visible) return; + if (!isVisible()) return; renderComponent(); } @@ -101,4 +103,22 @@ public abstract class VisualComponent extends AbstractRectCache implements Compo public void updateLayout() { } + + + @Override + public void enable(boolean yes) + { + if (yes) { + if (disableLevel > 0) disableLevel--; + } else { + disableLevel++; + } + } + + + @Override + public boolean isEnabled() + { + return disableLevel == 0; + } } diff --git a/src/mightypork/gamecore/gui/components/Component.java b/src/mightypork/gamecore/gui/components/Component.java index b101316..2e3f9a6 100644 --- a/src/mightypork/gamecore/gui/components/Component.java +++ b/src/mightypork/gamecore/gui/components/Component.java @@ -1,9 +1,8 @@ package mightypork.gamecore.gui.components; +import mightypork.gamecore.gui.Enableable; import mightypork.gamecore.gui.Hideable; -import mightypork.gamecore.util.math.constraints.rect.Rect; -import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; /** @@ -11,26 +10,7 @@ import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; * * @author MightyPork */ -public interface Component extends Hideable, PluggableRenderable { - - /** - * Set visible. When not visible, the component should not render. - */ - @Override - void setVisible(boolean yes); - - - @Override - boolean isVisible(); - - - @Override - Rect getRect(); - - - @Override - void setRect(RectBound rect); - +public interface Component extends Enableable, Hideable, PluggableRenderable { /** * Render the component, if it is visible. diff --git a/src/mightypork/gamecore/gui/components/InputComponent.java b/src/mightypork/gamecore/gui/components/InputComponent.java index b1f6ea9..d4844a1 100644 --- a/src/mightypork/gamecore/gui/components/InputComponent.java +++ b/src/mightypork/gamecore/gui/components/InputComponent.java @@ -5,25 +5,8 @@ import mightypork.gamecore.eventbus.clients.ToggleableClient; import mightypork.gamecore.gui.Enableable; -public abstract class InputComponent extends VisualComponent implements Enableable, ToggleableClient { - - private boolean enabled = true; - - - @Override - public void enable(boolean yes) - { - this.enabled = yes; - } - - - @Override - public boolean isEnabled() - { - return enabled && isVisible(); - } - - +public abstract class InputComponent extends BaseComponent implements Enableable, ToggleableClient { + @Override public boolean isListening() { diff --git a/src/mightypork/gamecore/gui/components/LayoutComponent.java b/src/mightypork/gamecore/gui/components/LayoutComponent.java index bcec65a..b2b0bb5 100644 --- a/src/mightypork/gamecore/gui/components/LayoutComponent.java +++ b/src/mightypork/gamecore/gui/components/LayoutComponent.java @@ -8,14 +8,13 @@ import mightypork.gamecore.app.AppAccess; import mightypork.gamecore.app.AppSubModule; import mightypork.gamecore.eventbus.EventBus; import mightypork.gamecore.eventbus.clients.ClientHub; -import mightypork.gamecore.gui.Enableable; import mightypork.gamecore.input.InputSystem; import mightypork.gamecore.render.DisplaySystem; import mightypork.gamecore.resources.audio.SoundSystem; import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; -public abstract class LayoutComponent extends VisualComponent implements Enableable, ClientHub, AppAccess { +public abstract class LayoutComponent extends BaseComponent implements ClientHub, AppAccess { private boolean enabled; @@ -106,21 +105,29 @@ public abstract class LayoutComponent extends VisualComponent implements Enablea subModule.removeChildClient(client); } - @Override public void enable(boolean yes) { - subModule.setDelegating(yes); - subModule.setListening(yes); - enabled = yes; + super.enable(yes); + for(Component c : components) { + c.enable(yes); + } } - - @Override - public boolean isEnabled() - { - return enabled; - } +// @Override +// public void enable(boolean yes) +// { +// subModule.setDelegating(yes); +// subModule.setListening(yes); +// enabled = yes; +// } +// +// +// @Override +// public boolean isEnabled() +// { +// return enabled; +// } /** diff --git a/src/mightypork/gamecore/gui/components/painters/ImagePainter.java b/src/mightypork/gamecore/gui/components/painters/ImagePainter.java index d676fd8..95733cb 100644 --- a/src/mightypork/gamecore/gui/components/painters/ImagePainter.java +++ b/src/mightypork/gamecore/gui/components/painters/ImagePainter.java @@ -1,7 +1,7 @@ package mightypork.gamecore.gui.components.painters; -import mightypork.gamecore.gui.components.VisualComponent; +import mightypork.gamecore.gui.components.BaseComponent; import mightypork.gamecore.render.Render; import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.util.math.constraints.num.Num; @@ -13,7 +13,7 @@ import mightypork.gamecore.util.math.constraints.rect.Rect; * * @author MightyPork */ -public class ImagePainter extends VisualComponent { +public class ImagePainter extends BaseComponent { private final TxQuad txQuad; private boolean aspratio = false; diff --git a/src/mightypork/gamecore/gui/components/painters/QuadPainter.java b/src/mightypork/gamecore/gui/components/painters/QuadPainter.java index 0bceed9..e64f090 100644 --- a/src/mightypork/gamecore/gui/components/painters/QuadPainter.java +++ b/src/mightypork/gamecore/gui/components/painters/QuadPainter.java @@ -1,7 +1,7 @@ package mightypork.gamecore.gui.components.painters; -import mightypork.gamecore.gui.components.VisualComponent; +import mightypork.gamecore.gui.components.BaseComponent; import mightypork.gamecore.render.Render; import mightypork.gamecore.util.annot.FactoryMethod; import mightypork.gamecore.util.math.color.Color; @@ -12,7 +12,7 @@ import mightypork.gamecore.util.math.color.Color; * * @author MightyPork */ -public class QuadPainter extends VisualComponent { +public class QuadPainter extends BaseComponent { @FactoryMethod public static QuadPainter gradH(Color colorLeft, Color colorRight) diff --git a/src/mightypork/gamecore/gui/components/painters/TextPainter.java b/src/mightypork/gamecore/gui/components/painters/TextPainter.java index 20df900..902c98a 100644 --- a/src/mightypork/gamecore/gui/components/painters/TextPainter.java +++ b/src/mightypork/gamecore/gui/components/painters/TextPainter.java @@ -2,15 +2,18 @@ package mightypork.gamecore.gui.components.painters; import mightypork.gamecore.gui.AlignX; -import mightypork.gamecore.gui.components.VisualComponent; +import mightypork.gamecore.gui.components.BaseComponent; +import mightypork.gamecore.render.Render; import mightypork.gamecore.resources.fonts.FontRenderer; import mightypork.gamecore.resources.fonts.GLFont; 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.vect.Vect; import mightypork.gamecore.util.strings.StringProvider; import mightypork.gamecore.util.strings.StringWrapper; +import mightypork.rogue.Config; /** @@ -20,7 +23,7 @@ import mightypork.gamecore.util.strings.StringWrapper; * * @author MightyPork */ -public class TextPainter extends VisualComponent { +public class TextPainter extends BaseComponent { private final FontRenderer font; private Color color; @@ -28,6 +31,9 @@ public class TextPainter extends VisualComponent { private StringProvider text; private boolean shadow; + private double yPaddingPerc = 0; + private double xPaddingPerc = 0; + private Color shadowColor = RGB.BLACK; private Vect shadowOffset = Vect.make(2, 2); @@ -35,8 +41,7 @@ public class TextPainter extends VisualComponent { /** * @param font font to use */ - public TextPainter(GLFont font) - { + public TextPainter(GLFont font) { this(font, AlignX.LEFT, RGB.WHITE); } @@ -49,8 +54,7 @@ public class TextPainter extends VisualComponent { * @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)); } @@ -63,8 +67,7 @@ public class TextPainter extends VisualComponent { * @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; @@ -77,8 +80,7 @@ public class TextPainter extends VisualComponent { * @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); } @@ -89,13 +91,20 @@ public class TextPainter extends VisualComponent { if (text == null) return; final String str = text.getString(); - final Rect rect = getRect(); + + Num shrX = height().perc(xPaddingPerc); + Num shrY = height().perc(yPaddingPerc); + + final Rect rect = getRect().shrink(shrX, shrY); if (shadow) { font.draw(str, rect.round(), align, shadowColor); } - font.draw(str, rect.move(shadowOffset.neg()).round(), align, color); + 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)); } @@ -147,4 +156,11 @@ public class TextPainter extends VisualComponent { { this.text = text; } + + + public void setPaddingHPerc(double percX, double percY) + { + xPaddingPerc = percX; + yPaddingPerc = percY; + } } diff --git a/src/mightypork/gamecore/gui/screens/LayeredScreen.java b/src/mightypork/gamecore/gui/screens/LayeredScreen.java index 79957a4..ab948b4 100644 --- a/src/mightypork/gamecore/gui/screens/LayeredScreen.java +++ b/src/mightypork/gamecore/gui/screens/LayeredScreen.java @@ -16,6 +16,11 @@ import mightypork.gamecore.eventbus.clients.DelegatingClient; */ public abstract class LayeredScreen extends Screen { + /** + * Wrapper for delegating client, to use custom client ordering. + * + * @author MightyPork + */ private class LayersClient implements DelegatingClient { @SuppressWarnings({ "unchecked", "rawtypes" }) diff --git a/src/mightypork/gamecore/gui/screens/Overlay.java b/src/mightypork/gamecore/gui/screens/Overlay.java index 0059c3d..d6e8632 100644 --- a/src/mightypork/gamecore/gui/screens/Overlay.java +++ b/src/mightypork/gamecore/gui/screens/Overlay.java @@ -7,6 +7,7 @@ import java.util.LinkedHashSet; import mightypork.gamecore.app.AppAccess; import mightypork.gamecore.app.AppSubModule; import mightypork.gamecore.eventbus.events.Updateable; +import mightypork.gamecore.gui.Enableable; import mightypork.gamecore.gui.Hideable; import mightypork.gamecore.gui.components.layout.ConstraintLayout; import mightypork.gamecore.gui.events.LayoutChangeListener; @@ -24,9 +25,11 @@ import mightypork.gamecore.util.math.constraints.vect.Vect; * * @author MightyPork */ -public abstract class Overlay extends AppSubModule implements Comparable, Updateable, Renderable, KeyBinder, Hideable, LayoutChangeListener { +public abstract class Overlay extends AppSubModule implements Comparable, Updateable, Renderable, KeyBinder, Hideable, Enableable, LayoutChangeListener { private boolean visible = true; + private boolean enabled = true; + private final KeyBindingPool keybindings = new KeyBindingPool(); /** Root layout, rendered and attached to the event bus. */ @@ -81,8 +84,21 @@ public abstract class Overlay extends AppSubModule implements Comparable 13) { + if (number % 10 == 1) return number + "st"; + if (number % 10 == 2) return number + "nd"; + if (number % 10 == 3) return number + "rd"; + } + return number + "th"; + } + + + /** + * Format number with thousands separated by a dot. + * + * @param number number + * @return string 12.004.225 + */ + public static String formatInt(long number) + { + final String num = number + ""; + String out = ""; + final String dot = "."; + int cnt = 1; + for (int i = num.length() - 1; i >= 0; i--) { + out = num.charAt(i) + out; + if (cnt % 3 == 0 && i > 0) out = dot + out; + cnt++; + } + + return out; + } } diff --git a/src/mightypork/gamecore/util/math/constraints/rect/Rect.java b/src/mightypork/gamecore/util/math/constraints/rect/Rect.java index e05b351..8b7ad8f 100644 --- a/src/mightypork/gamecore/util/math/constraints/rect/Rect.java +++ b/src/mightypork/gamecore/util/math/constraints/rect/Rect.java @@ -474,7 +474,7 @@ public abstract class Rect implements RectBound, Digestable { public Rect shrinkRight(final double shrink) { - return growLeft(-shrink); + return growRight(-shrink); } diff --git a/src/mightypork/gamecore/util/strings/StringUtils.java b/src/mightypork/gamecore/util/strings/StringUtils.java index 12360a5..26c7e70 100644 --- a/src/mightypork/gamecore/util/strings/StringUtils.java +++ b/src/mightypork/gamecore/util/strings/StringUtils.java @@ -100,45 +100,6 @@ public class StringUtils { } - /** - * Get ordinal version of numbers (1 = 1st, 5 = 5th etc.) - * - * @param number number - * @return ordinal, string - */ - public static String numberToOrdinal(int number) - { - if (number % 100 < 4 || number % 100 > 13) { - if (number % 10 == 1) return number + "st"; - if (number % 10 == 2) return number + "nd"; - if (number % 10 == 3) return number + "rd"; - } - return number + "th"; - } - - - /** - * Format number with thousands separated by a dot. - * - * @param number number - * @return string 12.004.225 - */ - public static String formatInt(long number) - { - final String num = number + ""; - String out = ""; - final String dot = "."; - int cnt = 1; - for (int i = num.length() - 1; i >= 0; i--) { - out = num.charAt(i) + out; - if (cnt % 3 == 0 && i > 0) out = dot + out; - cnt++; - } - - return out; - } - - public static boolean isValidFilenameChar(char ch) { return isValidFilenameString(Character.toString(ch)); diff --git a/src/mightypork/rogue/Config.java b/src/mightypork/rogue/Config.java index ea28057..470af55 100644 --- a/src/mightypork/rogue/Config.java +++ b/src/mightypork/rogue/Config.java @@ -24,6 +24,7 @@ public final class Config { // property keys private static final String PK_LAST_RUN_VERSION = "status.last_run_version"; private static final String PK_START_IN_FS = "cfg.start_in_fullscreen"; + /** @@ -76,4 +77,9 @@ public final class Config { public static boolean LOG_TO_STDOUT = true; public static boolean SINGLE_INSTANCE = true; + /** Render dark in unknown area & skip invisible stuff */ + public static boolean RENDER_UFOG = true; + + /** Render a font bounding box in text painters. */ + public static boolean DEBUG_FONT_RENDER = false; } diff --git a/src/mightypork/rogue/Res.java b/src/mightypork/rogue/Res.java index 8f57b4a..76261f4 100644 --- a/src/mightypork/rogue/Res.java +++ b/src/mightypork/rogue/Res.java @@ -53,13 +53,18 @@ public final class Res { //fonts.loadFont("polygon_pixel", new DeferredFont("/res/font/PolygonPixel5x7Standard.ttf", Glyphs.basic, 16)); fonts.loadFont("press_start", font = new DeferredFont("/res/font/PressStart2P.ttf", Glyphs.basic, 16)); - fonts.loadFont("polygon_pixel", font = new DeferredFont("/res/font/Simpleton.ttf", Glyphs.basic, 16)); - font.setDiscardRatio(5 / 16D, 2 / 16D); + + fonts.loadFont("battlenet", font = new DeferredFont("/res/font/battlenet.ttf", Glyphs.basic, 16)); + font.setDiscardRatio(3 / 16D, 2 / 16D); + + fonts.loadFont("tinyutf", font = new DeferredFont("/res/font/TinyUnicode2.ttf", Glyphs.basic, 16)); + font.setDiscardRatio(6 / 16D, 2 / 16D); // aliases based on concrete usage fonts.addAlias("thick", "press_start"); - fonts.addAlias("thin", "polygon_pixel"); + fonts.addAlias("thin", "battlenet"); + fonts.addAlias("tiny", "tinyutf"); } @@ -152,6 +157,13 @@ public final class Res { texture = textures.loadTexture("items", "/res/img/items.png", FilterMode.NEAREST, WrapMode.CLAMP); grid = texture.grid(8, 8); textures.add("item.meat", grid.makeQuad(0, 0)); + textures.add("item.club", grid.makeQuad(1, 0)); + textures.add("item.sword", grid.makeQuad(2, 0)); + textures.add("item.hammer", grid.makeQuad(3, 0)); + textures.add("item.stone", grid.makeQuad(4, 0)); + textures.add("item.bone", grid.makeQuad(5, 0)); + textures.add("item.cheese", grid.makeQuad(6, 0)); + textures.add("item.sandwich", grid.makeQuad(7, 0)); } diff --git a/src/mightypork/rogue/screens/game/HeartBar.java b/src/mightypork/rogue/screens/game/HeartBar.java index 348bffa..3bb2533 100644 --- a/src/mightypork/rogue/screens/game/HeartBar.java +++ b/src/mightypork/rogue/screens/game/HeartBar.java @@ -2,15 +2,16 @@ package mightypork.rogue.screens.game; import mightypork.gamecore.gui.AlignX; -import mightypork.gamecore.gui.components.VisualComponent; +import mightypork.gamecore.gui.components.BaseComponent; import mightypork.gamecore.render.Render; import mightypork.gamecore.resources.textures.TxQuad; +import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.gamecore.util.math.constraints.num.Num; import mightypork.gamecore.util.math.constraints.num.mutable.NumVar; import mightypork.gamecore.util.math.constraints.rect.Rect; -public class HeartBar extends VisualComponent { +public class HeartBar extends BaseComponent { private final TxQuad img_on; private final TxQuad img_off; @@ -18,8 +19,8 @@ public class HeartBar extends VisualComponent { private final Num total; private final Num active; - NumVar index = new NumVar(0); - Rect heart; + private final NumVar index = new NumVar(0); + private final Rect heart; /** @@ -30,8 +31,7 @@ public class HeartBar extends VisualComponent { * @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; @@ -52,6 +52,8 @@ public class HeartBar extends VisualComponent { case CENTER: heart = leftEdge().moveX(w.half().add(h.mul(total.half().neg()))).growRight(h).moveX(index.mul(h)); break; + default: + heart = null; // impossible } } @@ -59,12 +61,11 @@ public class HeartBar extends VisualComponent { @Override protected void renderComponent() - { + { for (int i = 0; i < total.value(); i++) { index.setTo(i); final double rem = active.value() - i; - Render.quadTextured(heart, (rem > 0.6 ? img_on : rem > 0.25 ? img_half : img_off)); } } diff --git a/src/mightypork/rogue/screens/game/HudLayer.java b/src/mightypork/rogue/screens/game/HudLayer.java index eb1bc99..6af2bb9 100644 --- a/src/mightypork/rogue/screens/game/HudLayer.java +++ b/src/mightypork/rogue/screens/game/HudLayer.java @@ -39,8 +39,7 @@ public class HudLayer extends ScreenLayer { private final ScreenGame gameScreen; - public HudLayer(ScreenGame screen) - { + public HudLayer(ScreenGame screen) { super(screen); this.gameScreen = screen; @@ -49,6 +48,22 @@ public class HudLayer extends ScreenLayer { buildDisplays(); buildMinimap(); + + buildConsole(); + } + + + 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)); + + Num perRow = consoleRect.height().div(20).max(12).min(32); + + WorldConsoleRenderer wcr = new WorldConsoleRenderer(perRow); + wcr.setRect(consoleRect); + root.add(wcr); } @@ -64,8 +79,6 @@ public class HudLayer extends ScreenLayer { { final Num h = root.height(); - final Num displays_height = h.perc(6); - //@formatter:off final HeartBar hearts = new HeartBar( playerHealthTotal, @@ -76,13 +89,11 @@ public class HudLayer extends ScreenLayer { AlignX.LEFT); //@formatter:on - - final Rect hearts_box = root.shrink(h.perc(3)).topLeft().startRect().growDown(displays_height); + final Rect hearts_box = root.shrink(h.perc(3)).topEdge().growDown(h.perc(6)); hearts.setRect(hearts_box); root.add(hearts); - - final TextPainter lvl = new TextPainter(Res.getFont("thick"), AlignX.RIGHT, RGB.WHITE, new StringProvider() { + final TextPainter levelText = new TextPainter(Res.getFont("tiny"), AlignX.RIGHT, RGB.WHITE, new StringProvider() { @Override public String getString() @@ -92,15 +103,8 @@ public class HudLayer extends ScreenLayer { } }); - final Rect rr = root.shrink(h.perc(3)).topEdge().growDown(displays_height); - lvl.setRect(rr.shrink(Num.ZERO, rr.height().perc(20))); - root.add(lvl); - - - /*final HeartBar experience = new HeartBar(6, 2, Res.getTxQuad("xp_on"), Res.getTxQuad("xp_off"), AlignX.RIGHT); - final Rect xp_box = shrunk.topRight().startRect().growDown(displays_height); - experience.setRect(xp_box); - root.add(experience);*/ + levelText.setRect(hearts_box.moveY(hearts_box.height().mul(1/7D))); + root.add(levelText); } @@ -112,24 +116,24 @@ public class HudLayer extends ScreenLayer { NavButton btn; - // ltr - nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.inventory"))); + nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.inventory"))); btn.setAction(gameScreen.actionInv); - nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.eat"))); + nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.eat"))); btn.setAction(gameScreen.actionEat); - nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.pause"))); + nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.pause"))); btn.setAction(gameScreen.actionTogglePause); + // TODO actions - nav.addRight(new NavButton(Res.txq("nav.button.fg.options"))); - nav.addRight(new NavButton(Res.txq("nav.button.fg.help"))); + nav.addLeft(new NavButton(Res.txq("nav.button.fg.options"))); + nav.addLeft(new NavButton(Res.txq("nav.button.fg.help"))); - nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.map"))); + nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.map"))); btn.setAction(gameScreen.actionToggleMinimap); - nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.magnify"))); + nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.magnify"))); btn.setAction(gameScreen.actionToggleZoom); } diff --git a/src/mightypork/rogue/screens/game/InvLayer.java b/src/mightypork/rogue/screens/game/InvLayer.java index 243f2df..750f959 100644 --- a/src/mightypork/rogue/screens/game/InvLayer.java +++ b/src/mightypork/rogue/screens/game/InvLayer.java @@ -30,7 +30,7 @@ public class InvLayer extends ScreenLayer { @Override public String getString() { - String s = "Esc - close"; + String s = "ESC-close"; final int selected = getSelectedSlot(); if (selected != -1) { @@ -39,16 +39,18 @@ public class InvLayer extends ScreenLayer { final Item itm = pl.getInventory().getItem(selected); if (itm != null && !itm.isEmpty()) { - s = "D - drop, " + s; + s = "D-drop," + s; if (itm.getType() == ItemType.FOOD) { - s = "E - eat, " + s; + s = "E-eat," + s; } if (itm.getType() == ItemType.WEAPON) { - s = "E - equip, " + s; + s = "E-equip," + s; } } + }else { + s = "Click-select,"+s; } return s; @@ -76,18 +78,19 @@ public class InvLayer extends ScreenLayer { final Rect fg = root.shrink(root.height().perc(15)); - final QuadPainter qp = new QuadPainter(Color.rgba(0, 0, 0, 0.5)); + final QuadPainter qp = new QuadPainter(RGB.BLACK_30, RGB.BLACK_30, RGB.BLACK_80, RGB.BLACK_80); qp.setRect(root); root.add(qp); int pos = 0; - final GridLayout gl = new GridLayout(root, fg, 21, 1); + final GridLayout gl = new GridLayout(root, fg, 10, 1); root.add(gl); final TextPainter txp = new TextPainter(Res.getFont("thick"), AlignX.CENTER, RGB.YELLOW, "Inventory"); - gl.put(txp, pos, 0, 2, 1); - pos += 3; + gl.put(txp, pos, 0, 1, 1); + txp.setPaddingHPerc(0, 5); + pos += 1; final HorizontalFixedFlowLayout row1 = new HorizontalFixedFlowLayout(root, null, AlignX.LEFT); row1.setElementWidth(row1.height()); @@ -95,8 +98,8 @@ public class InvLayer extends ScreenLayer { row1.setRect(cl1.axisV().grow(cl1.height().mul(2), Num.ZERO)); cl1.add(row1); - gl.put(cl1, pos, 0, 8, 1); - pos += 8; + gl.put(cl1, pos, 0, 4, 1); + pos += 4; row1.add(slots[0] = new InvSlot(0, slots)); row1.add(slots[1] = new InvSlot(1, slots)); @@ -109,25 +112,24 @@ public class InvLayer extends ScreenLayer { final ConstraintLayout cl2 = new ConstraintLayout(root); row2.setRect(cl2.axisV().grow(cl2.height().mul(2), Num.ZERO)); cl2.add(row2); - gl.put(cl2, pos, 0, 8, 1); - pos += 8; + gl.put(cl2, pos, 0, 4, 1); + pos += 4; row2.add(slots[4] = new InvSlot(4, slots)); row2.add(slots[5] = new InvSlot(5, slots)); row2.add(slots[6] = new InvSlot(6, slots)); row2.add(slots[7] = new InvSlot(7, slots)); - final TextPainter txp2 = new TextPainter(Res.getFont("thin"), AlignX.CENTER, RGB.WHITE, contextStrProv); - gl.put(txp2, pos + 1, 0, 1, 1); - - setVisible(false); + final TextPainter txp2 = new TextPainter(Res.getFont("thick"), AlignX.CENTER, RGB.WHITE, contextStrProv); + gl.put(txp2, pos, 0, 1, 1); + txp2.setPaddingHPerc(0, 25); bindKey(new KeyStroke(Keys.ESCAPE), new Runnable() { @Override public void run() { - if (!isVisible()) return; + if(WorldProvider.get().getPlayer().isDead()) return; screen.setState(GScrState.WORLD); } @@ -137,8 +139,8 @@ public class InvLayer extends ScreenLayer { @Override public void run() - { - if (!isVisible()) return; + { + if(WorldProvider.get().getPlayer().isDead()) return; final int selected = getSelectedSlot(); if (selected != -1) { @@ -147,15 +149,14 @@ public class InvLayer extends ScreenLayer { if (itm != null && !itm.isEmpty()) { if (itm.getType() == ItemType.FOOD) { - if (pl.eatFood(itm)) { - if (itm.consume()) { - pl.getInventory().setItem(selected, null); - } + if (pl.eatFood(itm)) { + pl.getInventory().clean(); } } if (itm.getType() == ItemType.WEAPON) { pl.selectWeapon(selected); + WorldProvider.get().getWorld().msgEquipWeapon(itm); } } } @@ -194,4 +195,13 @@ public class InvLayer extends ScreenLayer { return 200; } + @Override + public void onLayoutChanged() + { + // TODO Auto-generated method stub + super.onLayoutChanged(); + + System.out.println("LayoutChange @ invlayer"); + } + } diff --git a/src/mightypork/rogue/screens/game/InvSlot.java b/src/mightypork/rogue/screens/game/InvSlot.java index 9247872..d6c28f1 100644 --- a/src/mightypork/rogue/screens/game/InvSlot.java +++ b/src/mightypork/rogue/screens/game/InvSlot.java @@ -7,12 +7,17 @@ import mightypork.gamecore.gui.components.ClickableComponent; 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.caching.RectCache; import mightypork.rogue.Res; import mightypork.rogue.world.World.PlayerFacade; +import mightypork.rogue.world.PlayerInfo; import mightypork.rogue.world.WorldProvider; import mightypork.rogue.world.item.Item; +import mightypork.rogue.world.item.ItemType; /** @@ -28,16 +33,18 @@ public class InvSlot extends ClickableComponent { protected int index; private final RectCache itemRect; + private final RectCache uiRect; private final InvSlot[] slots; - private final TextPainter txt; + private final TextPainter rbTxP; + private final TextPainter rtTxP; - private final RectCache txtRect; + private final RectCache rbTxRect; + private final RectCache rtTxRect; - 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"); @@ -45,17 +52,27 @@ public class InvSlot extends ClickableComponent { this.index = index; this.slots = allSlots; - this.itemRect = 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(); + + //@formatter:off + this.rbTxRect = uiRect.bottomEdge() + .moveY(uiRect.height().perc(1*(30/7D))) + .growUp(uiRect.height().perc(30)).cached(); + //@formatter:on + + rbTxP = new TextPainter(Res.getFont("tiny"), AlignX.RIGHT, RGB.WHITE); + rbTxP.setRect(rbTxRect); + rbTxP.setShadow(RGB.BLACK_70, rbTxP.getRect().height().div(7).toVectXY()); //@formatter:off - this.txtRect = itemRect.bottomEdge() - .move(itemRect.height().perc(5).neg(), itemRect.height().perc(10).neg()) - .growUp(itemRect.height().perc(35)).cached(); + this.rtTxRect = uiRect.topEdge() + .growDown(uiRect.height().perc(30)).cached(); //@formatter:on - txt = new TextPainter(Res.getFont("thin"), AlignX.RIGHT, RGB.WHITE); - txt.setRect(txtRect); - txt.setShadow(RGB.BLACK_60, txt.getRect().height().div(8).toVectXY()); + rtTxP = new TextPainter(Res.getFont("tiny"), AlignX.RIGHT, RGB.GREEN); + rtTxP.setRect(rtTxRect); + rtTxP.setShadow(RGB.BLACK_70, rtTxP.getRect().height().div(7).toVectXY()); setAction(new Action() { @@ -76,8 +93,10 @@ public class InvSlot extends ClickableComponent { @Override public void updateLayout() { + uiRect.poll(); itemRect.poll(); - txtRect.poll(); + rbTxRect.poll(); + rtTxRect.poll(); } @@ -100,18 +119,28 @@ public class InvSlot extends ClickableComponent { if (itm != null && !itm.isEmpty()) { itm.render(itemRect); if (itm.getAmount() > 1) { - txt.setText("" + itm.getAmount()); - txt.setColor(RGB.WHITE); - txt.render(); + rbTxP.setText("" + itm.getAmount()); + rbTxP.setColor(RGB.WHITE); + rbTxP.render(); } - if (pl.getSelectedWeapon() == index) { - txt.setText("*"); - txt.setColor(RGB.YELLOW); - txt.render(); + if (pl.getSelectedWeaponIndex() == index) { + rbTxP.setText("*"); + rbTxP.setColor(RGB.YELLOW); + rbTxP.render(); } - + if (itm.getType() == ItemType.FOOD) { + rtTxP.setText(Calc.toString(itm.getFoodPoints() / 2D)); + rbTxP.setColor(RGB.GREEN); + rtTxP.render(); + } else if (itm.getType() == ItemType.WEAPON) { + + int atk = itm.getAttackPoints(); + rtTxP.setText((atk >= 0 ? "+" : "") + atk); + rtTxP.setColor(RGB.CYAN); + rtTxP.render(); + } } } diff --git a/src/mightypork/rogue/screens/game/NavButton.java b/src/mightypork/rogue/screens/game/NavButton.java index f6263f5..188dd98 100644 --- a/src/mightypork/rogue/screens/game/NavButton.java +++ b/src/mightypork/rogue/screens/game/NavButton.java @@ -40,6 +40,8 @@ public class NavButton extends ClickableComponent { bg = base; } + if(!isEnabled()) bg = base; // override effects + Render.quadTextured(this, bg); Render.quadTextured(this, fg); } diff --git a/src/mightypork/rogue/screens/game/ScreenGame.java b/src/mightypork/rogue/screens/game/ScreenGame.java index da2fae2..f3fa98e 100644 --- a/src/mightypork/rogue/screens/game/ScreenGame.java +++ b/src/mightypork/rogue/screens/game/ScreenGame.java @@ -9,6 +9,7 @@ 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.WorldProvider; import mightypork.rogue.world.events.WorldPauseRequest; import mightypork.rogue.world.events.WorldPauseRequest.PauseAction; @@ -26,7 +27,6 @@ public class ScreenGame extends LayeredScreen { WORLD, INV; } - private final Random rand = new Random(); private InvLayer invLayer; private HudLayer hudLayer; @@ -102,12 +102,14 @@ public class ScreenGame extends LayeredScreen { getEventBus().send(new WorldPauseRequest(PauseAction.RESUME)); invLayer.setVisible(false); // hide all extra layers + invLayer.enable(false); worldActions.enable(true); } if (nstate == GScrState.INV) { invLayer.setVisible(true); + invLayer.enable(true); } this.state = nstate; @@ -120,13 +122,20 @@ public class ScreenGame extends LayeredScreen { } - public ScreenGame(AppAccess app) - { + public ScreenGame(AppAccess app) { super(app); addLayer(invLayer = new InvLayer(this)); + invLayer.enable(false); + invLayer.setVisible(false); + addLayer(hudLayer = new HudLayer(this)); + hudLayer.enable(true); + hudLayer.setVisible(true); + addLayer(worldLayer = new WorldLayer(this)); + worldLayer.enable(true); + worldLayer.setVisible(true); // TODO temporary here ↓ bindKey(new KeyStroke(Keys.L_CONTROL, Keys.N), new Runnable() { @@ -146,6 +155,10 @@ public class ScreenGame extends LayeredScreen { bindKey(new KeyStroke(Keys.E), actionEat); bindKey(new KeyStroke(Keys.M), actionToggleMinimap); bindKey(new KeyStroke(Keys.Z), actionToggleZoom); + + // add as actions - enableables. + worldActions.add(worldLayer); + worldActions.add(hudLayer); worldActions.add(actionEat); worldActions.add(actionInv); @@ -154,6 +167,16 @@ public class ScreenGame extends LayeredScreen { worldActions.add(actionToggleZoom); worldActions.enable(true); + + // TMP TODO remove + bindKey(new KeyStroke(Keys.X), new Runnable() { + + @Override + public void run() + { + Config.RENDER_UFOG ^= true; + } + }); } diff --git a/src/mightypork/rogue/screens/game/WorldConsoleRenderer.java b/src/mightypork/rogue/screens/game/WorldConsoleRenderer.java new file mode 100644 index 0000000..0cbb391 --- /dev/null +++ b/src/mightypork/rogue/screens/game/WorldConsoleRenderer.java @@ -0,0 +1,62 @@ +package mightypork.rogue.screens.game; + + +import java.util.Collection; + +import mightypork.gamecore.gui.AlignX; +import mightypork.gamecore.gui.components.BaseComponent; +import mightypork.gamecore.gui.components.painters.TextPainter; +import mightypork.gamecore.resources.fonts.FontRenderer; +import mightypork.gamecore.util.math.color.Color; +import mightypork.gamecore.util.math.color.pal.RGB; +import mightypork.gamecore.util.math.constraints.num.Num; +import mightypork.gamecore.util.math.constraints.num.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; + + +public class WorldConsoleRenderer extends BaseComponent { + + private final Num rowHeight; + private final FontRenderer fr; + + + public WorldConsoleRenderer(Num rowHeight) { + this.rowHeight = rowHeight; + this.fr = new FontRenderer(Res.getFont("tiny")); + } + + + @Override + protected void renderComponent() + { + double rh = rowHeight.value(); + + Rect lowRow = bottomEdge().growUp(rowHeight); + + Collection entries = WorldProvider.get().getWorld().getConsole().getEntries(); + int cnt = 0; + + NumVar alph = Num.makeVar(); + + Color.pushAlpha(alph); + + for (WorldConsole.Entry entry : entries) { + + alph.setTo(entry.getAlpha()); + + 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); + + cnt++; + } + + Color.popAlpha(); + } + +} diff --git a/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java b/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java index 48c9817..b309629 100644 --- a/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java +++ b/src/mightypork/rogue/screens/test_bouncyboxes/BouncyBox.java @@ -4,7 +4,7 @@ package mightypork.rogue.screens.test_bouncyboxes; import java.util.Random; import mightypork.gamecore.eventbus.events.Updateable; -import mightypork.gamecore.gui.components.VisualComponent; +import mightypork.gamecore.gui.components.BaseComponent; import mightypork.gamecore.render.Render; import mightypork.gamecore.util.math.Easing; import mightypork.gamecore.util.math.color.pal.RGB; @@ -14,7 +14,7 @@ import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.rect.caching.RectCache; -public class BouncyBox extends VisualComponent implements Updateable { +public class BouncyBox extends BaseComponent implements Updateable { private final Random rand = new Random(); diff --git a/src/mightypork/rogue/world/Inventory.java b/src/mightypork/rogue/world/Inventory.java index ad4a97f..ed0bd6e 100644 --- a/src/mightypork/rogue/world/Inventory.java +++ b/src/mightypork/rogue/world/Inventory.java @@ -16,14 +16,12 @@ 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 } @@ -154,6 +152,19 @@ public class Inventory implements IonObjBinary { } + /** + * Clean empty items + */ + public void clean() + { + for (int i = 0; i < getSize(); i++) { + Item itm = getItem(i); + if (itm == null) continue; + if (itm.isEmpty()) setItem(i, null); + } + } + + @Override public String toString() { @@ -164,8 +175,10 @@ public class Inventory implements IonObjBinary { s += i + ": "; final Item itm = getItem(i); - if (itm == null) s += ""; - else s += itm; + if (itm == null) + s += ""; + else + s += itm; } s += "]"; return s; diff --git a/src/mightypork/rogue/world/PlayerControl.java b/src/mightypork/rogue/world/PlayerControl.java index 54d9db0..829327f 100644 --- a/src/mightypork/rogue/world/PlayerControl.java +++ b/src/mightypork/rogue/world/PlayerControl.java @@ -99,31 +99,34 @@ public abstract class PlayerControl { */ public boolean clickTile(Step side) { - return clickTile(getPlayer().getCoord().add(side).toVect().add(0.5, 0.5)); + return doClickTile(getPlayer().getCoord().add(side).toVect()); } public boolean clickTile(Vect pos) - { - //if (pos.dist(getPlayer().getVisualPos()).value() > 8) return false; // too far - + { if (pos.dist(getPlayer().getVisualPos().add(0.5, 0.5)).value() < 1.5) { - - // 1st try to hit entity - final Entity prey = getLevel().getClosestEntity(pos, EntityType.MONSTER, 1); - if (prey != null) { - prey.receiveAttack(getPlayer().getEntity(), getPlayer().getAttackStrength()); - return true; - } - - //2nd try to click tile - return getLevel().getTile(Coord.fromVect(pos)).onClick(); + return doClickTile(pos); } return false; } + private boolean doClickTile(Vect pos) + { + // 1st 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(); + } + + public void go(Step side) { getPlayer().cancelPath(); diff --git a/src/mightypork/rogue/world/PlayerInfo.java b/src/mightypork/rogue/world/PlayerInfo.java index 9cdb72c..4b5c9b7 100644 --- a/src/mightypork/rogue/world/PlayerInfo.java +++ b/src/mightypork/rogue/world/PlayerInfo.java @@ -19,7 +19,7 @@ public class PlayerInfo implements IonObjBundled { private static final int INV_SIZE = 8; /** Constant indicating that no weapon is selected. */ - private static final int NO_WEAPON = -1; + public static final int NO_WEAPON = -1; /** Attack str with bare hands */ public static final int BARE_ATTACK = 1; @@ -106,6 +106,10 @@ public class PlayerInfo implements IonObjBundled { public void selectWeapon(int selectedWeapon) { + if(selectedWeapon<0||selectedWeapon>=getInventory().getSize()) { + selectedWeapon = NO_WEAPON; + } + this.selectedWeapon = selectedWeapon; } diff --git a/src/mightypork/rogue/world/World.java b/src/mightypork/rogue/world/World.java index ddee98a..ac4a6e0 100644 --- a/src/mightypork/rogue/world/World.java +++ b/src/mightypork/rogue/world/World.java @@ -2,15 +2,15 @@ package mightypork.rogue.world; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Random; +import java.util.*; import mightypork.gamecore.eventbus.BusAccess; import mightypork.gamecore.eventbus.EventBus; import mightypork.gamecore.eventbus.clients.DelegatingClient; +import mightypork.gamecore.eventbus.events.Updateable; import mightypork.gamecore.util.ion.IonBundle; import mightypork.gamecore.util.ion.IonObjBundled; +import mightypork.gamecore.util.math.Calc; import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.constraints.vect.Vect; @@ -27,7 +27,7 @@ import mightypork.rogue.world.level.Level; * * @author MightyPork */ -public class World implements DelegatingClient, BusAccess, IonObjBundled, Pauseable { +public class World implements DelegatingClient, BusAccess, IonObjBundled, Pauseable, Updateable { /** * Convenient access to player-related methods and data @@ -36,7 +36,6 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea */ public class PlayerFacade { - public boolean canAscend() { return playerInfo.getLevelNumber() > 0; @@ -52,8 +51,11 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea playerInfo.setLevelNumber(lvl_num + 1); + getLevel().forceFreeTile(getLevel().getEnterPoint()); getLevel().addEntity(playerEntity, getLevel().getEnterPoint()); getLevel().explore(getCoord()); + + msgEnterFloor(getLevelNumber()); } @@ -72,8 +74,11 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea playerInfo.setLevelNumber(lvl_num - 1); + getLevel().forceFreeTile(getLevel().getExitPoint()); getLevel().addEntity(playerEntity, getLevel().getExitPoint()); getLevel().explore(getCoord()); + + msgEnterFloor(getLevelNumber()); } @@ -176,10 +181,16 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea if (weapon == null) return PlayerInfo.BARE_ATTACK; - return Math.min(weapon.getAttackPoints(), playerInfo.BARE_ATTACK); + return PlayerInfo.BARE_ATTACK + weapon.getAttackPoints(); } + /** + * Eat food. + * + * @param itm food item + * @return if something was eaten + */ public boolean eatFood(Item itm) { if (itm == null || itm.isEmpty() || itm.getType() != ItemType.FOOD) return false; @@ -187,11 +198,13 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea if (getHealth() < getHealthMax()) { playerEntity.health.addHealth(itm.getFoodPoints()); + itm.consume(); + + msgEat(itm); return true; } - return false; } @@ -202,7 +215,13 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea } - public int getSelectedWeapon() + public Item getSelectedWeapon() + { + return playerInfo.getSelectedWeapon(); + } + + + public int getSelectedWeaponIndex() { return playerInfo.getSelectedWeaponIndex(); } @@ -210,17 +229,122 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea public void tryToEatSomeFood() { + List foods = new ArrayList<>(); for (int i = 0; i < getInventory().getSize(); i++) { final Item itm = getInventory().getItem(i); - if (itm == null || itm.isEmpty()) continue; + if (itm != null && itm.getType() == ItemType.FOOD) { + foods.add(itm); + } + } + + // sort from smallest to biggest foods + Collections.sort(foods, new Comparator() { - final Item slice = itm.split(1); - if (!eatFood(slice)) itm.addItem(slice); - if (itm.isEmpty()) getInventory().setItem(i, null); - return; + @Override + public int compare(Item o1, Item o2) + { + return (o1.getFoodPoints() - o2.getFoodPoints()); + } + }); + + for (Item itm : foods) { + if (eatFood(itm)) { + getInventory().clean(); + return; + } } + + msgNoMoreFood(); + } + + + public void attack(Entity prey) + { + int attackPoints = getAttackStrength(); + + prey.receiveAttack(getPlayer().getEntity(), attackPoints); + + if (prey.isDead()) { + msgKill(prey); + } + + Item wpn = getSelectedWeapon(); + + if (wpn != null) { + wpn.use(); + if (wpn.isEmpty()) { + msgWeaponBreak(wpn); + + getInventory().clean(); + selectWeapon(-1); + + pickBestWeaponIfNoneSelected(); + } + } + } + + private void pickBestWeaponIfNoneSelected() + { + if (getSelectedWeapon() != null) return; + + List wpns = new ArrayList<>(); + for (int i = 0; i < getInventory().getSize(); i++) { + final Item itm = getInventory().getItem(i); + if (itm != null && itm.getType() == ItemType.WEAPON) { + wpns.add(itm); + } + } + + // sort from smallest to biggest foods + Collections.sort(wpns, new Comparator() { + + @Override + public int compare(Item o1, Item o2) + { + return (o2.getAttackPoints() - o1.getAttackPoints()); + } + }); + + for (Item itm : wpns) { + for (int i = 0; i < getInventory().getSize(); i++) { + final Item itm2 = getInventory().getItem(i); + if (itm2 == itm) { + selectWeapon(i); + break; + } + } + break; // just one cycle + } + + msgEquipWeapon(getSelectedWeapon()); + } + + + public boolean addItem(Item item) + { + if (!getInventory().addItem(item)) { + + msgCannotPick(); + + return false; + } + + msgPick(item); + + if (item.getType() == ItemType.WEAPON) { + if (getSelectedWeapon() != null) { + if (item.getAttackPoints() > getSelectedWeapon().getAttackPoints()) { + selectWeapon(-1); // unselect to grab the best one + } + } + + pickBestWeaponIfNoneSelected(); + } + + return true; + } } // not saved stuffs @@ -229,10 +353,10 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea private BusAccess bus; private int pauseDepth = 0; - private final ArrayList levels = new ArrayList<>(); private final PlayerInfo playerInfo = new PlayerInfo(); + private final WorldConsole console = new WorldConsole(); /** World seed */ private long seed; @@ -342,6 +466,8 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea playerInfo.setLevelNumber(0); playerInfo.setEID(playerEid); + + msgEnterFloor(0); } @@ -390,4 +516,79 @@ public class World implements DelegatingClient, BusAccess, IonObjBundled, Pausea return player; } + + @Override + public void update(double delta) + { + if (isPaused()) return; + + // update console timing + console.update(delta); + } + + + public WorldConsole getConsole() + { + return console; + } + + + public void msgPick(Item item) + { + console.addMessage("You've picked a " + item.getVisualName() + "."); + } + + + public void msgWeaponBreak(Item item) + { + console.addMessage("Your " + item.getVisualName() + " has broken!"); + } + + + public void msgEquipWeapon(Item item) + { + console.addMessage("You're now wielding " + (item == null ? "NOTHING" : "a " + item.getVisualName()) + "."); + } + + + public void msgEat(Item item) + { + console.addMessage("You've eaten a " + item.getVisualName() + "."); + } + + + public void msgKill(Entity prey) + { + console.addMessage("You've killed a " + prey.getVisualName() + "."); + } + + + public void msgDie(Entity attacker) + { + console.addMessage("You've been defeated by a " + attacker.getVisualName() + "!"); + } + + + public void msgDiscoverSecretDoor() + { + console.addMessage("You've discovered a secret door."); + } + + + public void msgNoMoreFood() + { + console.addMessage("You have no more food!"); + } + + + public void msgCannotPick() + { + console.addMessage("Inventory is full."); + } + + + public void msgEnterFloor(int floor) + { + console.addMessage("~ " + Calc.ordinal(floor + 1) + " floor ~"); + } } diff --git a/src/mightypork/rogue/world/WorldConsole.java b/src/mightypork/rogue/world/WorldConsole.java new file mode 100644 index 0000000..0c00fbf --- /dev/null +++ b/src/mightypork/rogue/world/WorldConsole.java @@ -0,0 +1,103 @@ +package mightypork.rogue.world; + + +import java.util.*; + +import mightypork.gamecore.eventbus.events.Updateable; +import mightypork.gamecore.util.math.Easing; +import mightypork.gamecore.util.math.constraints.num.mutable.NumAnimated; + + +public class WorldConsole implements Updateable { + + private static final double DURATION = 5; + + public class Entry implements Updateable { + + private final String text; + private final NumAnimated fadeout; + private boolean fading = false; + private double elapsed = 0; + + + private Entry(String text) { + this.text = text; + this.fadeout = new NumAnimated(1, Easing.LINEAR); + this.fadeout.setDefaultDuration(0.5); + } + + + @Override + public void update(double delta) + { + elapsed += delta; + + if (fading) { + fadeout.update(delta); + return; + } + + if (elapsed > DURATION) { + fading = true; + fadeout.fadeOut(); + } + } + + + private boolean canRemove() + { + return fading && fadeout.isFinished(); + } + + + public double getAlpha() + { + return !fading ? 1 : fadeout.value(); + } + + + public String getMessage() + { + return text; + } + + + public double getAge() + { + return elapsed; + } + } + + private final Deque entries = new LinkedList<>(); + + + @Override + public void update(double delta) + { + for (Iterator iter = entries.iterator(); iter.hasNext();) { + Entry e = iter.next(); + + e.update(delta); + + if (e.canRemove()) { + iter.remove(); + } + } + } + + + public void addMessage(String message) + { + entries.addFirst(new Entry(message)); + } + + + public Collection getEntries() + { + return entries; + } + + public void clear() { + entries.clear(); + } +} diff --git a/src/mightypork/rogue/world/WorldCreator.java b/src/mightypork/rogue/world/WorldCreator.java index 873427a..71247a9 100644 --- a/src/mightypork/rogue/world/WorldCreator.java +++ b/src/mightypork/rogue/world/WorldCreator.java @@ -20,7 +20,7 @@ public class WorldCreator { final World w = new World(); w.setSeed(seed); - final int count = 6; + 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); diff --git a/src/mightypork/rogue/world/entity/Entity.java b/src/mightypork/rogue/world/entity/Entity.java index e87e7da..209bf80 100644 --- a/src/mightypork/rogue/world/entity/Entity.java +++ b/src/mightypork/rogue/world/entity/Entity.java @@ -14,10 +14,10 @@ import mightypork.gamecore.util.ion.IonBundle; import mightypork.gamecore.util.ion.IonObjBundled; import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.pathfinding.PathFinder; +import mightypork.rogue.Config; import mightypork.rogue.world.World; import mightypork.rogue.world.entity.modules.EntityModuleHealth; import mightypork.rogue.world.entity.modules.EntityModulePosition; -import mightypork.rogue.world.entity.render.EntityRenderer; import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.render.MapRenderContext; @@ -43,6 +43,7 @@ public abstract class Entity implements IonObjBundled, Updateable { public final EntityModulePosition pos = new EntityModulePosition(this); public final EntityModuleHealth health = new EntityModuleHealth(this); private double despawnDelay = 1; + protected Entity lastAttacker; public Entity(EntityModel model, int eid) @@ -154,7 +155,7 @@ public abstract class Entity implements IonObjBundled, Updateable { @DefaultImpl public final void render(MapRenderContext context) { - if (context.getTile(getCoord()).isExplored()) { + if (context.getTile(getCoord()).isExplored() || !Config.RENDER_UFOG) { getRenderer().render(context); } } @@ -244,6 +245,7 @@ public abstract class Entity implements IonObjBundled, Updateable { */ public void receiveAttack(Entity attacker, int attackStrength) { + this.lastAttacker = attacker; health.receiveDamage(attackStrength); } @@ -264,4 +266,5 @@ public abstract class Entity implements IonObjBundled, Updateable { return despawnDelay; } + public abstract String getVisualName(); } diff --git a/src/mightypork/rogue/world/entity/render/EntityRenderer.java b/src/mightypork/rogue/world/entity/EntityRenderer.java similarity index 78% rename from src/mightypork/rogue/world/entity/render/EntityRenderer.java rename to src/mightypork/rogue/world/entity/EntityRenderer.java index c35243b..19705ee 100644 --- a/src/mightypork/rogue/world/entity/render/EntityRenderer.java +++ b/src/mightypork/rogue/world/entity/EntityRenderer.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world.entity.render; +package mightypork.rogue.world.entity; import mightypork.rogue.world.level.render.MapRenderContext; diff --git a/src/mightypork/rogue/world/entity/entities/MonsterAi.java b/src/mightypork/rogue/world/entity/entities/MonsterAi.java index fc1fb68..fb9791a 100644 --- a/src/mightypork/rogue/world/entity/entities/MonsterAi.java +++ b/src/mightypork/rogue/world/entity/entities/MonsterAi.java @@ -94,9 +94,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener { { if (entity.isDead()) return; - //System.out.println("monster ai step finished."); if (chasing) { - //System.out.println("chasing.."); final Entity prey = getPreyEntity(); if (!isPreyValid(prey)) { stopChasing(); @@ -283,7 +281,6 @@ public class MonsterAi extends EntityModule implements EntityMoveListener { return; } - //System.out.println("step to prey"); entity.pos.cancelPath(); entity.pos.addSteps(preyPath); } diff --git a/src/mightypork/rogue/world/entity/entities/PlayerEntity.java b/src/mightypork/rogue/world/entity/entities/PlayerEntity.java index 61af7c8..9e9183d 100644 --- a/src/mightypork/rogue/world/entity/entities/PlayerEntity.java +++ b/src/mightypork/rogue/world/entity/entities/PlayerEntity.java @@ -3,13 +3,8 @@ package mightypork.rogue.world.entity.entities; import mightypork.gamecore.util.math.algo.Coord; 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.EntityModule; -import mightypork.rogue.world.entity.EntityPathFinder; -import mightypork.rogue.world.entity.EntityType; +import mightypork.rogue.world.entity.*; import mightypork.rogue.world.entity.modules.EntityMoveListener; -import mightypork.rogue.world.entity.render.EntityRenderer; import mightypork.rogue.world.entity.render.EntityRendererMobLR; import mightypork.rogue.world.events.PlayerKilledEvent; import mightypork.rogue.world.events.PlayerStepEndEvent; @@ -21,8 +16,7 @@ public class PlayerEntity extends Entity { class PlayerAi extends EntityModule implements EntityMoveListener { - public PlayerAi(Entity entity) - { + public PlayerAi(Entity entity) { super(entity); setDespawnDelay(2); @@ -43,7 +37,7 @@ public class PlayerEntity extends Entity { final Tile t = getLevel().getTile(getCoord()); if (t.hasItem()) { final Item item = t.pickItem(); - if (getWorld().getPlayer().getInventory().addItem(item)) { + if (getWorld().getPlayer().addItem(item)) { // player picked item } else { t.dropItem(item); // put back. @@ -85,8 +79,7 @@ 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); @@ -141,5 +134,15 @@ public class PlayerEntity extends Entity { { // send kill event to listeners, after the entity has despawned (disappeared) getWorld().getEventBus().sendDelayed(new PlayerKilledEvent(), getDespawnDelay()); + + getWorld().msgDie(lastAttacker); + + } + + + @Override + public String getVisualName() + { + return "Player"; } } diff --git a/src/mightypork/rogue/world/entity/entities/RatEntity.java b/src/mightypork/rogue/world/entity/entities/RatEntity.java index 93ace9f..8754400 100644 --- a/src/mightypork/rogue/world/entity/entities/RatEntity.java +++ b/src/mightypork/rogue/world/entity/entities/RatEntity.java @@ -1,14 +1,14 @@ 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.EntityRenderer; import mightypork.rogue.world.entity.render.EntityRendererMobLR; -import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Items; @@ -22,8 +22,7 @@ public class RatEntity extends Entity { private EntityRenderer renderer; - public RatEntity(EntityModel model, int eid) - { + public RatEntity(EntityModel model, int eid) { super(model, eid); addModule("ai", ai); @@ -32,8 +31,8 @@ public class RatEntity extends Entity { pos.setStepTime(0.5); setDespawnDelay(1); - health.setMaxHealth(3 + rand.nextInt(3)); - health.fill(); // fill health bar to max + health.setMaxHealth(5); + health.setHealth(Calc.randInt(rand, 3, 5)); // fill health bar to max health.setHitCooldownTime(0.3); } @@ -77,10 +76,27 @@ public class RatEntity extends Entity { @Override public void onCorpseRemoved() { - // drop rat meat - final Item meat = Items.MEAT.createItem(); + // drop rat stuff + + if(rand.nextInt(7) == 0) { + getLevel().dropNear(getCoord(), Items.BONE.createItem()); + return; + } + + if(rand.nextInt(3) == 0) { + getLevel().dropNear(getCoord(), Items.MEAT.createItem()); + return; + } - getLevel().dropNear(getCoord(), meat); + if(rand.nextInt(2) == 0) { + getLevel().dropNear(getCoord(), Items.CHEESE.createItem()); + return; + } } + @Override + public String getVisualName() + { + return "Gray Rat"; + } } diff --git a/src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java b/src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java index a41d240..b26884e 100644 --- a/src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java +++ b/src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java @@ -13,6 +13,7 @@ import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.rogue.Res; import mightypork.rogue.world.entity.Entity; +import mightypork.rogue.world.entity.EntityRenderer; import mightypork.rogue.world.level.render.MapRenderContext; diff --git a/src/mightypork/rogue/world/gen/LevelGenerator.java b/src/mightypork/rogue/world/gen/LevelGenerator.java index dff8ee7..7f18215 100644 --- a/src/mightypork/rogue/world/gen/LevelGenerator.java +++ b/src/mightypork/rogue/world/gen/LevelGenerator.java @@ -10,6 +10,7 @@ import mightypork.rogue.world.entity.Entities; import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.gen.rooms.Rooms; import mightypork.rogue.world.gen.themes.ThemeBrick; +import mightypork.rogue.world.item.Items; import mightypork.rogue.world.level.Level; @@ -18,6 +19,7 @@ public class LevelGenerator { public static final MapTheme DUNGEON_THEME = new ThemeBrick(); + @SuppressWarnings("fallthrough") public static Level build(World world, long seed, int complexity, MapTheme theme, boolean lastLevel) { Log.f3("Generating level of complexity: " + complexity); @@ -31,16 +33,34 @@ public class LevelGenerator { // start map.addRoom(Rooms.ENTRANCE, true); - for (int i = 0; i < 1 + complexity / 2 + rand.nextInt((int) (1 + complexity * 0.3)); i++) { + for (int i = 0; i < 1 + complexity / 2 + rand.nextInt((int) (1 + complexity * 0.2)); i++) { map.addRoom(Rooms.BASIC, false); if (rand.nextInt(7) > 0) map.addRoom(Rooms.SECRET, false); - if (rand.nextInt(6) > 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); map.buildCorridors(); + switch(complexity) { + default: + case 3: + case 2: + if(rand.nextInt(2)==0) map.dropInMap(Items.CLUB.createItem(), 50); + case 1: + case 0: + if(rand.nextInt(2)==0) map.dropInMap(Items.ROCK.createItem(), 50); + } + + if(complexity == 6) { + map.dropInMap(Items.SWORD.createItem(), 200); + } + + if(complexity == 5) { + map.dropInMap(Items.HAMMER.createItem(), 100); + } + final Coord size = map.getNeededSize(); final Level lvl = new Level(size.x, size.y); @@ -49,6 +69,8 @@ public class LevelGenerator { // 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++) { @@ -62,20 +84,6 @@ public class LevelGenerator { } } -// for (int i = 0; i < 4 + complexity + rand.nextInt(1 + complexity); i++) { -// -// final Item meat = Items.MEAT.createItem(); -// -// for (int j = 0; j < 20; j++) { -// pos.x = rand.nextInt(lvl.getWidth()); -// pos.y = rand.nextInt(lvl.getHeight()); -// -// final Tile t = lvl.getTile(pos); -// if (t.dropItem(meat)) break; -// } -// } - - return lvl; } } diff --git a/src/mightypork/rogue/world/gen/ScratchMap.java b/src/mightypork/rogue/world/gen/ScratchMap.java index cbbd0a4..1d976c5 100644 --- a/src/mightypork/rogue/world/gen/ScratchMap.java +++ b/src/mightypork/rogue/world/gen/ScratchMap.java @@ -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.item.Item; import mightypork.rogue.world.level.Level; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.TileModel; @@ -42,7 +43,7 @@ public class ScratchMap { public boolean isAccessible(Coord pos) { if (!isIn(pos)) return false; - final Tile t = get(pos); + final Tile t = getTile(pos); if (t.isStairs()) return false; return t.isPotentiallyWalkable() || (t.genData.protection != TileProtectLevel.STRONG); } @@ -51,7 +52,7 @@ public class ScratchMap { @Override public int getCost(Coord last, Coord pos) { - final Tile t = get(pos); + final Tile t = getTile(pos); switch (t.getType()) { case NULL: @@ -173,7 +174,7 @@ public class ScratchMap { clampBounds(); nodes.add(center); -// Log.f3("placed room: " + rd.min + " -> " + rd.max); + Log.f3("Placed room on " + Calc.ordinal(1+failed_total) + " try."); return; } else { @@ -222,7 +223,7 @@ public class ScratchMap { } - public Tile get(Coord pos) + public Tile getTile(Coord pos) { if (!isIn(pos)) { throw new IndexOutOfBoundsException("Tile not in map: " + pos); @@ -267,7 +268,7 @@ public class ScratchMap { final Coord c = Coord.make(0, 0); for (c.x = min.x; c.x <= max.x; c.x++) for (c.y = min.y; c.y <= max.y; c.y++) - get(c).genData.protection = prot; + getTile(c).genData.protection = prot; } @@ -357,7 +358,7 @@ public class ScratchMap { genMax.y = Math.max(genMax.y, c.y); clampBounds(); - final Tile current = get(c); + final Tile current = getTile(c); if (!current.isNull() && (current.isPotentiallyWalkable() || current.isStairs())) continue; // floor already, let it be if (i == 0 && j == 0) { @@ -394,7 +395,7 @@ public class ScratchMap { final Coord cc = pos.add(Sides.get(i)); if (!isIn(cc)) continue; - if (get(cc).isWall()) { + if (getTile(cc).isWall()) { walls |= Sides.bit(i); } } @@ -409,7 +410,7 @@ public class ScratchMap { final Coord cc = pos.add(Sides.get(i)); if (!isIn(cc)) continue; - if (get(cc).isFloor()) { + if (getTile(cc).isFloor()) { floors |= Sides.bit(i); } } @@ -424,7 +425,7 @@ public class ScratchMap { final Coord cc = pos.add(Sides.get(i)); if (!isIn(cc)) continue; - if (get(cc).isDoor()) { + if (getTile(cc).isDoor()) { doors |= Sides.bit(i); } } @@ -438,7 +439,7 @@ public class ScratchMap { for (int i = 0; i <= 7; i++) { final Coord cc = pos.add(Sides.get(i)); - if (!isIn(cc) || get(cc).isNull()) { + if (!isIn(cc) || getTile(cc).isNull()) { nils |= Sides.bit(i); } } @@ -459,7 +460,7 @@ public class ScratchMap { for (c.x = 0; c.x < width; c.x++) { for (c.y = 0; c.y < height; c.y++) { - final Tile t = get(c); + final Tile t = getTile(c); final boolean isNull = t.isNull(); final boolean isDoor = !isNull && t.isDoor(); @@ -533,14 +534,13 @@ public class ScratchMap { for (c.x = genMin.x, c1.x = 0; c.x <= genMax.x; c.x++, c1.x++) { for (c.y = genMin.y, c1.y = 0; c.y <= genMax.y; c.y++, c1.y++) { - level.setTile(c1, get(c)); + level.setTile(c1, getTile(c)); } } final Coord entrance = new Coord(enterPoint.x - genMin.x, enterPoint.y - genMin.y); level.setEnterPoint(entrance); -// System.out.println("Entrance = " + entrance + ", original: " + enterPoint + ", minG=" + genMin + ", maxG=" + genMax); - + final Coord exit = new Coord(exitPoint.x - genMin.x, exitPoint.y - genMin.y); level.setExitPoint(exit); } @@ -556,4 +556,26 @@ public class ScratchMap { { exitPoint.setTo(pos); } + + + public boolean dropInArea(Item item, Coord min, Coord max, int tries) + { + Coord pos = Coord.zero(); + + for(int i=0; i0) uses--; + if(uses==0) consume(); + } + + + public abstract boolean isDamageable(); + + + public abstract String getVisualName(); } diff --git a/src/mightypork/rogue/world/item/ItemModel.java b/src/mightypork/rogue/world/item/ItemModel.java index b04dd05..173d69e 100644 --- a/src/mightypork/rogue/world/item/ItemModel.java +++ b/src/mightypork/rogue/world/item/ItemModel.java @@ -19,8 +19,7 @@ public final class ItemModel { public final Class itemClass; - public ItemModel(int id, Class item) - { + public ItemModel(int id, Class item) { Items.register(id, this); this.id = id; this.itemClass = item; @@ -30,10 +29,15 @@ public final class ItemModel { /** * @return new item instance of this type */ - public T createItem() + public Item createItem() { try { - return (T) itemClass.getConstructor(ItemModel.class).newInstance(this); + Item itm = itemClass.getConstructor(ItemModel.class).newInstance(this); + + itm.setRemainingUses(itm.getMaxUses()); + + return itm; + } catch (final Exception e) { throw new RuntimeException("Could not instantiate an item.", e); } diff --git a/src/mightypork/rogue/world/item/ItemRenderer.java b/src/mightypork/rogue/world/item/ItemRenderer.java index 61b936d..d4a26e3 100644 --- a/src/mightypork/rogue/world/item/ItemRenderer.java +++ b/src/mightypork/rogue/world/item/ItemRenderer.java @@ -6,6 +6,16 @@ import mightypork.gamecore.util.math.constraints.rect.Rect; public abstract class ItemRenderer { + protected final Item item; + + + + public ItemRenderer(Item item) { + this.item = item; + } + + + public abstract void render(Rect r); } diff --git a/src/mightypork/rogue/world/item/Items.java b/src/mightypork/rogue/world/item/Items.java index ecc872e..a7ebd0b 100644 --- a/src/mightypork/rogue/world/item/Items.java +++ b/src/mightypork/rogue/world/item/Items.java @@ -6,7 +6,14 @@ import java.util.Collection; import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonOutput; -import mightypork.rogue.world.item.items.ItemMeat; +import mightypork.rogue.world.item.items.food.ItemCheese; +import mightypork.rogue.world.item.items.food.ItemMeat; +import mightypork.rogue.world.item.items.food.ItemSandwich; +import mightypork.rogue.world.item.items.weapons.ItemBone; +import mightypork.rogue.world.item.items.weapons.ItemClub; +import mightypork.rogue.world.item.items.weapons.ItemHammer; +import mightypork.rogue.world.item.items.weapons.ItemStone; +import mightypork.rogue.world.item.items.weapons.ItemSword; /** @@ -19,6 +26,13 @@ public final class Items { private static final ItemModel[] items = new ItemModel[256]; public static final ItemModel MEAT = new ItemModel(1, ItemMeat.class); + public static final ItemModel CHEESE = new ItemModel(2, ItemCheese.class); + public static final ItemModel BONE = new ItemModel(3, ItemBone.class); + public static final ItemModel SANDWICH = new ItemModel(4, ItemSandwich.class); + public static final ItemModel CLUB = new ItemModel(5, ItemClub.class); + public static final ItemModel HAMMER = new ItemModel(6, ItemHammer.class); + public static final ItemModel SWORD = new ItemModel(7, ItemSword.class); + public static final ItemModel ROCK = new ItemModel(8, ItemStone.class); public static void register(int id, ItemModel model) diff --git a/src/mightypork/rogue/world/item/items/ItemBaseFood.java b/src/mightypork/rogue/world/item/items/ItemBaseFood.java index dcfa2d8..a539334 100644 --- a/src/mightypork/rogue/world/item/items/ItemBaseFood.java +++ b/src/mightypork/rogue/world/item/items/ItemBaseFood.java @@ -34,4 +34,15 @@ public abstract class ItemBaseFood extends Item { return ItemType.FOOD; } + @Override + public boolean isDamageable() + { + return false; + } + + @Override + public int getMaxUses() + { + return 1; + } } diff --git a/src/mightypork/rogue/world/item/items/ItemBaseWeapon.java b/src/mightypork/rogue/world/item/items/ItemBaseWeapon.java index 1b6e474..394a25e 100644 --- a/src/mightypork/rogue/world/item/items/ItemBaseWeapon.java +++ b/src/mightypork/rogue/world/item/items/ItemBaseWeapon.java @@ -34,4 +34,10 @@ public abstract class ItemBaseWeapon extends Item { return ItemType.WEAPON; } + @Override + public boolean isDamageable() + { + return true; + } + } diff --git a/src/mightypork/rogue/world/item/items/food/ItemCheese.java b/src/mightypork/rogue/world/item/items/food/ItemCheese.java new file mode 100644 index 0000000..d90ab8b --- /dev/null +++ b/src/mightypork/rogue/world/item/items/food/ItemCheese.java @@ -0,0 +1,38 @@ +package mightypork.rogue.world.item.items.food; + + +import mightypork.rogue.Res; +import mightypork.rogue.world.item.ItemModel; +import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseFood; +import mightypork.rogue.world.item.render.QuadItemRenderer; + + +public class ItemCheese extends ItemBaseFood { + + public ItemCheese(ItemModel model) + { + super(model); + } + + + @Override + protected ItemRenderer makeRenderer() + { + return new QuadItemRenderer(this, Res.txq("item.cheese")); + } + + + @Override + public int getFoodPoints() + { + return 2; + } + + + @Override + public String getVisualName() + { + return "Cheese"; + } +} diff --git a/src/mightypork/rogue/world/item/items/ItemMeat.java b/src/mightypork/rogue/world/item/items/food/ItemMeat.java similarity index 61% rename from src/mightypork/rogue/world/item/items/ItemMeat.java rename to src/mightypork/rogue/world/item/items/food/ItemMeat.java index c4e74bf..d5d56e4 100644 --- a/src/mightypork/rogue/world/item/items/ItemMeat.java +++ b/src/mightypork/rogue/world/item/items/food/ItemMeat.java @@ -1,9 +1,10 @@ -package mightypork.rogue.world.item.items; +package mightypork.rogue.world.item.items.food; import mightypork.rogue.Res; import mightypork.rogue.world.item.ItemModel; import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseFood; import mightypork.rogue.world.item.render.QuadItemRenderer; @@ -18,14 +19,20 @@ public class ItemMeat extends ItemBaseFood { @Override protected ItemRenderer makeRenderer() { - return new QuadItemRenderer(Res.txq("item.meat")); + return new QuadItemRenderer(this, Res.txq("item.meat")); } @Override public int getFoodPoints() { - return 2; + return 3; } + + @Override + public String getVisualName() + { + return "Chunk Of Meat"; + } } diff --git a/src/mightypork/rogue/world/item/items/food/ItemSandwich.java b/src/mightypork/rogue/world/item/items/food/ItemSandwich.java new file mode 100644 index 0000000..6378c06 --- /dev/null +++ b/src/mightypork/rogue/world/item/items/food/ItemSandwich.java @@ -0,0 +1,38 @@ +package mightypork.rogue.world.item.items.food; + + +import mightypork.rogue.Res; +import mightypork.rogue.world.item.ItemModel; +import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseFood; +import mightypork.rogue.world.item.render.QuadItemRenderer; + + +public class ItemSandwich extends ItemBaseFood { + + public ItemSandwich(ItemModel model) + { + super(model); + } + + + @Override + protected ItemRenderer makeRenderer() + { + return new QuadItemRenderer(this, Res.txq("item.sandwich")); + } + + + @Override + public int getFoodPoints() + { + return 6; + } + + + @Override + public String getVisualName() + { + return "Sandwich"; + } +} diff --git a/src/mightypork/rogue/world/item/items/weapons/ItemBone.java b/src/mightypork/rogue/world/item/items/weapons/ItemBone.java new file mode 100644 index 0000000..ca34b9a --- /dev/null +++ b/src/mightypork/rogue/world/item/items/weapons/ItemBone.java @@ -0,0 +1,39 @@ +package mightypork.rogue.world.item.items.weapons; + +import mightypork.rogue.Res; +import mightypork.rogue.world.item.ItemModel; +import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseWeapon; +import mightypork.rogue.world.item.render.QuadItemRenderer; + + +public class ItemBone extends ItemBaseWeapon { + + 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() + { + return "Bone"; + } +} \ No newline at end of file diff --git a/src/mightypork/rogue/world/item/items/weapons/ItemClub.java b/src/mightypork/rogue/world/item/items/weapons/ItemClub.java new file mode 100644 index 0000000..96e6be8 --- /dev/null +++ b/src/mightypork/rogue/world/item/items/weapons/ItemClub.java @@ -0,0 +1,39 @@ +package mightypork.rogue.world.item.items.weapons; + +import mightypork.rogue.Res; +import mightypork.rogue.world.item.ItemModel; +import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseWeapon; +import mightypork.rogue.world.item.render.QuadItemRenderer; + + +public class ItemClub extends ItemBaseWeapon { + + 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() + { + return "Wooden Club"; + } +} \ No newline at end of file diff --git a/src/mightypork/rogue/world/item/items/weapons/ItemHammer.java b/src/mightypork/rogue/world/item/items/weapons/ItemHammer.java new file mode 100644 index 0000000..d7de95e --- /dev/null +++ b/src/mightypork/rogue/world/item/items/weapons/ItemHammer.java @@ -0,0 +1,39 @@ +package mightypork.rogue.world.item.items.weapons; + +import mightypork.rogue.Res; +import mightypork.rogue.world.item.ItemModel; +import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseWeapon; +import mightypork.rogue.world.item.render.QuadItemRenderer; + + +public class ItemHammer extends ItemBaseWeapon { + + 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() + { + return "Hammer"; + } +} \ No newline at end of file diff --git a/src/mightypork/rogue/world/item/items/weapons/ItemStone.java b/src/mightypork/rogue/world/item/items/weapons/ItemStone.java new file mode 100644 index 0000000..d680dac --- /dev/null +++ b/src/mightypork/rogue/world/item/items/weapons/ItemStone.java @@ -0,0 +1,39 @@ +package mightypork.rogue.world.item.items.weapons; + +import mightypork.rogue.Res; +import mightypork.rogue.world.item.ItemModel; +import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseWeapon; +import mightypork.rogue.world.item.render.QuadItemRenderer; + + +public class ItemStone extends ItemBaseWeapon { + + 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() + { + return "Rock"; + } +} \ No newline at end of file diff --git a/src/mightypork/rogue/world/item/items/weapons/ItemSword.java b/src/mightypork/rogue/world/item/items/weapons/ItemSword.java new file mode 100644 index 0000000..efbfea5 --- /dev/null +++ b/src/mightypork/rogue/world/item/items/weapons/ItemSword.java @@ -0,0 +1,39 @@ +package mightypork.rogue.world.item.items.weapons; + +import mightypork.rogue.Res; +import mightypork.rogue.world.item.ItemModel; +import mightypork.rogue.world.item.ItemRenderer; +import mightypork.rogue.world.item.items.ItemBaseWeapon; +import mightypork.rogue.world.item.render.QuadItemRenderer; + + +public class ItemSword extends ItemBaseWeapon { + + 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"; + } +} \ No newline at end of file diff --git a/src/mightypork/rogue/world/item/render/QuadItemRenderer.java b/src/mightypork/rogue/world/item/render/QuadItemRenderer.java index 2d59ee5..7940487 100644 --- a/src/mightypork/rogue/world/item/render/QuadItemRenderer.java +++ b/src/mightypork/rogue/world/item/render/QuadItemRenderer.java @@ -3,8 +3,12 @@ package mightypork.rogue.world.item.render; import mightypork.gamecore.render.Render; import mightypork.gamecore.resources.textures.TxQuad; -import mightypork.gamecore.resources.textures.TxSheet; +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; @@ -12,16 +16,14 @@ 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(TxQuad txq) - { - this.txq = txq; - } - - public QuadItemRenderer(TxSheet txs) - { - this.txq = txs.getQuad(0); + public QuadItemRenderer(Item item, TxQuad txq) { + super(item); + this.txq = txq; } @@ -29,6 +31,23 @@ 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(); + } + } } diff --git a/src/mightypork/rogue/world/level/Level.java b/src/mightypork/rogue/world/level/Level.java index 5ef4c88..8bfb203 100644 --- a/src/mightypork/rogue/world/level/Level.java +++ b/src/mightypork/rogue/world/level/Level.java @@ -86,13 +86,11 @@ 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(); } @@ -128,7 +126,7 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl public final Tile getTile(Coord pos) { if (!pos.isInRange(0, 0, size.x - 1, size.y - 1)) return Tiles.NULL.createTile(); // out of range - + return tiles[pos.y][pos.x]; } @@ -589,6 +587,11 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl } } + if (!getTile(pos).isWalkable()) { + // this should never happen. + setTile(pos, Tiles.BRICK_FLOOR.createTile()); + } + } diff --git a/src/mightypork/rogue/world/tile/Tile.java b/src/mightypork/rogue/world/tile/Tile.java index 6177872..a5dc18e 100644 --- a/src/mightypork/rogue/world/tile/Tile.java +++ b/src/mightypork/rogue/world/tile/Tile.java @@ -12,6 +12,7 @@ import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonObjBlob; import mightypork.gamecore.util.ion.IonOutput; import mightypork.gamecore.util.math.color.Color; +import mightypork.rogue.Config; import mightypork.rogue.world.World; import mightypork.rogue.world.item.Item; import mightypork.rogue.world.level.Level; @@ -56,7 +57,7 @@ public abstract class Tile implements BusAccess, IonObjBlob { @DefaultImpl public void renderTile(TileRenderContext context) { - if (!isExplored()) return; + if (!isExplored() && Config.RENDER_UFOG) return; initRenderer(); diff --git a/src/mightypork/rogue/world/tile/TileRenderer.java b/src/mightypork/rogue/world/tile/TileRenderer.java index d8a8c7f..cb6a14d 100644 --- a/src/mightypork/rogue/world/tile/TileRenderer.java +++ b/src/mightypork/rogue/world/tile/TileRenderer.java @@ -6,6 +6,7 @@ import mightypork.gamecore.render.Render; import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.constraints.rect.Rect; +import mightypork.rogue.Config; import mightypork.rogue.Res; import mightypork.rogue.world.level.render.TileRenderContext; import mightypork.rogue.world.tile.render.NullTileRenderer; @@ -104,6 +105,8 @@ public abstract class TileRenderer implements Updateable { public void renderUnexploredFog(TileRenderContext context) { + if(!Config.RENDER_UFOG) return; + // TODO cache values, update neighbouring tiles upon "explored" flag changed. byte ufog = 0; diff --git a/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java b/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java index ebfaa4d..aa67b49 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java +++ b/src/mightypork/rogue/world/tile/tiles/TileBaseSecretDoor.java @@ -30,7 +30,10 @@ public abstract class TileBaseSecretDoor extends TileBaseDoor { if (clicks > 0) clicks--; - if (clicks == 0) locked = false; + if (clicks == 0) { + locked = false; + getWorld().msgDiscoverSecretDoor(); + } return true; } diff --git a/src/mightypork/rogue/world/tile/tiles/TileWithItems.java b/src/mightypork/rogue/world/tile/tiles/TileWithItems.java index 8e2bf3c..caff12d 100644 --- a/src/mightypork/rogue/world/tile/tiles/TileWithItems.java +++ b/src/mightypork/rogue/world/tile/tiles/TileWithItems.java @@ -6,6 +6,7 @@ import java.util.Stack; import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonOutput; +import mightypork.rogue.Config; import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Items; import mightypork.rogue.world.level.render.TileRenderContext; @@ -21,8 +22,7 @@ public abstract class TileWithItems extends Tile { protected final Stack items = new Stack<>(); - public TileWithItems(TileModel model) - { + public TileWithItems(TileModel model) { super(model); } @@ -30,7 +30,7 @@ public abstract class TileWithItems extends Tile { @Override public void renderExtra(TileRenderContext context) { - if (isExplored() && !items.isEmpty()) { + if ((isExplored() || !Config.RENDER_UFOG) && !items.isEmpty()) { itemRenderer.render(items.peek(), context); } } @@ -98,18 +98,18 @@ public abstract class TileWithItems extends Tile { } - @Override - public boolean onClick() - { - if (hasItem()) { - final Item item = pickItem(); - if (getWorld().getPlayer().getInventory().addItem(item)) { - // player picked item - } else { - dropItem(item); // put back. - } - return true; - } - return false; - } +// @Override +// public boolean onClick() +// { +// if (hasItem()) { +// final Item item = pickItem(); +// if (getWorld().getPlayer().addItem(item)) { +// // player picked item +// } else { +// dropItem(item); // put back. +// } +// return true; +// } +// return false; +// } }