diff --git a/src/main/java/betterquesting/api/storage/BQ_Settings.java b/src/main/java/betterquesting/api/storage/BQ_Settings.java index 62c742e6f..61344c366 100644 --- a/src/main/java/betterquesting/api/storage/BQ_Settings.java +++ b/src/main/java/betterquesting/api/storage/BQ_Settings.java @@ -1,9 +1,8 @@ package betterquesting.api.storage; import betterquesting.core.ModReference; -import net.minecraft.util.ResourceLocation; - import java.io.File; +import net.minecraft.util.ResourceLocation; /** * A container for all the configurable settings in the mod @@ -37,4 +36,5 @@ public class BQ_Settings { public static String defaultVisibility = "NORMAL"; public static boolean spawnWithQuestBook = true; + public static boolean taskFoldedInitially = false; } diff --git a/src/main/java/betterquesting/api/utils/RenderUtils.java b/src/main/java/betterquesting/api/utils/RenderUtils.java index c11c5fadd..93400d3fd 100644 --- a/src/main/java/betterquesting/api/utils/RenderUtils.java +++ b/src/main/java/betterquesting/api/utils/RenderUtils.java @@ -1,5 +1,14 @@ package betterquesting.api.utils; +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import javax.annotation.Nonnull; + +import org.lwjgl.opengl.GL11; + import betterquesting.api2.client.gui.misc.GuiRectangle; import betterquesting.api2.client.gui.misc.IGuiRect; import betterquesting.api2.client.gui.resources.colors.GuiColorStatic; @@ -8,7 +17,12 @@ import betterquesting.core.BetterQuesting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; @@ -19,18 +33,14 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -import org.lwjgl.opengl.GL11; - -import javax.annotation.Nonnull; -import java.awt.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; // TODO: Move text related stuff to its own utility class @SideOnly(Side.CLIENT) public class RenderUtils { + public static final String REGEX_NUMBER = "[^\\.0123456789-]"; // I keep screwing this up so now it's reusable + // Saves me having to run the math function every frame + private static final double RAD = Math.toRadians(360F); public static void RenderItemStack(Minecraft mc, ItemStack stack, int x, int y, String text) { RenderItemStack(mc, stack, x, y, text, Color.WHITE.getRGB()); @@ -65,7 +75,8 @@ public static void RenderItemStack(Minecraft mc, ItemStack stack, int x, int y, itemRender.zLevel = -150F; // Counters internal Z depth change so that GL translation makes sense FontRenderer font = stack.getItem().getFontRenderer(stack); - if (font == null) font = mc.fontRenderer; + if (font == null) + font = mc.fontRenderer; try { itemRender.renderItemAndEffectIntoGUI(stack, x, y); @@ -206,11 +217,42 @@ public static void drawSplitString(FontRenderer renderer, String string, int x, // TODO: Clean this up. The list of parameters is getting a bit excessive - public static void drawHighlightedSplitString(FontRenderer renderer, String string, int x, int y, int width, int color, boolean shadow, int highlightColor, int highlightStart, int highlightEnd) { - drawHighlightedSplitString(renderer, string, x, y, width, color, shadow, 0, splitString(string, width, renderer).size() - 1, highlightColor, highlightStart, highlightEnd); + public static void drawHighlightedSplitString(FontRenderer renderer, + String string, + int x, + int y, + int width, + int color, + boolean shadow, + int highlightColor, + int highlightStart, + int highlightEnd) { + drawHighlightedSplitString(renderer, + string, + x, + y, + width, + color, + shadow, + 0, + splitString(string, width, renderer).size() - 1, + highlightColor, + highlightStart, + highlightEnd); } - public static void drawHighlightedSplitString(FontRenderer renderer, String string, int x, int y, int width, int color, boolean shadow, int start, int end, int highlightColor, int highlightStart, int highlightEnd) { + public static void drawHighlightedSplitString(FontRenderer renderer, + String string, + int x, + int y, + int width, + int color, + boolean shadow, + int start, + int end, + int highlightColor, + int highlightStart, + int highlightEnd) { if (renderer == null || string == null || string.length() <= 0 || start > end) { return; } @@ -248,22 +290,22 @@ public static void drawHighlightedSplitString(FontRenderer renderer, String stri renderer.drawString(list.get(i), x, y + (renderer.FONT_HEIGHT * (i - start)), color, shadow); // DEBUG - /*boolean b = (System.currentTimeMillis()/1000)%2 == 0; - - if(b) - { - renderer.drawString(i + ": " + list.get(i), x, y + (renderer.FONT_HEIGHT * (i - start)), color, shadow); - } - - if(i >= noFormat.size()) - { - continue; - } - - if(!b) - { - renderer.drawString(i + ": " + noFormat.get(i), x, y + (renderer.FONT_HEIGHT * (i - start)), color, shadow); - }*/ + /*boolean b = (System.currentTimeMillis()/1000)%2 == 0; + + if(b) + { + renderer.drawString(i + ": " + list.get(i), x, y + (renderer.FONT_HEIGHT * (i - start)), color, shadow); + } + + if(i >= noFormat.size()) + { + continue; + } + + if(!b) + { + renderer.drawString(i + ": " + noFormat.get(i), x, y + (renderer.FONT_HEIGHT * (i - start)), color, shadow); + }*/ int lineSize = noFormat.get(i).length(); int idxEnd = idxStart + lineSize; @@ -276,14 +318,26 @@ public static void drawHighlightedSplitString(FontRenderer renderer, String stri int x1 = getStringWidth(lastFormat + noFormat.get(i).substring(0, i1), renderer); int x2 = getStringWidth(lastFormat + noFormat.get(i).substring(0, i2), renderer); - drawHighlightBox(x + x1, y + (renderer.FONT_HEIGHT * (i - start)), x + x2, y + (renderer.FONT_HEIGHT * (i - start)) + renderer.FONT_HEIGHT, highlightColor); + drawHighlightBox(x + x1, + y + (renderer.FONT_HEIGHT * (i - start)), + x + x2, + y + (renderer.FONT_HEIGHT * (i - start)) + renderer.FONT_HEIGHT, + highlightColor); } idxStart = idxEnd; } } - public static void drawHighlightedString(FontRenderer renderer, String string, int x, int y, int color, boolean shadow, int highlightColor, int highlightStart, int highlightEnd) { + public static void drawHighlightedString(FontRenderer renderer, + String string, + int x, + int y, + int color, + boolean shadow, + int highlightColor, + int highlightStart, + int highlightEnd) { if (renderer == null || string == null || string.length() <= 0) { return; } @@ -356,7 +410,10 @@ public static void drawColoredRect(IGuiRect rect, IGuiColor color) { BufferBuilder vertexbuffer = tessellator.getBuffer(); GlStateManager.enableBlend(); GlStateManager.disableTexture2D(); - GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); color.applyGlColor(); vertexbuffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); vertexbuffer.pos((double) rect.getX(), (double) rect.getY() + rect.getHeight(), 0.0D).endVertex(); @@ -659,18 +716,33 @@ public static int lerpRGB(int c1, int c2, float blend) { return (a3 << 24) + (r3 << 16) + (g3 << 8) + b3; } - public static void drawHoveringText(List textLines, int mouseX, int mouseY, int screenWidth, int screenHeight, int maxTextWidth, FontRenderer font) { + public static void drawHoveringText(List textLines, + int mouseX, + int mouseY, + int screenWidth, + int screenHeight, + int maxTextWidth, + FontRenderer font) { drawHoveringText(ItemStack.EMPTY, textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, font); } /** * Modified version of Forge's tooltip rendering that doesn't adjust Z depth */ - public static void drawHoveringText(@Nonnull final ItemStack stack, List textLines, int mouseX, int mouseY, int screenWidth, int screenHeight, int maxTextWidth, FontRenderer font) { - if (textLines == null || textLines.isEmpty()) return; + public static void drawHoveringText(@Nonnull final ItemStack stack, + List textLines, + int mouseX, + int mouseY, + int screenWidth, + int screenHeight, + int maxTextWidth, + FontRenderer font) { + if (textLines == null || textLines.isEmpty()) + return; RenderTooltipEvent.Pre event = new RenderTooltipEvent.Pre(stack, textLines, mouseX, mouseY, screenWidth, screenHeight, maxTextWidth, font); - if (MinecraftForge.EVENT_BUS.post(event)) return; + if (MinecraftForge.EVENT_BUS.post(event)) + return; mouseX = event.getX(); mouseY = event.getY(); @@ -766,28 +838,28 @@ public static void drawHoveringText(@Nonnull final ItemStack stack, List } else if (tooltipY + tooltipHeight + 4 > screenHeight) { tooltipY = screenHeight - tooltipHeight - 4; } - - /*int backgroundColor = 0xF0100010; - int borderColorStart = 0x505000FF; - int borderColorEnd = (borderColorStart & 0xFEFEFE) >> 1 | borderColorStart & 0xFF000000; - - RenderTooltipEvent.Color colorEvent = new RenderTooltipEvent.Color(stack, textLines, tooltipX, tooltipY, font, backgroundColor, borderColorStart, borderColorEnd); - MinecraftForge.EVENT_BUS.post(colorEvent); - backgroundColor = colorEvent.getBackground(); - borderColorStart = colorEvent.getBorderStart(); - borderColorEnd = colorEvent.getBorderEnd(); - - GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3, tooltipY - 3, backgroundColor, backgroundColor); - GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY + tooltipHeight + 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor, backgroundColor); - GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); - GuiUtils.drawGradientRect(0, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); - GuiUtils.drawGradientRect(0, tooltipX + tooltipTextWidth + 3, tooltipY - 3, tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); - GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); - GuiUtils.drawGradientRect(0, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); - GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColorStart, borderColorStart); - GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY + tooltipHeight + 2, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, borderColorEnd, borderColorEnd); - - MinecraftForge.EVENT_BUS.post(new RenderTooltipEvent.PostBackground(stack, textLines, tooltipX, tooltipY, font, tooltipTextWidth, tooltipHeight));*/ + + /*int backgroundColor = 0xF0100010; + int borderColorStart = 0x505000FF; + int borderColorEnd = (borderColorStart & 0xFEFEFE) >> 1 | borderColorStart & 0xFF000000; + + RenderTooltipEvent.Color colorEvent = new RenderTooltipEvent.Color(stack, textLines, tooltipX, tooltipY, font, backgroundColor, borderColorStart, borderColorEnd); + MinecraftForge.EVENT_BUS.post(colorEvent); + backgroundColor = colorEvent.getBackground(); + borderColorStart = colorEvent.getBorderStart(); + borderColorEnd = colorEvent.getBorderEnd(); + + GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3, tooltipY - 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY + tooltipHeight + 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(0, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(0, tooltipX + tooltipTextWidth + 3, tooltipY - 3, tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + GuiUtils.drawGradientRect(0, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColorStart, borderColorStart); + GuiUtils.drawGradientRect(0, tooltipX - 3, tooltipY + tooltipHeight + 2, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, borderColorEnd, borderColorEnd); + + MinecraftForge.EVENT_BUS.post(new RenderTooltipEvent.PostBackground(stack, textLines, tooltipX, tooltipY, font, tooltipTextWidth, tooltipHeight));*/ PresetTexture.TOOLTIP_BG.getTexture().drawTexture(tooltipX - 4, tooltipY - 4, tooltipTextWidth + 8, tooltipHeight + 8, 0F, 1F); int tooltipTop = tooltipY; @@ -818,7 +890,8 @@ public static void drawHoveringText(@Nonnull final ItemStack stack, List * A version of getStringWidth that actually behaves according to the format resetting rules of colour codes. Minecraft's built in one is busted! */ public static int getStringWidth(String text, FontRenderer font) { - if (text == null || text.length() == 0) return 0; + if (text == null || text.length() == 0) + return 0; int maxWidth = 0; int curLineWidth = 0; @@ -865,4 +938,16 @@ public static int getStringWidth(String text, FontRenderer font) { return Math.max(maxWidth, curLineWidth); } + + public static float sineWave(double periodSeconds, double phase) { + // Period in milliseconds + double pms = 1000 * periodSeconds; + // Current period time + double time = System.currentTimeMillis() % pms; + // Shift current time by phase, wrap value and scale between 0.0 - 1.0 + time = (time + (pms * phase)) % pms / pms; + // Convert time to sine wave between 0.0 and 1.0 + return (float) (Math.cos(time * RAD) / 2D + 0.5D); + } + } diff --git a/src/main/java/betterquesting/api2/client/gui/panels/content/PanelTaskOverlay.java b/src/main/java/betterquesting/api2/client/gui/panels/content/PanelTaskOverlay.java new file mode 100644 index 000000000..d6a2aad6d --- /dev/null +++ b/src/main/java/betterquesting/api2/client/gui/panels/content/PanelTaskOverlay.java @@ -0,0 +1,210 @@ +package betterquesting.api2.client.gui.panels.content; + +import java.util.List; + +import org.lwjgl.opengl.GL11; + +import betterquesting.api.utils.RenderUtils; +import betterquesting.api2.client.gui.misc.IGuiRect; +import betterquesting.api2.client.gui.panels.IGuiPanel; +import betterquesting.api2.client.gui.resources.colors.GuiColorStatic; +import betterquesting.api2.client.gui.themes.presets.PresetIcon; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; + +/** + * Displays task info over the panel. + */ +public class PanelTaskOverlay implements IGuiPanel { + + public static final float FRAME_WIDTH = 2; + + private final IGuiPanel delegate; + private State state; + private boolean consume; + private String text; // Long text will be scaled. + + public PanelTaskOverlay(IGuiPanel delegate) { this.delegate = delegate; } + + public PanelTaskOverlay setState(State state) { + this.state = state; + return this; + } + + public PanelTaskOverlay setConsume(boolean consume) { + this.consume = consume; + return this; + } + + public PanelTaskOverlay setText(String text) { + this.text = text; + return this; + } + + @Override + public void drawPanel(int mx, int my, float partialTick) { + delegate.drawPanel(mx, my, partialTick); + switch (state) { + case INCOMPLETE -> { + renderIncomplete(); + if (consume) + renderConsumeIcon(mx, my); + } + case COMPLETE -> { + renderComplete(mx, my); + } + case IN_PROGRESS -> { + renderInProgress(); + if (consume) + renderConsumeIcon(mx, my); + } + } + renderText(mx, my); + } + + // delegates + + @Override + public IGuiRect getTransform() { return delegate.getTransform(); } + + @Override + public void initPanel() { + delegate.initPanel(); + } + + @Override + public void setEnabled(boolean state) { + delegate.setEnabled(state); + } + + @Override + public boolean isEnabled() { return delegate.isEnabled(); } + + @Override + public boolean onMouseClick(int mx, int my, int button) { + return delegate.onMouseClick(mx, my, button); + } + + @Override + public boolean onMouseRelease(int mx, int my, int button) { + return delegate.onMouseRelease(mx, my, button); + } + + @Override + public boolean onMouseScroll(int mx, int my, int scroll) { + return delegate.onMouseScroll(mx, my, scroll); + } + + @Override + public boolean onKeyTyped(char c, int keycode) { + return delegate.onKeyTyped(c, keycode); + } + + @Override + public List getTooltip(int mx, int my) { + return delegate.getTooltip(mx, my); + } + + private void renderIncomplete() { + renderFrame(0.2f * RenderUtils.sineWave(2, 0) + 0.3f, 0, 0, 1); + } + + private void renderComplete(int mx, int my) { + renderFrame(0.2f, 1, 0, 1); + int size = 12; + IGuiRect rect = getTransform(); + int x = rect.getX() + rect.getWidth() - size + 2; + int y = rect.getY() - 2; + int a = getTransform().contains(mx, my) ? 100 : 255; + PresetIcon.ICON_CHECK.getTexture().drawTexture(x, y, size, size, 0, 0, new GuiColorStatic(0, 255, 0, a)); + } + + private void renderInProgress() { + float r = 0.3f * RenderUtils.sineWave(2, 0) + 0.3f; + float g = r; + renderFrame(r, g, 0, 1); + } + + private void renderFrame(float red, float green, float blue, float alpha) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder vertexbuffer = tessellator.getBuffer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); + GlStateManager.color(red, green, blue, alpha); + + vertexbuffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); + IGuiRect rect = getTransform(); + double w = FRAME_WIDTH / 2; + vertexbuffer.pos((double) rect.getX() - w, (double) rect.getY() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + rect.getWidth() + w, (double) rect.getY() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + rect.getWidth() + w, (double) rect.getY() - w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() - w, (double) rect.getY() - w, 0.0D).endVertex(); + + vertexbuffer.pos((double) rect.getX() - w, (double) rect.getY() + rect.getHeight() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + rect.getWidth() + w, (double) rect.getY() + rect.getHeight() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + rect.getWidth() + w, (double) rect.getY() + rect.getHeight() - w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() - w, (double) rect.getY() + rect.getHeight() - w, 0.0D).endVertex(); + + vertexbuffer.pos((double) rect.getX() - w, (double) rect.getY() + rect.getHeight() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + w, (double) rect.getY() + rect.getHeight() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + w, (double) rect.getY() - w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() - w, (double) rect.getY() - w, 0.0D).endVertex(); + + vertexbuffer.pos((double) rect.getX() + rect.getWidth() - w, (double) rect.getY() + rect.getHeight() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + rect.getWidth() + w, (double) rect.getY() + rect.getHeight() + w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + rect.getWidth() + w, (double) rect.getY() - w, 0.0D).endVertex(); + vertexbuffer.pos((double) rect.getX() + rect.getWidth() - w, (double) rect.getY() - w, 0.0D).endVertex(); + + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + } + + private void renderText(int mx, int my) { + GlStateManager.enableBlend(); + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + IGuiRect rect = getTransform(); + int width = fontRenderer.getStringWidth(text); + int x = rect.getX() + rect.getWidth() - width; + int y = rect.getY() + rect.getHeight() - fontRenderer.FONT_HEIGHT + 1; + int a = getTransform().contains(mx, my) ? 100 : 255; + if (x < rect.getX() + FRAME_WIDTH / 2) { + //scale to fit + float s = (rect.getWidth() - FRAME_WIDTH) / width; + float new_x = rect.getX() + FRAME_WIDTH / 2; + float new_y = y + fontRenderer.FONT_HEIGHT * (1 - s) - FRAME_WIDTH / 2; + GlStateManager.pushMatrix(); + GlStateManager.translate(new_x, new_y, 0); + GlStateManager.scale(s, s, s); + fontRenderer.drawStringWithShadow(text, 0, 0, 0xFFFFFF | (a << 24)); + GlStateManager.popMatrix(); + } else { + fontRenderer.drawStringWithShadow(text, x, y, 0xFFFFFF | (a << 24)); + } + } + + private void renderConsumeIcon(int mx, int my) { + GlStateManager.enableBlend(); + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRenderer; + IGuiRect rect = getTransform(); + int x = rect.getX() + rect.getWidth() - fontRenderer.getStringWidth("C"); + int y = rect.getY() + 1; + int a = getTransform().contains(mx, my) ? 100 : 255; + fontRenderer.drawStringWithShadow("C", x, y, 0xFFFF00 | (a << 24)); + } + + public enum State { + INCOMPLETE, + COMPLETE, + IN_PROGRESS, + } + +} diff --git a/src/main/java/betterquesting/api2/client/gui/resources/colors/GuiColorPulse.java b/src/main/java/betterquesting/api2/client/gui/resources/colors/GuiColorPulse.java index d08e4a65c..41a9c7b40 100644 --- a/src/main/java/betterquesting/api2/client/gui/resources/colors/GuiColorPulse.java +++ b/src/main/java/betterquesting/api2/client/gui/resources/colors/GuiColorPulse.java @@ -4,8 +4,6 @@ import net.minecraft.client.renderer.GlStateManager; public class GuiColorPulse implements IGuiColor { - // Saves me having to run the math function every frame - private final static double RAD = Math.toRadians(360F); private final IGuiColor c1; private final IGuiColor c2; @@ -27,37 +25,22 @@ public GuiColorPulse(IGuiColor color1, IGuiColor color2, double period, float ph @Override public int getRGB() { - // Period in milliseconds - double pms = 1000D * period; - // Current period time - double time = System.currentTimeMillis() % pms; - // Shift current time by phase, wrap value and scale between 0.0 - 1.0 - time = (time + (pms * phase)) % pms / pms; - // Convert time to sine wave between 0.0 and 1.0 - float blend = (float) (Math.cos(time * RAD) / 2D + 0.5D); + float blend = RenderUtils.sineWave(period, phase); // Return interpolated color return RenderUtils.lerpRGB(c1.getRGB(), c2.getRGB(), blend); } @Override - public float getRed() { - return (getRGB() >> 16 & 255) / 255F; - } + public float getRed() { return (getRGB() >> 16 & 255) / 255F; } @Override - public float getGreen() { - return (getRGB() >> 8 & 255) / 255F; - } + public float getGreen() { return (getRGB() >> 8 & 255) / 255F; } @Override - public float getBlue() { - return (getRGB() & 255) / 255F; - } + public float getBlue() { return (getRGB() & 255) / 255F; } @Override - public float getAlpha() { - return (getRGB() >> 24 & 255) / 255F; - } + public float getAlpha() { return (getRGB() >> 24 & 255) / 255F; } @Override public void applyGlColor() { @@ -68,4 +51,5 @@ public void applyGlColor() { float b = (float) (color & 255) / 255F; GlStateManager.color(r, g, b, a); } + } diff --git a/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java b/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java index f91329277..f81f874b4 100644 --- a/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java +++ b/src/main/java/betterquesting/api2/client/gui/themes/presets/PresetIcon.java @@ -99,7 +99,8 @@ public enum PresetIcon { ICON_MENU("icon_menu"), ICON_PATREON("icon_patreon"), - ICON_TWITCH("icon_twitch"); + ICON_TWITCH("icon_twitch"), + ICON_CHECK("icon_check"); public static final ResourceLocation TX_ICONS = new ResourceLocation(ModReference.MODID, "textures/gui/editor_icons.png"); @@ -197,5 +198,6 @@ public static void registerIcons(IThemeRegistry reg) { reg.setDefaultTexture(ICON_PATREON.key, new SimpleTexture(TX_ICONS, new GuiRectangle(144, 80, 16, 16)).maintainAspect(true)); reg.setDefaultTexture(ICON_TWITCH.key, new SimpleTexture(TX_ICONS, new GuiRectangle(160, 80, 16, 16)).maintainAspect(true)); + reg.setDefaultTexture(ICON_CHECK.key, new SimpleTexture(TX_ICONS, new GuiRectangle(0, 48, 16, 16)).maintainAspect(true)); } } diff --git a/src/main/java/betterquesting/client/gui2/GuiQuest.java b/src/main/java/betterquesting/client/gui2/GuiQuest.java index 4b9931def..4d3c9c6b0 100644 --- a/src/main/java/betterquesting/client/gui2/GuiQuest.java +++ b/src/main/java/betterquesting/client/gui2/GuiQuest.java @@ -16,16 +16,23 @@ import betterquesting.api2.client.gui.events.PEventBroadcaster; import betterquesting.api2.client.gui.events.PanelEvent; import betterquesting.api2.client.gui.events.types.PEventButton; -import betterquesting.api2.client.gui.misc.*; +import betterquesting.api2.client.gui.misc.GuiAlign; +import betterquesting.api2.client.gui.misc.GuiPadding; +import betterquesting.api2.client.gui.misc.GuiRectangle; +import betterquesting.api2.client.gui.misc.GuiTransform; +import betterquesting.api2.client.gui.misc.IGuiRect; import betterquesting.api2.client.gui.panels.CanvasEmpty; import betterquesting.api2.client.gui.panels.CanvasTextured; import betterquesting.api2.client.gui.panels.IGuiPanel; import betterquesting.api2.client.gui.panels.bars.PanelVScrollBar; +import betterquesting.api2.client.gui.panels.content.PanelGeneric; import betterquesting.api2.client.gui.panels.content.PanelLine; import betterquesting.api2.client.gui.panels.content.PanelTextBox; import betterquesting.api2.client.gui.panels.lists.CanvasScrolling; import betterquesting.api2.client.gui.popups.PopContextMenu; +import betterquesting.api2.client.gui.resources.colors.GuiColorStatic; import betterquesting.api2.client.gui.themes.presets.PresetColor; +import betterquesting.api2.client.gui.themes.presets.PresetIcon; import betterquesting.api2.client.gui.themes.presets.PresetLine; import betterquesting.api2.client.gui.themes.presets.PresetTexture; import betterquesting.api2.storage.DBEntry; @@ -36,18 +43,15 @@ import betterquesting.network.handlers.NetQuestAction; import betterquesting.questing.QuestDatabase; import betterquesting.questing.tasks.TaskRetrieval; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.resources.I18n; -import org.lwjgl.util.vector.Vector4f; - import java.util.HashMap; import java.util.List; import java.util.Map; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; +import org.lwjgl.util.vector.Vector4f; public class GuiQuest extends GuiScreenCanvas implements IPEventListener, INeedsRefresh { - /* * Map which contains scrolls positions. > */ @@ -62,6 +66,7 @@ public class GuiQuest extends GuiScreenCanvas implements IPEventListener, INeeds private PanelButton btnClaim; private CanvasEmpty cvInner; + private PanelTextBox logicTitle; private IGuiRect rectReward; private IGuiRect rectTask; @@ -101,7 +106,9 @@ public void initPanel() { PEventBroadcaster.INSTANCE.register(this, PEventButton.class); // Background panel - CanvasTextured cvBackground = new CanvasTextured(new GuiTransform(GuiAlign.FULL_BOX, new GuiPadding(0, 0, 0, 0), 0), PresetTexture.PANEL_MAIN.getTexture()) { + CanvasTextured cvBackground = new CanvasTextured(new GuiTransform(GuiAlign.FULL_BOX, new GuiPadding(0, 0, 0, 0), 0), + PresetTexture.PANEL_MAIN.getTexture()) { + @Override public boolean onMouseClick(int mx, int my, int click) { if (click != 1) { @@ -139,16 +146,27 @@ else if (rectReward != null && rectReward.contains(mx, my) && QuestingAPI.getAPI return super.onMouseClick(mx, my, click); } } + }; this.addPanel(cvBackground); - PanelTextBox panTxt = new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 16, 0, -32), 0), QuestTranslation.translate(quest.getProperty(NativeProps.NAME))).setAlignment(1); + PanelTextBox panTxt = new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 16, 0, -32), 0), + QuestTranslation.translate(quest.getProperty(NativeProps.NAME))).setAlignment(1); panTxt.setColor(PresetColor.TEXT_HEADER.getColor()); cvBackground.addPanel(panTxt); + if (quest.getTasks().getEntries().size() > 1) { + // The text will be set in refreshGui() + logicTitle = new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 16, 16, -32), 0), QuestTranslation.translate("betterquesting.btn.logic") + ": " + quest.getProperty(NativeProps.LOGIC_TASK)).setAlignment(2); + logicTitle.setColor(PresetColor.TEXT_HEADER.getColor()); + cvBackground.addPanel(logicTitle); + } + if (QuestingAPI.getAPI(ApiReference.SETTINGS).canUserEdit(mc.player)) { cvBackground.addPanel(new PanelButton(new GuiTransform(GuiAlign.BOTTOM_CENTER, -100, -16, 100, 16, 0), 0, QuestTranslation.translate("gui.back"))); - cvBackground.addPanel(new PanelButton(new GuiTransform(GuiAlign.BOTTOM_CENTER, 0, -16, 100, 16, 0), 1, QuestTranslation.translate("betterquesting.btn.edit"))); + cvBackground.addPanel(new PanelButton(new GuiTransform(GuiAlign.BOTTOM_CENTER, 0, -16, 100, 16, 0), + 1, + QuestTranslation.translate("betterquesting.btn.edit"))); } else { cvBackground.addPanel(new PanelButton(new GuiTransform(GuiAlign.BOTTOM_CENTER, -100, -16, 200, 16, 0), 0, QuestTranslation.translate("gui.back"))); } @@ -160,7 +178,9 @@ else if (rectReward != null && rectReward.contains(mx, my) && QuestingAPI.getAPI refreshDescPanel(true); - btnClaim = new PanelButton(new GuiTransform(new Vector4f(0F, 1F, 0.5F, 1F), new GuiPadding(0, -16, 8, 0), 0), 6, QuestTranslation.translate("betterquesting.btn.claim")); + btnClaim = new PanelButton(new GuiTransform(new Vector4f(0F, 1F, 0.5F, 1F), new GuiPadding(0, -16, 8, 0), 0), + 6, + QuestTranslation.translate("betterquesting.btn.claim")); btnClaim.setActive(false); cvInner.addPanel(btnClaim); @@ -172,16 +192,19 @@ else if (rectReward != null && rectReward.contains(mx, my) && QuestingAPI.getAPI refreshDescPanel(false); } - btnDetect = new PanelButton(new GuiTransform(new Vector4f(0.5F, 1F, 1F, 1F), new GuiPadding(8, -16, 0, 0), 0), 7, QuestTranslation.translate("betterquesting.btn.detect_submit")); + btnDetect = new PanelButton(new GuiTransform(new Vector4f(0.5F, 1F, 1F, 1F), new GuiPadding(8, -16, 0, 0), 0), + 7, + QuestTranslation.translate("betterquesting.btn.detect_submit")); btnDetect.setActive(false); cvInner.addPanel(btnDetect); - rectTask = new GuiTransform(GuiAlign.HALF_RIGHT, new GuiPadding(8, 0, 0, 16), 0); + rectTask = new GuiTransform(GuiAlign.HALF_RIGHT, new GuiPadding(0, 0, 0, 16), 0); rectTask.setParent(cvInner.getTransform()); refreshTaskPanel(); CanvasEmpty cvTaskPopup = new CanvasEmpty(rectTask) { + @Override public boolean onMouseClick(int mx, int my, int click) { if (click != 1) @@ -197,6 +220,7 @@ public boolean onMouseClick(int mx, int my, int click) { } else return false; } + }; cvInner.addPanel(cvTaskPopup); @@ -210,6 +234,9 @@ public boolean onMouseClick(int mx, int my, int click) { @Override public void refreshGui() { + if (logicTitle != null) + logicTitle.setText(QuestTranslation.translate("betterquesting.btn.logic") + ": " + quest.getProperty(NativeProps.LOGIC_TASK)); + this.refreshTaskPanel(); this.refreshRewardPanel(); this.updateButtons(); @@ -293,9 +320,13 @@ private void onButtonPress(PEventButton event) { } else if (btn.getButtonID() == 1) { // Edit mc.displayGuiScreen(new GuiQuestEditor(this, questID)); } else if (btn.getButtonID() == 6) { // Reward claim - NetQuestAction.requestClaim(new int[]{questID}); + NetQuestAction.requestClaim(new int[]{ + questID + }); } else if (btn.getButtonID() == 7) { // Task detect/submit - NetQuestAction.requestDetect(new int[]{questID}); + NetQuestAction.requestDetect(new int[]{ + questID + }); } } @@ -324,18 +355,25 @@ private void refreshRewardPanel() { for (DBEntry entry : quest.getRewards().getEntries()) { IReward rew = entry.getValue(); - PanelTextBox titleReward = new PanelTextBox(new GuiTransform(new Vector4f(), 0, yOffset, rectReward.getWidth(), 12, 0), QuestTranslation.translate(rew.getUnlocalisedName())); + PanelTextBox titleReward = new PanelTextBox(new GuiTransform(new Vector4f(), 0, yOffset, rectReward.getWidth(), 12, 0), + QuestTranslation.translate(rew.getUnlocalisedName())); titleReward.setColor(PresetColor.TEXT_HEADER.getColor()).setAlignment(1); titleReward.setEnabled(true); csReward.addPanel(titleReward); yOffset += 12; - IGuiPanel rewardGui = rew.getRewardGui(new GuiTransform(GuiAlign.FULL_BOX, 0, 0, rectReward.getWidth(), rectReward.getHeight(), 111), new DBEntry<>(questID, quest)); + IGuiPanel rewardGui = rew.getRewardGui(new GuiTransform(GuiAlign.FULL_BOX, 0, 0, rectReward.getWidth(), rectReward.getHeight(), 111), + new DBEntry<>(questID, quest)); rewardGui.initPanel(); // Wrapping into canvas to avoid empty space at end - CanvasEmpty tempCanvas = new CanvasEmpty(new GuiTransform(GuiAlign.TOP_LEFT, 0, yOffset, rectReward.getWidth(), rewardGui.getTransform().getHeight() - rewardGui.getTransform().getY(), 1)); + CanvasEmpty tempCanvas = new CanvasEmpty(new GuiTransform(GuiAlign.TOP_LEFT, + 0, + yOffset, + rectReward.getWidth(), + rewardGui.getTransform().getHeight() - rewardGui.getTransform().getY(), + 1)); csReward.addPanel(tempCanvas); tempCanvas.addPanel(rewardGui); @@ -366,12 +404,6 @@ private void refreshTaskPanel() { int yOffset = 0; List> entries = quest.getTasks().getEntries(); - if (entries.size() > 1) { - PanelTextBox logicTitle = new PanelTextBox(new GuiTransform(new Vector4f(), 0, yOffset, rectTask.getWidth(), 12, 0), I18n.format("betterquesting.btn.task_logic",quest.getProperty(NativeProps.LOGIC_TASK))); - logicTitle.setColor(PresetColor.TEXT_HEADER.getColor()); - csTask.addPanel(logicTitle); - yOffset += 12; - } for (int i = 0; i < entries.size(); i++) { ITask tsk = entries.get(i).getValue(); @@ -381,19 +413,41 @@ private void refreshTaskPanel() { if (entryLogic != EnumLogic.AND) taskName += " (" + entryLogic + ")"; } - PanelTextBox titleReward = new PanelTextBox(new GuiTransform(new Vector4f(), 0, yOffset, rectTask.getWidth(), 12, 0), taskName); + PanelTextBox titleReward = new PanelTextBox(new GuiTransform(new Vector4f(), 0, yOffset, csTask.getTransform().getWidth(), 12, 0), taskName); titleReward.setColor(PresetColor.TEXT_HEADER.getColor()).setAlignment(1); titleReward.setEnabled(true); csTask.addPanel(titleReward); + // Display checkmark if completed + if (tsk.isComplete(QuestingAPI.getQuestingUUID(Minecraft.getMinecraft().player))) { + int size = 18; + int x = csTask.getTransform().getWidth() / 2; + int y = yOffset - 4; + PanelGeneric panel = new PanelGeneric(new GuiTransform(new Vector4f(), x, y, size, size, 0), + PresetIcon.ICON_CHECK.getTexture(), + new GuiColorStatic(0, 255, 0, 255)); + csTask.addPanel(panel); + } + yOffset += 10; - IGuiPanel taskGui = tsk.getTaskGui(new GuiTransform(GuiAlign.FULL_BOX, 0, i == 0 && entries.size() == 1 && tsk.displaysCenteredAlone() ? rectTask.getHeight() / 3 : 0, rectTask.getWidth(), rectTask.getHeight(), 0), new DBEntry<>(questID, quest)); + IGuiPanel taskGui = tsk.getTaskGui(new GuiTransform(GuiAlign.FULL_BOX, + 8, + i == 0 && entries.size() == 1 && tsk.displaysCenteredAlone() ? csTask.getTransform() + .getHeight() / 3 : 0, + csTask.getTransform().getWidth(), + csTask.getTransform().getHeight(), + 0), new DBEntry<>(questID, quest)); if (taskGui != null) { taskGui.initPanel(); // Wrapping into canvas to avoid empty space at end - CanvasEmpty tempCanvas = new CanvasEmpty(new GuiTransform(GuiAlign.TOP_LEFT, 0, yOffset, rectTask.getWidth(), taskGui.getTransform().getHeight() - taskGui.getTransform().getY(), 1)); + CanvasEmpty tempCanvas = new CanvasEmpty(new GuiTransform(GuiAlign.TOP_LEFT, + 0, + yOffset, + csTask.getTransform().getWidth(), + taskGui.getTransform().getHeight() - taskGui.getTransform().getY(), + 1)); csTask.addPanel(tempCanvas); tempCanvas.addPanel(taskGui); @@ -417,15 +471,21 @@ private void refreshDescPanel(boolean hasReward) { csDesc = new CanvasScrolling(new GuiTransform(GuiAlign.HALF_LEFT, new GuiPadding(0, 0, 16, 0), 0)); } cvInner.addPanel(csDesc); - PanelTextBox paDesc = new PanelTextBox(new GuiRectangle(0, 0, csDesc.getTransform().getWidth(), 0), QuestTranslation.translate(quest.getProperty(NativeProps.DESC)), true); + PanelTextBox paDesc = new PanelTextBox(new GuiRectangle(0, 0, csDesc.getTransform().getWidth(), 0), + QuestTranslation.translate(quest.getProperty(NativeProps.DESC)), + true); paDesc.setColor(PresetColor.TEXT_MAIN.getColor());//.setFontSize(10); csDesc.addCulledPanel(paDesc, false); PanelVScrollBar paDescScroll; if (hasReward) { - paDescScroll = new PanelVScrollBar(new GuiTransform(GuiAlign.quickAnchor(GuiAlign.TOP_CENTER, GuiAlign.MID_CENTER), new GuiPadding(-16, 0, 8, 16), 0)); + paDescScroll = new PanelVScrollBar(new GuiTransform(GuiAlign.quickAnchor(GuiAlign.TOP_CENTER, GuiAlign.MID_CENTER), + new GuiPadding(-16, 0, 8, 16), + 0)); } else { - paDescScroll = new PanelVScrollBar(new GuiTransform(GuiAlign.quickAnchor(GuiAlign.TOP_CENTER, GuiAlign.BOTTOM_CENTER), new GuiPadding(-16, 0, 8, 0), 0)); + paDescScroll = new PanelVScrollBar(new GuiTransform(GuiAlign.quickAnchor(GuiAlign.TOP_CENTER, GuiAlign.BOTTOM_CENTER), + new GuiPadding(-16, 0, 8, 0), + 0)); } cvInner.addPanel(paDescScroll); csDesc.setScrollDriverY(paDescScroll); @@ -450,6 +510,7 @@ private void updateButtons() { } public static class ScrollPosition { + public ScrollPosition(int taskScrollY, int rewardScrollY, int descScrollY) { this.taskScrollY = taskScrollY; this.rewardScrollY = rewardScrollY; @@ -458,32 +519,22 @@ public ScrollPosition(int taskScrollY, int rewardScrollY, int descScrollY) { private int taskScrollY; - public int getTaskScrollY() { - return taskScrollY; - } + public int getTaskScrollY() { return taskScrollY; } - public void setTaskScrollY(int taskScrollY) { - this.taskScrollY = taskScrollY; - } + public void setTaskScrollY(int taskScrollY) { this.taskScrollY = taskScrollY; } private int rewardScrollY; - public int getRewardScrollY() { - return rewardScrollY; - } + public int getRewardScrollY() { return rewardScrollY; } - public void setRewardScrollY(int rewardScrollY) { - this.rewardScrollY = rewardScrollY; - } + public void setRewardScrollY(int rewardScrollY) { this.rewardScrollY = rewardScrollY; } private int descScrollY; - public int getDescScrollY() { - return descScrollY; - } + public int getDescScrollY() { return descScrollY; } + + public void setDescScrollY(int descScrollY) { this.descScrollY = descScrollY; } - public void setDescScrollY(int descScrollY) { - this.descScrollY = descScrollY; - } } + } diff --git a/src/main/java/betterquesting/client/gui2/editors/GuiTaskEditor.java b/src/main/java/betterquesting/client/gui2/editors/GuiTaskEditor.java index f5378948b..ceb8fa6b8 100644 --- a/src/main/java/betterquesting/client/gui2/editors/GuiTaskEditor.java +++ b/src/main/java/betterquesting/client/gui2/editors/GuiTaskEditor.java @@ -1,5 +1,14 @@ package betterquesting.client.gui2.editors; +import java.util.ArrayDeque; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import javax.annotation.Nullable; + +import org.lwjgl.util.vector.Vector4f; + import betterquesting.api.client.gui.misc.INeedsRefresh; import betterquesting.api.client.gui.misc.IVolatileScreen; import betterquesting.api.questing.IQuest; @@ -14,7 +23,11 @@ import betterquesting.api2.client.gui.events.PEventBroadcaster; import betterquesting.api2.client.gui.events.PanelEvent; import betterquesting.api2.client.gui.events.types.PEventButton; -import betterquesting.api2.client.gui.misc.*; +import betterquesting.api2.client.gui.misc.GuiAlign; +import betterquesting.api2.client.gui.misc.GuiPadding; +import betterquesting.api2.client.gui.misc.GuiRectangle; +import betterquesting.api2.client.gui.misc.GuiTransform; +import betterquesting.api2.client.gui.misc.IGuiRect; import betterquesting.api2.client.gui.panels.CanvasTextured; import betterquesting.api2.client.gui.panels.bars.PanelVScrollBar; import betterquesting.api2.client.gui.panels.content.PanelLine; @@ -22,31 +35,32 @@ import betterquesting.api2.client.gui.panels.lists.CanvasScrolling; import betterquesting.api2.client.gui.panels.lists.CanvasSearch; import betterquesting.api2.client.gui.themes.presets.PresetColor; +import betterquesting.api2.client.gui.themes.presets.PresetIcon; import betterquesting.api2.client.gui.themes.presets.PresetLine; import betterquesting.api2.client.gui.themes.presets.PresetTexture; import betterquesting.api2.registry.IFactoryData; import betterquesting.api2.storage.DBEntry; +import betterquesting.api2.storage.IDatabaseNBT; import betterquesting.api2.utils.QuestTranslation; import betterquesting.client.gui2.editors.nbt.GuiNbtEditor; import betterquesting.network.handlers.NetQuestEdit; import betterquesting.questing.QuestDatabase; import betterquesting.questing.tasks.TaskRegistry; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import net.minecraft.client.gui.GuiScreen; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.text.TextFormatting; -import org.lwjgl.util.vector.Vector4f; - -import java.util.ArrayDeque; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; public class GuiTaskEditor extends GuiScreenCanvas implements IPEventListener, IVolatileScreen, INeedsRefresh { + private CanvasScrolling qtList; private IQuest quest; private final int qID; + @Nullable // Not null when tasks are reordered. + private Int2IntMap taskIndexBeforeReorder = null; // currentIndex -> oldIndex public GuiTaskEditor(GuiScreen parent, IQuest quest) { super(parent); @@ -79,16 +93,24 @@ public void initPanel() { PEventBroadcaster.INSTANCE.register(this, PEventButton.class); // Background panel - CanvasTextured cvBackground = new CanvasTextured(new GuiTransform(GuiAlign.FULL_BOX, new GuiPadding(0, 0, 0, 0), 0), PresetTexture.PANEL_MAIN.getTexture()); + CanvasTextured cvBackground = new CanvasTextured(new GuiTransform(GuiAlign.FULL_BOX, new GuiPadding(0, 0, 0, 0), 0), + PresetTexture.PANEL_MAIN.getTexture()); this.addPanel(cvBackground); - PanelTextBox panTxt = new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 16, 0, -32), 0), QuestTranslation.translate("betterquesting.title.edit_tasks")).setAlignment(1); + PanelTextBox panTxt = new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(0, 16, 0, -32), 0), + QuestTranslation.translate("betterquesting.title.edit_tasks")).setAlignment(1); panTxt.setColor(PresetColor.TEXT_HEADER.getColor()); cvBackground.addPanel(panTxt); cvBackground.addPanel(new PanelButton(new GuiTransform(GuiAlign.BOTTOM_CENTER, -100, -16, 200, 16, 0), 0, QuestTranslation.translate("gui.back"))); - CanvasSearch, IFactoryData> cvRegSearch = new CanvasSearch, IFactoryData>((new GuiTransform(GuiAlign.HALF_RIGHT, new GuiPadding(8, 48, 24, 32), 0))) { + CanvasSearch, IFactoryData> cvRegSearch = new CanvasSearch, IFactoryData>((new GuiTransform(GuiAlign.HALF_RIGHT, + new GuiPadding(8, + 48, + 24, + 32), + 0))) { + @Override protected Iterator> getIterator() { List> list = TaskRegistry.INSTANCE.getAll(); @@ -98,7 +120,8 @@ protected Iterator> getIterator() { @Override protected void queryMatches(IFactoryData value, String query, ArrayDeque> results) { - if (value.getRegistryName().toString().toLowerCase().contains(query.toLowerCase())) results.add(value); + if (value.getRegistryName().toString().toLowerCase().contains(query.toLowerCase())) + results.add(value); } @Override @@ -106,6 +129,7 @@ protected boolean addResult(IFactoryData entry, int index this.addPanel(new PanelButtonStorage<>(new GuiRectangle(0, index * 16, cachedWidth, 16, 0), 1, entry.getRegistryName().toString(), entry)); return true; } + }; cvBackground.addPanel(cvRegSearch); @@ -113,7 +137,9 @@ protected boolean addResult(IFactoryData entry, int index cvBackground.addPanel(scReg); cvRegSearch.setScrollDriverY(scReg); - PanelTextField tfSearch = new PanelTextField<>(new GuiTransform(new Vector4f(0.5F, 0F, 1F, 0F), new GuiPadding(8, 32, 16, -48), 0), "", FieldFilterString.INSTANCE); + PanelTextField tfSearch = new PanelTextField<>(new GuiTransform(new Vector4f(0.5F, 0F, 1F, 0F), new GuiPadding(8, 32, 16, -48), 0), + "", + FieldFilterString.INSTANCE); tfSearch.setCallback(cvRegSearch::setSearchFilter); tfSearch.setWatermark("Search..."); cvBackground.addPanel(tfSearch); @@ -177,6 +203,16 @@ private void onButtonPress(PEventButton event) { SendChanges(); })); } + } else if (btn.getButtonID() == 4 && btn instanceof PanelButtonStorage) // Up + { + ITask task = ((PanelButtonStorage) btn).getStoredValue(); + int idx = quest.getTasks().getID(task); + reorder(idx, false); + } else if (btn.getButtonID() == 5 && btn instanceof PanelButtonStorage) // Down + { + ITask task = ((PanelButtonStorage) btn).getStoredValue(); + int idx = quest.getTasks().getID(task); + reorder(idx, true); } } @@ -188,8 +224,23 @@ private void refreshTasks() { for (int i = 0; i < dbTsk.size(); i++) { ITask task = dbTsk.get(i).getValue(); - qtList.addPanel(new PanelButtonStorage<>(new GuiRectangle(0, i * 16, w - 16, 16, 0), 3, QuestTranslation.translate(task.getUnlocalisedName()), task)); - qtList.addPanel(new PanelButtonStorage<>(new GuiRectangle(w - 16, i * 16, 16, 16, 0), 2, "" + TextFormatting.RED + TextFormatting.BOLD + "x", task)); + int index = taskIndexBeforeReorder == null ? i : taskIndexBeforeReorder.get(i); + qtList.addPanel(new PanelButtonStorage<>(new GuiRectangle(0, i * 16, w - 48, 16, 0), + 3, + (index + 1) + ". " + QuestTranslation.translate(task.getUnlocalisedName()), + task)); + + PanelButton btnUp = new PanelButtonStorage<>(new GuiRectangle(w - 48, i * 16, 16, 16, 0), 4, "", task).setIcon(PresetIcon.ICON_UP.getTexture()); + btnUp.setActive(i > 0); + qtList.addPanel(btnUp); + PanelButton btnDown = new PanelButtonStorage<>(new GuiRectangle(w - 32, i * 16, 16, 16, 0), 5, "", task).setIcon(PresetIcon.ICON_DOWN.getTexture()); + btnDown.setActive(i < dbTsk.size() - 1); + qtList.addPanel(btnDown); + + qtList.addPanel(new PanelButtonStorage<>(new GuiRectangle(w - 16, i * 16, 16, 16, 0), + 2, + "" + TextFormatting.RED + TextFormatting.BOLD + "x", + task)); } } @@ -204,4 +255,34 @@ private void SendChanges() { payload.setInteger("action", 0); NetQuestEdit.sendEdit(payload); } + + private void reorder(int index, boolean down) { + + int size = quest.getTasks().size(); + + int indexFrom = (index + (down ? 1 : -1) + size) % size; + + IDatabaseNBT tasks = quest.getTasks(); + + if (taskIndexBeforeReorder == null) { + taskIndexBeforeReorder = new Int2IntOpenHashMap(); + for (DBEntry entry : tasks.getEntries()) { + taskIndexBeforeReorder.put(entry.getID(), entry.getID()); + } + } + + ITask task = tasks.getValue(index); + ITask task2 = tasks.getValue(indexFrom); + tasks.removeID(index); + tasks.removeID(indexFrom); + tasks.add(index, task2); + tasks.add(indexFrom, task); + + int tmp = taskIndexBeforeReorder.get(index); + taskIndexBeforeReorder.put(index, taskIndexBeforeReorder.get(indexFrom)); + taskIndexBeforeReorder.put(indexFrom, tmp); + + SendChanges(); + } + } diff --git a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskAdvancement.java b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskAdvancement.java index 03ac684a1..cfeb4838d 100644 --- a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskAdvancement.java +++ b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskAdvancement.java @@ -6,6 +6,8 @@ import betterquesting.api2.client.gui.misc.*; import betterquesting.api2.client.gui.panels.CanvasEmpty; import betterquesting.api2.client.gui.panels.content.PanelGeneric; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay.State; import betterquesting.api2.client.gui.panels.content.PanelTextBox; import betterquesting.api2.client.gui.resources.textures.ItemTexture; import betterquesting.api2.client.gui.themes.presets.PresetColor; @@ -45,7 +47,12 @@ public void initPanel() { } this.addPanel(new PanelGeneric(new GuiRectangle(0, 0, 24, 24, 0), PresetTexture.ITEM_FRAME.getTexture())); - this.addPanel(new PanelGeneric(new GuiRectangle(0, 0, 24, 24, -1), new ItemTexture(icon))); + PanelTaskOverlay overlay = new PanelTaskOverlay(new PanelGeneric(new GuiRectangle(0, 0, 24, 24, -1), new ItemTexture(icon))); + if (isComplete) + overlay.setState(State.COMPLETE); + else + overlay.setState(State.INCOMPLETE); + this.addPanel(overlay); this.addPanel(new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, new GuiPadding(28, 2, 0, -12), 0), title).setColor(PresetColor.TEXT_MAIN.getColor())); String s = isComplete ? (TextFormatting.GREEN.toString() + QuestTranslation.translate("betterquesting.tooltip.complete")) : (TextFormatting.RED.toString() + QuestTranslation.translate("betterquesting.tooltip.incomplete")); diff --git a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskBlockBreak.java b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskBlockBreak.java index 3e808fe64..b276710f5 100644 --- a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskBlockBreak.java +++ b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskBlockBreak.java @@ -1,11 +1,15 @@ package betterquesting.client.gui2.tasks; +import java.util.UUID; + import betterquesting.api.api.QuestingAPI; import betterquesting.api.utils.BigItemStack; import betterquesting.api2.client.gui.misc.GuiRectangle; import betterquesting.api2.client.gui.misc.IGuiRect; import betterquesting.api2.client.gui.panels.CanvasMinimum; import betterquesting.api2.client.gui.panels.content.PanelItemSlot; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay.State; import betterquesting.api2.client.gui.panels.content.PanelTextBox; import betterquesting.api2.client.gui.themes.presets.PresetColor; import betterquesting.api2.utils.QuestTranslation; @@ -13,8 +17,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.util.text.TextFormatting; -import java.util.UUID; - public class PanelTaskBlockBreak extends CanvasMinimum { private final IGuiRect initialRect; @@ -42,19 +44,30 @@ public void initPanel() { if (stack == null) { continue; } + boolean completed = isComplete || progress[i] >= stack.stackSize; PanelItemSlot slot = new PanelItemSlot(new GuiRectangle(0, i * 36, 36, 36, 0), -1, stack, true, true); - this.addPanel(slot); + PanelTaskOverlay overlay = new PanelTaskOverlay(slot); + if (completed) + overlay.setState(State.COMPLETE); + else if (progress[i] > 0) + overlay.setState(State.IN_PROGRESS); + else + overlay.setState(State.INCOMPLETE); + if (!completed) + overlay.setText(progress[i] + "/" + stack.stackSize); + this.addPanel(overlay); StringBuilder sb = new StringBuilder(); sb.append(stack.getBaseStack().getDisplayName()); - if (stack.hasOreDict()) sb.append(" (").append(stack.getOreDict()).append(")"); + if (stack.hasOreDict()) + sb.append(" (").append(stack.getOreDict()).append(")"); sb.append("\n").append(progress[i]).append("/").append(stack.stackSize).append("\n"); - if (progress[i] >= stack.stackSize || isComplete) { + if (completed) { sb.append(TextFormatting.GREEN).append(QuestTranslation.translate("betterquesting.tooltip.complete")); } else { sb.append(TextFormatting.RED).append(QuestTranslation.translate("betterquesting.tooltip.incomplete")); diff --git a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskCrafting.java b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskCrafting.java index fe6b1f1d9..2746b814f 100644 --- a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskCrafting.java +++ b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskCrafting.java @@ -1,5 +1,7 @@ package betterquesting.client.gui2.tasks; +import java.util.UUID; + import betterquesting.api.api.QuestingAPI; import betterquesting.api.utils.BigItemStack; import betterquesting.api2.client.gui.misc.GuiRectangle; @@ -7,6 +9,8 @@ import betterquesting.api2.client.gui.panels.CanvasMinimum; import betterquesting.api2.client.gui.panels.content.PanelGeneric; import betterquesting.api2.client.gui.panels.content.PanelItemSlot; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay.State; import betterquesting.api2.client.gui.panels.content.PanelTextBox; import betterquesting.api2.client.gui.resources.colors.GuiColorStatic; import betterquesting.api2.client.gui.resources.textures.GuiTextureColored; @@ -20,8 +24,6 @@ import net.minecraft.init.Blocks; import net.minecraft.util.text.TextFormatting; -import java.util.UUID; - public class PanelTaskCrafting extends CanvasMinimum { private final IGuiRect initialRect; @@ -57,19 +59,30 @@ public void initPanel() { for (int i = 0; i < task.requiredItems.size(); i++) { BigItemStack stack = task.requiredItems.get(i); + boolean completed = isComplete || progress[i] >= stack.stackSize; PanelItemSlot slot = new PanelItemSlot(new GuiRectangle(0, i * 28 + 24, 28, 28, 0), -1, stack, false, true); - this.addPanel(slot); + PanelTaskOverlay overlay = new PanelTaskOverlay(slot); + if (completed) + overlay.setState(State.COMPLETE); + else if (progress[i] > 0) + overlay.setState(State.IN_PROGRESS); + else + overlay.setState(State.INCOMPLETE); + if (!completed) + overlay.setText(progress[i] + "/" + stack.stackSize); + this.addPanel(overlay); StringBuilder sb = new StringBuilder(); sb.append(stack.getBaseStack().getDisplayName()); - if (stack.hasOreDict()) sb.append(" (").append(stack.getOreDict()).append(")"); + if (stack.hasOreDict()) + sb.append(" (").append(stack.getOreDict()).append(")"); sb.append("\n").append(progress[i]).append("/").append(stack.stackSize).append("\n"); - if (isComplete || progress[i] >= stack.stackSize) { + if (completed) { sb.append(TextFormatting.GREEN).append(QuestTranslation.translate("betterquesting.tooltip.complete")); } else { sb.append(TextFormatting.RED).append(QuestTranslation.translate("betterquesting.tooltip.incomplete")); diff --git a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskFluid.java b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskFluid.java index ff943a8f7..f66f67a49 100644 --- a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskFluid.java +++ b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskFluid.java @@ -1,14 +1,19 @@ package betterquesting.client.gui2.tasks; +import java.util.List; +import java.util.UUID; + import betterquesting.api.api.QuestingAPI; -import betterquesting.api2.client.gui.misc.GuiAlign; +import betterquesting.api2.client.gui.controls.PanelButton; import betterquesting.api2.client.gui.misc.GuiRectangle; -import betterquesting.api2.client.gui.misc.GuiTransform; import betterquesting.api2.client.gui.misc.IGuiRect; import betterquesting.api2.client.gui.panels.CanvasMinimum; import betterquesting.api2.client.gui.panels.content.PanelFluidSlot; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay.State; import betterquesting.api2.client.gui.panels.content.PanelTextBox; import betterquesting.api2.client.gui.themes.presets.PresetColor; +import betterquesting.api2.client.gui.themes.presets.PresetIcon; import betterquesting.api2.utils.QuestTranslation; import betterquesting.core.BetterQuesting; import betterquesting.questing.tasks.TaskFluid; @@ -20,10 +25,11 @@ import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.common.Optional.Method; -import java.util.UUID; - public class PanelTaskFluid extends CanvasMinimum { + public static final int MAX_SLOT_SIZE = PanelTaskRetrieval.MAX_SLOT_SIZE; + public static final int MIN_SLOT_SIZE = PanelTaskRetrieval.MIN_SLOT_SIZE; + public static final int SLOT_PADDING = PanelTaskRetrieval.SLOT_PADDING; private final IGuiRect initialRect; private final TaskFluid task; @@ -42,37 +48,129 @@ public void initPanel() { int[] progress = task.getUsersProgress(uuid); boolean isComplete = task.isComplete(uuid); - String sCon = (task.consume ? TextFormatting.RED : TextFormatting.GREEN) + QuestTranslation.translate(task.consume ? "gui.yes" : "gui.no"); - this.addPanel(new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, 0, 0, listW, 12, 0), QuestTranslation.translate("bq_standard.btn.consume", sCon)).setColor(PresetColor.TEXT_MAIN.getColor())); - - for (int i = 0; i < task.requiredFluids.size(); i++) { - FluidStack stack = task.requiredFluids.get(i); + final int firstIconOffset = 10; - PanelFluidSlot slot = new PanelFluidSlot(new GuiRectangle(0, i * 28 + 12, 28, 28, 0), -1, stack); - if (BetterQuesting.hasJEI) slot.setCallback(this::lookupRecipe); - this.addPanel(slot); + if (task.isFold() && task.requiredFluids.size() > 1) { + int x = firstIconOffset; + int y = 0; + int slotSize = MAX_SLOT_SIZE; + int canvasWidth = initialRect.getWidth(); + canvasWidth -= 8; //scrollbar width + canvasWidth -= (int) PanelTaskOverlay.FRAME_WIDTH / 2; + if (firstIconOffset + task.requiredFluids.size() * (slotSize + SLOT_PADDING) >= canvasWidth) { + // Fit it into the (parent) canvas + slotSize = (int) Math.max(MIN_SLOT_SIZE, (float) (canvasWidth - firstIconOffset) / task.requiredFluids.size() - SLOT_PADDING); + } - StringBuilder sb = new StringBuilder(); + PanelButton foldArrow = new PanelButton(new GuiRectangle(0, 0, 8, 8, 0), -1, ""); + foldArrow.setIcon(PresetIcon.ICON_RIGHT.getTexture()); + foldArrow.setClickAction(b -> setFold(false)); + this.addPanel(foldArrow); - sb.append(stack.getLocalizedName()).append("\n"); - sb.append(progress[i]).append("/").append(stack.amount).append("mB\n"); + for (int i = 0; i < task.requiredFluids.size(); i++) { + if (x + slotSize > canvasWidth) { + x = firstIconOffset; + y += slotSize + SLOT_PADDING; + } + FluidStack stack = task.requiredFluids.get(i); + boolean completed = isComplete || progress[i] >= stack.amount; - if (progress[i] >= stack.amount || isComplete) { - sb.append(TextFormatting.GREEN).append(QuestTranslation.translate("betterquesting.tooltip.complete")); - } else { - sb.append(TextFormatting.RED).append(QuestTranslation.translate("betterquesting.tooltip.incomplete")); + PanelFluidSlot slot = createPanelFluidSlot(new GuiRectangle(x, y, slotSize, slotSize, 0), stack); + if (BetterQuesting.hasJEI) + slot.setCallback(this::lookupRecipe); + PanelTaskOverlay overlay = new PanelTaskOverlay(slot); + if (completed) + overlay.setState(State.COMPLETE); + else if (progress[i] > 0) + overlay.setState(State.IN_PROGRESS); + else + overlay.setState(State.INCOMPLETE); + if (!completed) + overlay.setText(progress[i] + "/" + stack.amount); + if (task.consume) + overlay.setConsume(true); + this.addPanel(overlay); + x += slotSize + SLOT_PADDING; } + } else { + if (task.requiredFluids.size() > 1) { + PanelButton foldArrow = new PanelButton(new GuiRectangle(0, 0, 8, 8, 0), -1, ""); + foldArrow.setIcon(PresetIcon.ICON_DOWN.getTexture()); + foldArrow.setClickAction(b -> setFold(true)); + this.addPanel(foldArrow); + } + + for (int i = 0; i < task.requiredFluids.size(); i++) { + FluidStack stack = task.requiredFluids.get(i); + boolean completed = isComplete || progress[i] >= stack.amount; + + PanelFluidSlot slot = createPanelFluidSlot(new GuiRectangle(firstIconOffset, + i * (MAX_SLOT_SIZE + SLOT_PADDING), + MAX_SLOT_SIZE, + MAX_SLOT_SIZE, + 0), stack); + if (BetterQuesting.hasJEI) + slot.setCallback(this::lookupRecipe); + PanelTaskOverlay overlay = new PanelTaskOverlay(slot); + if (completed) + overlay.setState(State.COMPLETE); + else if (progress[i] > 0) + overlay.setState(State.IN_PROGRESS); + else + overlay.setState(State.INCOMPLETE); + if (!completed) + overlay.setText(progress[i] + "/" + stack.amount); + if (task.consume) + overlay.setConsume(true); + this.addPanel(overlay); + + StringBuilder sb = new StringBuilder(); + + sb.append(stack.getLocalizedName()).append("\n"); + sb.append(progress[i]).append("/").append(stack.amount).append("mB\n"); - PanelTextBox text = new PanelTextBox(new GuiRectangle(36, i * 28 + 12, listW - 36, 28, 0), sb.toString()); - text.setColor(PresetColor.TEXT_MAIN.getColor()); - this.addPanel(text); + if (progress[i] >= stack.amount || isComplete) { + sb.append(TextFormatting.GREEN).append(QuestTranslation.translate("betterquesting.tooltip.complete")); + } else { + sb.append(TextFormatting.RED).append(QuestTranslation.translate("betterquesting.tooltip.incomplete")); + } + + PanelTextBox text = new PanelTextBox(new GuiRectangle(firstIconOffset + (MAX_SLOT_SIZE + SLOT_PADDING), + i * (MAX_SLOT_SIZE + SLOT_PADDING), + listW - MAX_SLOT_SIZE, + MAX_SLOT_SIZE, + 0), sb.toString()); + text.setColor(PresetColor.TEXT_MAIN.getColor()); + this.addPanel(text); + } } + recalculateSizes(); } @Method(modid = "jei") private void lookupRecipe(FluidStack fluid) { - if (fluid == null || Internal.getRuntime() == null) return; + if (fluid == null || Internal.getRuntime() == null) + return; Internal.getRuntime().getRecipesGui().show(new Focus<>(Mode.OUTPUT, fluid)); } + + private PanelFluidSlot createPanelFluidSlot(GuiRectangle rect, FluidStack stack) { + return new PanelFluidSlot(rect, -1, stack, false) { + + @Override + public PanelButton setTooltip(List tooltip) { + if (tooltip != null && task.consume) { + tooltip.add(TextFormatting.RED + "[" + QuestTranslation.translate("bq_standard.tooltip.consume") + "]"); + } + return super.setTooltip(tooltip); + } + + }; + } + + private void setFold(boolean fold) { + task.setFold(fold); + } + } diff --git a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskRetrieval.java b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskRetrieval.java index 08acdaf97..eb746a49b 100644 --- a/src/main/java/betterquesting/client/gui2/tasks/PanelTaskRetrieval.java +++ b/src/main/java/betterquesting/client/gui2/tasks/PanelTaskRetrieval.java @@ -1,24 +1,30 @@ package betterquesting.client.gui2.tasks; +import java.util.List; +import java.util.UUID; + import betterquesting.api.api.QuestingAPI; import betterquesting.api.utils.BigItemStack; -import betterquesting.api2.client.gui.misc.GuiAlign; +import betterquesting.api2.client.gui.controls.PanelButton; import betterquesting.api2.client.gui.misc.GuiRectangle; -import betterquesting.api2.client.gui.misc.GuiTransform; import betterquesting.api2.client.gui.misc.IGuiRect; import betterquesting.api2.client.gui.panels.CanvasMinimum; import betterquesting.api2.client.gui.panels.content.PanelItemSlot; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay; +import betterquesting.api2.client.gui.panels.content.PanelTaskOverlay.State; import betterquesting.api2.client.gui.panels.content.PanelTextBox; import betterquesting.api2.client.gui.themes.presets.PresetColor; +import betterquesting.api2.client.gui.themes.presets.PresetIcon; import betterquesting.api2.utils.QuestTranslation; import betterquesting.questing.tasks.TaskRetrieval; import net.minecraft.client.Minecraft; import net.minecraft.util.text.TextFormatting; -import java.util.UUID; - public class PanelTaskRetrieval extends CanvasMinimum { + public static final int MAX_SLOT_SIZE = 28; + public static final int MIN_SLOT_SIZE = 20; + public static final int SLOT_PADDING = 4; private final IGuiRect initialRect; private final TaskRetrieval task; @@ -37,34 +43,120 @@ public void initPanel() { int[] progress = task.getUsersProgress(uuid); boolean isComplete = task.isComplete(uuid); - String sCon = (task.consume ? TextFormatting.RED : TextFormatting.GREEN) + QuestTranslation.translate(task.consume ? "gui.yes" : "gui.no"); - - this.addPanel(new PanelTextBox(new GuiTransform(GuiAlign.TOP_EDGE, 0, 0, listW, 16, 0), QuestTranslation.translate("bq_standard.btn.consume", sCon)).setColor(PresetColor.TEXT_MAIN.getColor())); + final int firstIconOffset = 10; - for (int i = 0; i < task.requiredItems.size(); i++) { - BigItemStack stack = task.requiredItems.get(i); + if (task.isFold() && task.requiredItems.size() > 1) { - PanelItemSlot slot = new PanelItemSlot(new GuiRectangle(0, i * 32 + 16, 28, 28, 0), -1, stack, false, true); - this.addPanel(slot); - - StringBuilder sb = new StringBuilder(); + int x = firstIconOffset; + int y = 0; + int slotSize = MAX_SLOT_SIZE; + int canvasWidth = initialRect.getWidth(); + canvasWidth -= 8; //scrollbar width + canvasWidth -= (int) PanelTaskOverlay.FRAME_WIDTH / 2; + if (firstIconOffset + task.requiredItems.size() * (slotSize + SLOT_PADDING) >= canvasWidth) { + // Fit it into the (parent) canvas + slotSize = (int) Math.max(MIN_SLOT_SIZE, (float) (canvasWidth - firstIconOffset) / task.requiredItems.size() - SLOT_PADDING); + } - sb.append(stack.getBaseStack().getDisplayName()); + PanelButton foldArrow = new PanelButton(new GuiRectangle(0, 0, 8, 8, 0), -1, ""); + foldArrow.setIcon(PresetIcon.ICON_RIGHT.getTexture()); + foldArrow.setClickAction(b -> setFold(false)); + this.addPanel(foldArrow); + + for (int i = 0; i < task.requiredItems.size(); i++) { + if (x + slotSize > canvasWidth) { + x = firstIconOffset; + y += slotSize + SLOT_PADDING; + } + BigItemStack stack = task.requiredItems.get(i); + boolean completed = isComplete || progress[i] >= stack.stackSize; + + PanelItemSlot slot = createPanelItemSlot(new GuiRectangle(x, y, slotSize, slotSize, 0), stack); + PanelTaskOverlay overlay = new PanelTaskOverlay(slot); + if (completed) + overlay.setState(State.COMPLETE); + else if (progress[i] > 0) + overlay.setState(State.IN_PROGRESS); + else + overlay.setState(State.INCOMPLETE); + if (!completed) + overlay.setText(progress[i] + "/" + stack.stackSize); + if (task.consume) + overlay.setConsume(true); + this.addPanel(overlay); + x += slotSize + SLOT_PADDING; + } + } else { + if (task.requiredItems.size() > 1) { + PanelButton foldArrow = new PanelButton(new GuiRectangle(0, 0, 8, 8, 0), -1, ""); + foldArrow.setIcon(PresetIcon.ICON_DOWN.getTexture()); + foldArrow.setClickAction(b -> setFold(true)); + this.addPanel(foldArrow); + } - if (stack.hasOreDict()) sb.append(" (").append(stack.getOreDict()).append(")"); + for (int i = 0; i < task.requiredItems.size(); i++) { + BigItemStack stack = task.requiredItems.get(i); + boolean completed = isComplete || progress[i] >= stack.stackSize; + + PanelItemSlot slot = createPanelItemSlot(new GuiRectangle(firstIconOffset, i * (MAX_SLOT_SIZE + SLOT_PADDING), MAX_SLOT_SIZE, MAX_SLOT_SIZE, 0), + stack); + PanelTaskOverlay overlay = new PanelTaskOverlay(slot); + if (completed) + overlay.setState(State.COMPLETE); + else if (progress[i] > 0) + overlay.setState(State.IN_PROGRESS); + else + overlay.setState(State.INCOMPLETE); + if (!completed) + overlay.setText(progress[i] + "/" + stack.stackSize); + if (task.consume) + overlay.setConsume(true); + this.addPanel(overlay); + + StringBuilder sb = new StringBuilder(); + + sb.append(stack.getBaseStack().getDisplayName()); + + if (stack.hasOreDict()) + sb.append(" (").append(stack.getOreDict()).append(")"); + + sb.append("\n").append(progress[i]).append("/").append(stack.stackSize).append("\n"); + + if (completed) { + sb.append(TextFormatting.GREEN).append(QuestTranslation.translate("betterquesting.tooltip.complete")); + } else { + sb.append(TextFormatting.RED).append(QuestTranslation.translate("betterquesting.tooltip.incomplete")); + } + + PanelTextBox text = new PanelTextBox(new GuiRectangle(firstIconOffset + (MAX_SLOT_SIZE + SLOT_PADDING), + i * (MAX_SLOT_SIZE + SLOT_PADDING), + listW - MAX_SLOT_SIZE, + MAX_SLOT_SIZE, + 0), sb.toString()); + text.setColor(PresetColor.TEXT_MAIN.getColor()); + this.addPanel(text); + } + } + recalculateSizes(); + } - sb.append("\n").append(progress[i]).append("/").append(stack.stackSize).append("\n"); + private PanelItemSlot createPanelItemSlot(GuiRectangle rect, BigItemStack stack) { + return new PanelItemSlot(rect, -1, stack, false, true) { - if (isComplete || progress[i] >= stack.stackSize) { - sb.append(TextFormatting.GREEN).append(QuestTranslation.translate("betterquesting.tooltip.complete")); - } else { - sb.append(TextFormatting.RED).append(QuestTranslation.translate("betterquesting.tooltip.incomplete")); + @Override + public List getTooltip(int mx, int my) { + List tooltip = super.getTooltip(mx, my); + if (tooltip != null && task.consume) { + tooltip.add(TextFormatting.RED + "[" + QuestTranslation.translate("bq_standard.tooltip.consume") + "]"); + } + return tooltip; } - PanelTextBox text = new PanelTextBox(new GuiRectangle(32, i * 32 + 16, listW - 28, 28, 0), sb.toString()); - text.setColor(PresetColor.TEXT_MAIN.getColor()); - this.addPanel(text); - } - recalculateSizes(); + }; + } + + private void setFold(boolean fold) { + task.setFold(fold); } + } diff --git a/src/main/java/betterquesting/handlers/ConfigHandler.java b/src/main/java/betterquesting/handlers/ConfigHandler.java index cb2af5897..bb3323293 100644 --- a/src/main/java/betterquesting/handlers/ConfigHandler.java +++ b/src/main/java/betterquesting/handlers/ConfigHandler.java @@ -41,6 +41,7 @@ public static void initConfigs() { BQ_Settings.defaultVisibility = config.getString("Default Quest Visibility", Configuration.CATEGORY_GENERAL, "NORMAL", "The default visibility value used when creating quests"); BQ_Settings.spawnWithQuestBook = config.getBoolean("Spawn with Quest Book", Configuration.CATEGORY_GENERAL, true, "If true, then the player will spawn with a Quest Book when they first join the world"); + BQ_Settings.taskFoldedInitially = config.getBoolean("Task Folded Initially", Configuration.CATEGORY_GENERAL, BQ_Settings.taskFoldedInitially, "If true, then quest tasks will be initially folded."); config.save(); } } diff --git a/src/main/java/betterquesting/questing/tasks/TaskFluid.java b/src/main/java/betterquesting/questing/tasks/TaskFluid.java index a13a9b109..f26289ac8 100644 --- a/src/main/java/betterquesting/questing/tasks/TaskFluid.java +++ b/src/main/java/betterquesting/questing/tasks/TaskFluid.java @@ -1,8 +1,10 @@ package betterquesting.questing.tasks; +import betterquesting.api.client.gui.misc.INeedsRefresh; import betterquesting.api.questing.IQuest; import betterquesting.api.questing.tasks.IFluidTask; import betterquesting.api.questing.tasks.IItemTask; +import betterquesting.api.storage.BQ_Settings; import betterquesting.api.utils.JsonHelper; import betterquesting.api2.client.gui.misc.IGuiRect; import betterquesting.api2.client.gui.panels.IGuiPanel; @@ -11,6 +13,17 @@ import betterquesting.client.gui2.tasks.PanelTaskFluid; import betterquesting.core.BetterQuesting; import betterquesting.questing.tasks.factory.FactoryTaskFluid; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.UUID; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.InventoryPlayer; @@ -32,11 +45,8 @@ import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.logging.log4j.Level; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.*; - public class TaskFluid implements ITaskInventory, IFluidTask, IItemTask { + private final Set completeUsers = new TreeSet<>(); public final NonNullList requiredFluids = NonNullList.create(); public final TreeMap userProgress = new TreeMap<>(); @@ -45,16 +55,23 @@ public class TaskFluid implements ITaskInventory, IFluidTask, IItemTask { public boolean consume = true; public boolean groupDetect = false; public boolean autoConsume = false; + private boolean fold = BQ_Settings.taskFoldedInitially; // This remains through the game. - @Override - public ResourceLocation getFactoryID() { - return FactoryTaskFluid.INSTANCE.getRegistryName(); + public boolean isFold() { return fold; } + + public void setFold(boolean fold) { + this.fold = fold; + GuiScreen screen = Minecraft.getMinecraft().currentScreen; + if (screen instanceof INeedsRefresh needsRefresh) { + needsRefresh.refreshGui(); + } } @Override - public String getUnlocalisedName() { - return "bq_standard.task.fluid"; - } + public ResourceLocation getFactoryID() { return FactoryTaskFluid.INSTANCE.getRegistryName(); } + + @Override + public String getUnlocalisedName() { return "bq_standard.task.fluid"; } @Override public boolean isComplete(UUID uuid) { @@ -75,7 +92,8 @@ public void onInventoryChange(@Nonnull DBEntry quest, @Nonnull Participa @Override public void detect(ParticipantInfo pInfo, DBEntry quest) { - if (isComplete(pInfo.UUID)) return; + if (isComplete(pInfo.UUID)) + return; // Removing the consume check here would make the task cheaper on groups and for that reason sharing is restricted to detect only final List> progress = getBulkProgress(consume ? Collections.singletonList(pInfo.UUID) : pInfo.ALL_UUIDS); @@ -112,33 +130,41 @@ public void detect(ParticipantInfo pInfo, DBEntry quest) { for (InventoryPlayer invo : invoList) { for (int i = 0; i < invo.getSizeInventory(); i++) { ItemStack stack = invo.getStackInSlot(i); - if (stack.isEmpty()) continue; + if (stack.isEmpty()) + continue; IFluidHandlerItem handler = FluidUtil.getFluidHandler(stack); - if (handler == null) continue; + if (handler == null) + continue; boolean hasDrained = false; for (int j = 0; j < requiredFluids.size(); j++) { final FluidStack rStack = requiredFluids.get(j); FluidStack drainOG = rStack.copy(); - if (ignoreNbt) drainOG.tag = null; + if (ignoreNbt) + drainOG.tag = null; // Pre-check FluidStack sample = handler.drain(drainOG, false); - if (sample == null || sample.amount <= 0) continue; + if (sample == null || sample.amount <= 0) + continue; // Theoretically this could work in consume mode for parties but the priority order and manual submission code would need changing for (Tuple value : progress) { - if (value.getSecond()[j] >= rStack.amount) continue; + if (value.getSecond()[j] >= rStack.amount) + continue; int remaining = rStack.amount - value.getSecond()[j]; FluidStack drain = rStack.copy(); drain.amount = remaining / stack.getCount(); // Must be a multiple of the stack size - if (ignoreNbt) drain.tag = null; - if (drain.amount <= 0) continue; + if (ignoreNbt) + drain.tag = null; + if (drain.amount <= 0) + continue; FluidStack fluid = handler.drain(drain, consume); // TODO: Look into reducing this to a single call if possible - if (fluid == null || fluid.amount <= 0) continue; + if (fluid == null || fluid.amount <= 0) + continue; value.getSecond()[j] += fluid.amount * stack.getCount(); hasDrained = true; @@ -146,11 +172,13 @@ public void detect(ParticipantInfo pInfo, DBEntry quest) { } } - if (hasDrained && consume) invo.setInventorySlotContents(i, handler.getContainer()); + if (hasDrained && consume) + invo.setInventorySlotContents(i, handler.getContainer()); } } - if (updated) setBulkProgress(progress); + if (updated) + setBulkProgress(progress); checkAndComplete(pInfo, quest, updated); } @@ -161,7 +189,8 @@ private void checkAndComplete(ParticipantInfo pInfo, DBEntry quest, bool topLoop: for (Tuple value : progress) { for (int j = 0; j < requiredFluids.size(); j++) { - if (value.getSecond()[j] >= requiredFluids.get(j).amount) continue; + if (value.getSecond()[j] >= requiredFluids.get(j).amount) + continue; continue topLoop; } @@ -259,14 +288,17 @@ public NBTTagCompound writeProgressToNBT(NBTTagCompound nbt, @Nullable List { - if (completeUsers.contains(uuid)) jArray.appendTag(new NBTTagString(uuid.toString())); + if (completeUsers.contains(uuid)) + jArray.appendTag(new NBTTagString(uuid.toString())); int[] data = userProgress.get(uuid); if (data != null) { NBTTagCompound pJson = new NBTTagCompound(); pJson.setString("uuid", uuid.toString()); NBTTagList pArray = new NBTTagList(); // TODO: Why the heck isn't this just an int array?! - for (int i : data) pArray.appendTag(new NBTTagInt(i)); + for (int i : data) { + pArray.appendTag(new NBTTagInt(i)); + } pJson.setTag("data", pArray); progArray.appendTag(pJson); } @@ -278,7 +310,9 @@ public NBTTagCompound writeProgressToNBT(NBTTagCompound nbt, @Nullable List quest, FluidStack flui for (int j = 0; j < requiredFluids.size(); j++) { FluidStack rStack = requiredFluids.get(j).copy(); - if (ignoreNbt) rStack.tag = null; - if (progress[j] < rStack.amount && rStack.equals(fluid)) return true; + if (ignoreNbt) + rStack.tag = null; + if (progress[j] < rStack.amount && rStack.equals(fluid)) + return true; } return false; @@ -338,13 +374,16 @@ public boolean canAcceptItem(UUID owner, DBEntry quest, ItemStack item) IFluidHandlerItem handler = FluidUtil.getFluidHandler(item); - if (handler == null) return false; + if (handler == null) + return false; for (IFluidTankProperties tank : handler.getTankProperties()) { - if (!tank.canDrain()) continue; + if (!tank.canDrain()) + continue; for (FluidStack rStack : requiredFluids) { - if (rStack.equals(tank.getContents())) return true; + if (rStack.equals(tank.getContents())) + return true; } } @@ -367,7 +406,8 @@ private FluidStack submitFluidInternal(UUID owner, DBEntry quest, FluidS for (int j = 0; j < requiredFluids.size(); j++) { FluidStack rStack = requiredFluids.get(j); - if (progress[j] >= rStack.amount) continue; + if (progress[j] >= rStack.amount) + continue; int remaining = rStack.amount - progress[j]; @@ -396,13 +436,15 @@ private FluidStack submitFluidInternal(UUID owner, DBEntry quest, FluidS // It's implied to be a consume task so no need to lookup the party boolean hasAll = true; for (int j = 0; j < requiredFluids.size(); j++) { - if (progress[j] >= requiredFluids.get(j).amount) continue; + if (progress[j] >= requiredFluids.get(j).amount) + continue; hasAll = false; break; } - if (hasAll) setComplete(owner); + if (hasAll) + setComplete(owner); } } @@ -411,24 +453,28 @@ private FluidStack submitFluidInternal(UUID owner, DBEntry quest, FluidS @Override public ItemStack submitItem(UUID owner, DBEntry quest, ItemStack input) { - if (owner == null || input.isEmpty() || !consume || isComplete(owner)) return input; + if (owner == null || input.isEmpty() || !consume || isComplete(owner)) + return input; ItemStack item = input.splitStack(1); // Prevents issues with stack filling/draining IFluidHandlerItem handler = FluidUtil.getFluidHandler(item); - if (handler == null) return item; + if (handler == null) + return item; boolean hasDrained = false; for (IFluidTankProperties tank : handler.getTankProperties()) { - if (!tank.canDrain() || tank.getContents() == null || !tank.canDrainFluidType(tank.getContents())) continue; + if (!tank.canDrain() || tank.getContents() == null || !tank.canDrainFluidType(tank.getContents())) + continue; // Figure out how much of this fluid is left to submit to the task FluidStack remaining = submitFluidInternal(owner, quest, tank.getContents().copy(), false); FluidStack drain = tank.getContents().copy(); drain.amount -= remaining == null ? 0 : remaining.amount; - if (drain.amount <= 0) continue; + if (drain.amount <= 0) + continue; // Attempt drain of remaining amount and submit to task progress submitFluidInternal(owner, quest, handler.drain(drain, true), true); @@ -448,7 +494,8 @@ public int[] getUsersProgress(UUID uuid) { } private List> getBulkProgress(@Nonnull List uuids) { - if (uuids.size() <= 0) return Collections.emptyList(); + if (uuids.size() <= 0) + return Collections.emptyList(); List> list = new ArrayList<>(); uuids.forEach((key) -> list.add(new Tuple<>(key, getUsersProgress(key)))); return list; @@ -467,4 +514,5 @@ public List getTextForSearch() { } return texts; } + } diff --git a/src/main/java/betterquesting/questing/tasks/TaskRetrieval.java b/src/main/java/betterquesting/questing/tasks/TaskRetrieval.java index 96de78345..439df7bd0 100644 --- a/src/main/java/betterquesting/questing/tasks/TaskRetrieval.java +++ b/src/main/java/betterquesting/questing/tasks/TaskRetrieval.java @@ -1,8 +1,10 @@ package betterquesting.questing.tasks; +import betterquesting.api.client.gui.misc.INeedsRefresh; import betterquesting.api.enums.EnumLogic; import betterquesting.api.questing.IQuest; import betterquesting.api.questing.tasks.IItemTask; +import betterquesting.api.storage.BQ_Settings; import betterquesting.api.utils.BigItemStack; import betterquesting.api.utils.ItemComparison; import betterquesting.api.utils.JsonHelper; @@ -13,6 +15,18 @@ import betterquesting.client.gui2.tasks.PanelTaskRetrieval; import betterquesting.core.BetterQuesting; import betterquesting.questing.tasks.factory.FactoryTaskRetrieval; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.UUID; +import java.util.stream.IntStream; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.InventoryPlayer; @@ -30,12 +44,8 @@ import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.logging.log4j.Level; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.*; -import java.util.stream.IntStream; - public class TaskRetrieval implements ITaskInventory, IItemTask { + private final Set completeUsers = new TreeSet<>(); public final NonNullList requiredItems = NonNullList.create(); private final TreeMap userProgress = new TreeMap<>(); @@ -45,16 +55,23 @@ public class TaskRetrieval implements ITaskInventory, IItemTask { public boolean groupDetect = false; public boolean autoConsume = false; public EnumLogic entryLogic = EnumLogic.AND; + private boolean fold = BQ_Settings.taskFoldedInitially; // This remains through the game. - @Override - public String getUnlocalisedName() { - return BetterQuesting.MODID_STD + ".task.retrieval"; + public boolean isFold() { return fold; } + + public void setFold(boolean fold) { + this.fold = fold; + GuiScreen screen = Minecraft.getMinecraft().currentScreen; + if (screen instanceof INeedsRefresh needsRefresh) { + needsRefresh.refreshGui(); + } } @Override - public ResourceLocation getFactoryID() { - return FactoryTaskRetrieval.INSTANCE.getRegistryName(); - } + public String getUnlocalisedName() { return BetterQuesting.MODID_STD + ".task.retrieval"; } + + @Override + public ResourceLocation getFactoryID() { return FactoryTaskRetrieval.INSTANCE.getRegistryName(); } @Override public boolean isComplete(UUID uuid) { @@ -120,7 +137,8 @@ public void detect(ParticipantInfo pInfo, DBEntry quest) { for (int j = 0; j < requiredItems.size(); j++) { BigItemStack rStack = requiredItems.get(j); - if (!ItemComparison.StackMatch(rStack.getBaseStack(), stack, !ignoreNBT, partialMatch) && !ItemComparison.OreDictionaryMatch(rStack.getOreIngredient(), rStack.GetTagCompound(), stack, !ignoreNBT, partialMatch)) { + if (!ItemComparison.StackMatch(rStack.getBaseStack(), stack, !ignoreNBT, partialMatch) && !ItemComparison.OreDictionaryMatch(rStack + .getOreIngredient(), rStack.GetTagCompound(), stack, !ignoreNBT, partialMatch)) { continue; } @@ -338,7 +356,8 @@ public boolean canAcceptItem(UUID owner, DBEntry quest, ItemStack stack) if (progress[j] >= rStack.stackSize) continue; - if (ItemComparison.StackMatch(rStack.getBaseStack(), stack, !ignoreNBT, partialMatch) || ItemComparison.OreDictionaryMatch(rStack.getOreIngredient(), rStack.GetTagCompound(), stack, !ignoreNBT, partialMatch)) { + if (ItemComparison.StackMatch(rStack.getBaseStack(), stack, !ignoreNBT, partialMatch) || ItemComparison.OreDictionaryMatch(rStack + .getOreIngredient(), rStack.GetTagCompound(), stack, !ignoreNBT, partialMatch)) { return true; } } @@ -367,7 +386,8 @@ public ItemStack submitItem(UUID owner, DBEntry quest, ItemStack input) int remaining = rStack.stackSize - progress[j]; - if (ItemComparison.StackMatch(rStack.getBaseStack(), stack, !ignoreNBT, partialMatch) || ItemComparison.OreDictionaryMatch(rStack.getOreIngredient(), rStack.GetTagCompound(), stack, !ignoreNBT, partialMatch)) { + if (ItemComparison.StackMatch(rStack.getBaseStack(), stack, !ignoreNBT, partialMatch) || ItemComparison.OreDictionaryMatch(rStack + .getOreIngredient(), rStack.GetTagCompound(), stack, !ignoreNBT, partialMatch)) { int removed = Math.min(stack.getCount(), remaining); stack.shrink(removed); progress[j] += removed; @@ -436,4 +456,5 @@ public List getTextForSearch() { } return texts; } + } diff --git a/src/main/resources/assets/betterquesting/lang/en_us.lang b/src/main/resources/assets/betterquesting/lang/en_us.lang index 1983a1f89..d9d88af2e 100644 --- a/src/main/resources/assets/betterquesting/lang/en_us.lang +++ b/src/main/resources/assets/betterquesting/lang/en_us.lang @@ -313,6 +313,7 @@ bq_standard.tooltip.fixed_loot=Loot Set: %s bq_standard.tooltip.fixed_loot_size=Contains %s items bq_standard.tooltip.loot_table=Loot Table: %s bq_standard.tooltip.loot_chest=Rarity: %s +bq_standard.tooltip.consume=This will be consumed!! betterquesting.notification.enabled=Quest Notifications: On betterquesting.notification.disabled=Quest Notifications: Off