That's one heck of a commit you've got there...
I may have got a bit behind with version control. A lot behind, in fact. Maybe I'll go back and split this sometime - then again, I probably won't. But hey, at least it's here!
This commit is contained in:
@@ -1,23 +1,27 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import electroblob.wizardry.SpellGlyphData;
|
||||
import electroblob.wizardry.WizardData;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.IManaStoringItem;
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.item.IWorkbenchItem;
|
||||
import electroblob.wizardry.packet.PacketControlInput;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.ContainerArcaneWorkbench;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
@@ -25,131 +29,260 @@ import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
private GuiButton applyBtn;
|
||||
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID,
|
||||
public static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID,
|
||||
"textures/gui/arcane_workbench.png");
|
||||
|
||||
private IInventory playerInventory;
|
||||
private IInventory arcaneWorkbenchInventory;
|
||||
|
||||
private final int tooltipWidth = 164;
|
||||
private static final int TOOLTIP_WIDTH = 164;
|
||||
|
||||
// We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it.
|
||||
// For calculations, we use the size without the tooltip.
|
||||
private final int xSizeNoTip = 176;
|
||||
/** We report the actual size of the GUI to Minecraft when a wand is in so JEI doesn't overdraw it.
|
||||
* For calculations, we use the size without the tooltip, which is stored in this constant. */
|
||||
private static final int MAIN_GUI_WIDTH = 176;
|
||||
|
||||
private static final int RUNE_LEFT = 38;
|
||||
private static final int RUNE_TOP = 22;
|
||||
private static final int RUNE_WIDTH = 100;
|
||||
private static final int RUNE_HEIGHT = 100;
|
||||
|
||||
private static final int HALO_DIAMETER = 156;
|
||||
|
||||
private static final int TEXTURE_WIDTH = 512;
|
||||
private static final int TEXTURE_HEIGHT = 256;
|
||||
|
||||
private int animationTimer = 0;
|
||||
private static final int ANIMATION_DURATION = 20;
|
||||
|
||||
public GuiArcaneWorkbench(InventoryPlayer invPlayer, TileEntityArcaneWorkbench entity){
|
||||
super(new ContainerArcaneWorkbench(invPlayer, entity));
|
||||
this.playerInventory = invPlayer;
|
||||
this.arcaneWorkbenchInventory = entity;
|
||||
xSize = xSizeNoTip;
|
||||
xSize = MAIN_GUI_WIDTH;
|
||||
ySize = 220;
|
||||
}
|
||||
|
||||
// Huh, didn't realise this method existed. Pretty neat.
|
||||
@Override
|
||||
public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_){
|
||||
|
||||
this.drawDefaultBackground();
|
||||
|
||||
// Tests if there is a wand in the workbench and edits the positioning accordingly
|
||||
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots
|
||||
.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){
|
||||
xSize = xSizeNoTip + tooltipWidth;
|
||||
guiLeft = (this.width - this.xSize) / 2;
|
||||
this.applyBtn.x = (this.width - tooltipWidth) / 2 + 48;
|
||||
}else{
|
||||
xSize = xSizeNoTip;
|
||||
guiLeft = (this.width - this.xSize) / 2;
|
||||
this.applyBtn.x = this.width / 2 + 48;
|
||||
}
|
||||
|
||||
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){
|
||||
this.applyBtn.enabled = true;
|
||||
}else{
|
||||
this.applyBtn.enabled = false;
|
||||
}
|
||||
|
||||
super.drawScreen(p_73863_1_, p_73863_2_, p_73863_3_);
|
||||
|
||||
// Required now, or item mouseover tooltips won't render.
|
||||
this.renderHoveredToolTip(p_73863_1_, p_73863_2_);
|
||||
public void updateScreen(){
|
||||
if(animationTimer > 0) animationTimer--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY){
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
GlStateManager.color(1F, 1F, 1F, 1F);
|
||||
this.drawDefaultBackground();
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1); // Just in case
|
||||
|
||||
Slot slot = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT);
|
||||
|
||||
// Tests if there is a wand in the workbench and edits the positioning accordingly
|
||||
if(slot.getHasStack() && slot.getStack().getItem() instanceof IWorkbenchItem
|
||||
&& ((IWorkbenchItem)slot.getStack().getItem()).showTooltip(slot.getStack())){
|
||||
xSize = MAIN_GUI_WIDTH + TOOLTIP_WIDTH;
|
||||
guiLeft = (this.width - this.xSize) / 2;
|
||||
this.applyBtn.x = (this.width - TOOLTIP_WIDTH) / 2 + 64;
|
||||
}else{
|
||||
xSize = MAIN_GUI_WIDTH;
|
||||
guiLeft = (this.width - this.xSize) / 2;
|
||||
this.applyBtn.x = this.width / 2 + 64;
|
||||
}
|
||||
|
||||
this.applyBtn.enabled = slot.getHasStack();
|
||||
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
|
||||
// Required now, or item mouseover tooltips won't render.
|
||||
this.renderHoveredToolTip(mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY){
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
|
||||
// Animation
|
||||
|
||||
// Grey background
|
||||
DrawingUtils.drawTexturedRect(guiLeft + RUNE_LEFT, guiTop + RUNE_TOP, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, 0,
|
||||
RUNE_WIDTH, RUNE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
// Yellow 'halo'
|
||||
if(animationTimer > 0){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
int x = guiLeft + RUNE_LEFT + RUNE_WIDTH/2;
|
||||
int y = guiTop + RUNE_TOP + RUNE_HEIGHT/2;
|
||||
|
||||
float scale = (animationTimer + partialTicks)/ANIMATION_DURATION;
|
||||
scale = (float)(1 - Math.pow(1-scale, 1.4f)); // Makes it slower at the start and speed up
|
||||
GlStateManager.scale(scale, scale, 1);
|
||||
GlStateManager.translate(x/scale, y/scale, 0);
|
||||
|
||||
DrawingUtils.drawTexturedRect(-HALO_DIAMETER /2, -HALO_DIAMETER /2, MAIN_GUI_WIDTH + TOOLTIP_WIDTH, RUNE_HEIGHT,
|
||||
HALO_DIAMETER, HALO_DIAMETER, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
// Main inventory
|
||||
DrawingUtils.drawTexturedRect(guiLeft, guiTop, 0, 0, MAIN_GUI_WIDTH, ySize, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
float opacity = (animationTimer + partialTicks)/ANIMATION_DURATION;
|
||||
|
||||
// Changing slots
|
||||
for(int i = 0; i < ContainerArcaneWorkbench.CRYSTAL_SLOT; i++){
|
||||
|
||||
Slot slot = this.inventorySlots.getSlot(i);
|
||||
if(slot.xPos >= 0 && slot.yPos >= 0)
|
||||
this.drawTexturedModalRect(guiLeft + slot.xPos - 10, guiTop + slot.yPos - 10, 0, 220, 36, 36);
|
||||
|
||||
if(slot.xPos >= 0 && slot.yPos >= 0){
|
||||
// Slot background
|
||||
DrawingUtils.drawTexturedRect(guiLeft + slot.xPos - 10, guiTop + slot.yPos - 10, 0, 220, 36, 36, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
// Slot animation
|
||||
// IDEA: Somehow replace with intelligent check for whether the spell actually got applied
|
||||
if(animationTimer > 0 && slot.getHasStack()){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
GlStateManager.color(1, 1, 1, opacity);
|
||||
|
||||
DrawingUtils.drawTexturedRect(guiLeft + slot.xPos - 10, guiTop + slot.yPos - 10, 36, 220, 36, 36, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Crystal + upgrade slot animations
|
||||
if(animationTimer > 0){
|
||||
|
||||
Slot crystals = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CRYSTAL_SLOT);
|
||||
Slot upgrades = this.inventorySlots.getSlot(ContainerArcaneWorkbench.UPGRADE_SLOT);
|
||||
|
||||
if(crystals.getHasStack()){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
GlStateManager.color(1, 1, 1, opacity);
|
||||
|
||||
DrawingUtils.drawTexturedRect(guiLeft + crystals.xPos - 8, guiTop + crystals.yPos - 8,
|
||||
MAIN_GUI_WIDTH + TOOLTIP_WIDTH + RUNE_WIDTH, 0, 32, 32, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
if(upgrades.getHasStack()){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||
GlStateManager.color(1, 1, 1, opacity);
|
||||
|
||||
DrawingUtils.drawTexturedRect(guiLeft + upgrades.xPos - 8, guiTop + upgrades.yPos - 8,
|
||||
MAIN_GUI_WIDTH + TOOLTIP_WIDTH + RUNE_WIDTH, 0, 32, 32, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip only drawn if there is a wand
|
||||
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots
|
||||
.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){
|
||||
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){
|
||||
|
||||
// Tooltip box
|
||||
drawTexturedModalRect(guiLeft + xSizeNoTip, guiTop, xSizeNoTip, 0, 256 - xSizeNoTip - 4, ySize);
|
||||
drawTexturedModalRect(guiLeft + 252, guiTop, xSizeNoTip + 4, 0, tooltipWidth - 2 * (256 - xSizeNoTip - 4), ySize);
|
||||
drawTexturedModalRect(guiLeft + xSize - (256 - xSizeNoTip - 4), guiTop, xSizeNoTip + 4, 0,
|
||||
256 - xSizeNoTip - 4, ySize);
|
||||
ItemStack stack = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack();
|
||||
|
||||
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack();
|
||||
|
||||
Spell[] spells = WandHelper.getSpells(wand);
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(Spell spell : spells){
|
||||
|
||||
boolean discovered = true;
|
||||
|
||||
if(!this.mc.player.capabilities.isCreativeMode && WizardData.get(this.mc.player) != null){
|
||||
discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
// As of Wizardry 1.2, the icons have been split off into their own texture files to allow for add-on
|
||||
// mods to add their own.
|
||||
Minecraft.getMinecraft().renderEngine
|
||||
.bindTexture(discovered ? spell.element.getIcon() : Element.MAGIC.getIcon());
|
||||
|
||||
// Renders the little element icon
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, guiTop + 34 + 10 * i++, 8, 8);
|
||||
if(!(stack.getItem() instanceof IWorkbenchItem)){
|
||||
Wizardry.logger.warn("Invalid item in central slot of arcane workbench, how did that get there?!");
|
||||
return;
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int y = guiTop + 50 + spells.length * 10;
|
||||
if(((IWorkbenchItem)stack.getItem()).showTooltip(stack)){
|
||||
|
||||
// Look how much shorter this is with the WandHelper class!
|
||||
for(Item item : WandHelper.getSpecialUpgrades()){
|
||||
// Tooltip box
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH, guiTop, MAIN_GUI_WIDTH, 0, TOOLTIP_WIDTH, ySize, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
int level = WandHelper.getUpgradeLevel(wand, item);
|
||||
int y = guiTop + 20;
|
||||
|
||||
if(level > 0){
|
||||
ItemStack stack = new ItemStack(item, level);
|
||||
GlStateManager.enableDepth();
|
||||
this.itemRender.renderItemAndEffectIntoGUI(stack, guiLeft + xSizeNoTip + 6 + x, y);
|
||||
this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack, guiLeft + xSizeNoTip + 6 + x, y,
|
||||
null);
|
||||
x += 18;
|
||||
GlStateManager.disableDepth();
|
||||
if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){
|
||||
y += 14;
|
||||
}
|
||||
|
||||
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){
|
||||
|
||||
Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack);
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
|
||||
for(Spell spell : spells){
|
||||
|
||||
boolean discovered = true;
|
||||
|
||||
if(!this.mc.player.isCreative() && WizardData.get(this.mc.player) != null){
|
||||
discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
// As of Wizardry 1.2, the icons have been split off into their own texture files to allow for add-on
|
||||
// mods to add their own.
|
||||
Minecraft.getMinecraft().renderEngine
|
||||
.bindTexture(discovered ? spell.getElement().getIcon() : Element.MAGIC.getIcon());
|
||||
|
||||
// Renders the little element icon
|
||||
DrawingUtils.drawTexturedRect(guiLeft + MAIN_GUI_WIDTH + 5, y, 8, 8);
|
||||
|
||||
y += 10;
|
||||
}
|
||||
}
|
||||
|
||||
GlStateManager.disableBlend();
|
||||
|
||||
int x = 0;
|
||||
y += 16;
|
||||
|
||||
// Look how much shorter this is with the WandHelper class!
|
||||
for(Item item : WandHelper.getSpecialUpgrades()){
|
||||
|
||||
int level = WandHelper.getUpgradeLevel(stack, item);
|
||||
|
||||
if(level > 0){
|
||||
ItemStack stack1 = new ItemStack(item, level);
|
||||
GlStateManager.enableDepth();
|
||||
this.itemRender.renderItemAndEffectIntoGUI(stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y);
|
||||
this.itemRender.renderItemOverlayIntoGUI(this.fontRenderer, stack1, guiLeft + MAIN_GUI_WIDTH + 6 + x, y,
|
||||
null);
|
||||
x += 18;
|
||||
GlStateManager.disableDepth();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
|
||||
// Fixes the bug that caused the slot hightlight to render opaque. I don't know why it works, it just works!
|
||||
// Fixes the bug that caused the slot highlight to render opaque. I don't know why it works, it just works!
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableAlpha();
|
||||
}
|
||||
@@ -157,64 +290,86 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
@Override
|
||||
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1); // Just in case
|
||||
|
||||
this.fontRenderer
|
||||
.drawString(this.arcaneWorkbenchInventory.hasCustomName() ? this.arcaneWorkbenchInventory.getName()
|
||||
: I18n.format(this.arcaneWorkbenchInventory.getName()), 8, 6, 4210752);
|
||||
this.fontRenderer.drawString(this.playerInventory.hasCustomName() ? this.playerInventory.getName()
|
||||
: I18n.format(this.playerInventory.getName()), 8, this.ySize - 96 + 2, 4210752);
|
||||
|
||||
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack() && this.inventorySlots
|
||||
.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack().getItem() instanceof ItemWand){
|
||||
if(this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getHasStack()){
|
||||
|
||||
ItemStack wand = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack();
|
||||
ItemStack stack = this.inventorySlots.getSlot(ContainerArcaneWorkbench.CENTRE_SLOT).getStack();
|
||||
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + wand.getDisplayName(), xSizeNoTip + 6, 6, 0);
|
||||
this.fontRenderer.drawStringWithShadow(
|
||||
"\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana") + " "
|
||||
+ (wand.getMaxDamage() - wand.getItemDamage()) + "/" + wand.getMaxDamage(),
|
||||
xSizeNoTip + 6, 20, 0);
|
||||
|
||||
Spell[] spells = WandHelper.getSpells(wand);
|
||||
|
||||
int y = 34;
|
||||
|
||||
for(Spell spell : spells){
|
||||
|
||||
boolean discovered = true;
|
||||
|
||||
if(!this.mc.player.capabilities.isCreativeMode && WizardData.get(this.mc.player) != null){
|
||||
discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), xSizeNoTip + 16, y, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawStringWithShadow(
|
||||
"\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), xSizeNoTip + 16, y, 0);
|
||||
}
|
||||
y += 10;
|
||||
if(!(stack.getItem() instanceof IWorkbenchItem)){
|
||||
Wizardry.logger.warn("Invalid item in central slot of arcane workbench, how did that get there?!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(WandHelper.getTotalUpgrades(wand) > 0){
|
||||
if(((IWorkbenchItem)stack.getItem()).showTooltip(stack)){
|
||||
|
||||
this.fontRenderer.drawStringWithShadow(
|
||||
"\u00A7f" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.upgrades"), xSizeNoTip + 6, y + 6, 0);
|
||||
int y = 6;
|
||||
|
||||
int x = 0;
|
||||
y = 50 + spells.length * 10;
|
||||
// Wand upgrade tooltips
|
||||
for(Item item : WandHelper.getSpecialUpgrades()){
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + stack.getDisplayName(), MAIN_GUI_WIDTH + 6, y, 0);
|
||||
|
||||
int level = WandHelper.getUpgradeLevel(wand, item);
|
||||
if(stack.getItem() instanceof IManaStoringItem && ((IManaStoringItem)stack.getItem()).showManaInWorkbench(this.mc.player, stack)){
|
||||
y += 14;
|
||||
this.fontRenderer.drawStringWithShadow(
|
||||
"\u00A77" + I18n.format("container." + Wizardry.MODID + ":arcane_workbench.mana")
|
||||
+ " " + ((IManaStoringItem)stack.getItem()).getMana(stack) + "/"
|
||||
+ ((IManaStoringItem)stack.getItem()).getManaCapacity(stack),
|
||||
MAIN_GUI_WIDTH + 6, y, 0);
|
||||
}
|
||||
|
||||
if(level > 0){
|
||||
// The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is
|
||||
// relative to the GUI but the POINT isn't.
|
||||
if(isPointInRegion(xSizeNoTip + 6 + x, y, 16, 16, mouseX, mouseY)){
|
||||
ItemStack stack = new ItemStack(item, level);
|
||||
this.renderToolTip(stack, mouseX - guiLeft, mouseY - guiTop);
|
||||
y += 14;
|
||||
|
||||
if(stack.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)stack.getItem()).showSpellsInWorkbench(this.mc.player, stack)){
|
||||
|
||||
Spell[] spells = ((ISpellCastingItem)stack.getItem()).getSpells(stack);
|
||||
|
||||
for(Spell spell : spells){
|
||||
|
||||
boolean discovered = true;
|
||||
|
||||
if(!this.mc.player.isCreative() && WizardData.get(this.mc.player) != null){
|
||||
discovered = WizardData.get(this.mc.player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawStringWithShadow(spell.getDisplayNameWithFormatting(), MAIN_GUI_WIDTH + 16, y, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawStringWithShadow(
|
||||
"\u00A79" + SpellGlyphData.getGlyphName(spell, this.mc.world), MAIN_GUI_WIDTH + 16, y, 0);
|
||||
}
|
||||
y += 10;
|
||||
}
|
||||
}
|
||||
|
||||
if(WandHelper.getTotalUpgrades(stack) > 0){
|
||||
|
||||
y += 6;
|
||||
|
||||
this.fontRenderer.drawStringWithShadow("\u00A7f" + I18n.format("container."
|
||||
+ Wizardry.MODID + ":arcane_workbench.upgrades"), MAIN_GUI_WIDTH + 6, y, 0);
|
||||
|
||||
int x = 0;
|
||||
y += 10;
|
||||
|
||||
// Wand upgrade tooltips
|
||||
for(Item item : WandHelper.getSpecialUpgrades()){
|
||||
|
||||
int level = WandHelper.getUpgradeLevel(stack, item);
|
||||
|
||||
if(level > 0){
|
||||
// The javadoc for isPointInRegion is ambiguous; what it means is that the REGION is
|
||||
// relative to the GUI but the POINT isn't.
|
||||
if(isPointInRegion(MAIN_GUI_WIDTH + 6 + x, y, 16, 16, mouseX, mouseY)){
|
||||
ItemStack stack1 = new ItemStack(item, level);
|
||||
this.renderToolTip(stack1, mouseX - guiLeft, mouseY - guiTop);
|
||||
}
|
||||
x += 18;
|
||||
}
|
||||
x += 18;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +383,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
this.guiTop = (this.height - this.ySize) / 2;
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 48, this.height / 2 + 3));
|
||||
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -244,8 +399,51 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
// Packet building
|
||||
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.APPLY_BUTTON);
|
||||
WizardryPacketHandler.net.sendToServer(msg);
|
||||
// Sound
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(
|
||||
WizardrySounds.BLOCK_ARCANE_WORKBENCH_SPELLBIND, 1));
|
||||
// Animation
|
||||
animationTimer = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class GuiButtonApply extends GuiButton {
|
||||
|
||||
public GuiButtonApply(int id, int x, int y){
|
||||
super(id, x, y, 16, 16, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.apply"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
// Whether the button is highlighted
|
||||
this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
||||
|
||||
int k = 72;
|
||||
int l = 220;
|
||||
//int colour = 14737632;
|
||||
|
||||
if(this.enabled){
|
||||
if(this.hovered){
|
||||
k += this.width * 2;
|
||||
//colour = 16777120;
|
||||
}
|
||||
}else{
|
||||
k += this.width;
|
||||
//colour = 10526880;
|
||||
}
|
||||
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, 512, 256);
|
||||
//this.drawCenteredString(minecraft.fontRenderer, this.displayString, this.x + this.width / 2,
|
||||
// this.y + (this.height - 8) / 2, colour);
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
|
||||
event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_CRYSTAL);
|
||||
event.getMap().registerSprite(ContainerArcaneWorkbench.EMPTY_SLOT_UPGRADE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,10 +2,8 @@ package electroblob.wizardry.client.gui;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class GuiButtonInvisible extends GuiButton {
|
||||
|
||||
public GuiButtonInvisible(int id, int x, int y, int width, int height){
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.item.ItemArtefact;
|
||||
import electroblob.wizardry.packet.PacketControlInput;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.spell.Resurrection;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiGameOver;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class GuiButtonResurrect extends GuiButton {
|
||||
|
||||
private static int timeSinceDeath = -1;
|
||||
|
||||
private final String translationKey;
|
||||
|
||||
public GuiButtonResurrect(int id, int x, int y, String translationKey){
|
||||
super(id, x, y, I18n.format(translationKey + "_wait", Resurrection.getRemainingWaitTime(timeSinceDeath)));
|
||||
this.translationKey = translationKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks){
|
||||
int waitTime = Resurrection.getRemainingWaitTime(timeSinceDeath);
|
||||
this.enabled = waitTime == 0;
|
||||
this.displayString = I18n.format(translationKey + (waitTime == 0 ? "_ready" : "_wait"), waitTime);
|
||||
super.drawButton(mc, mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onClientTickEvent(TickEvent.ClientTickEvent event){
|
||||
if(event.phase == TickEvent.Phase.START && timeSinceDeath >= 0) timeSinceDeath++;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onGuiScreenInitEvent(GuiScreenEvent.InitGuiEvent event){
|
||||
|
||||
if(event.getGui() instanceof GuiGameOver && ItemArtefact.isArtefactActive(Minecraft.getMinecraft().player, WizardryItems.amulet_resurrection)
|
||||
&& WizardryUtilities.getHotbar(Minecraft.getMinecraft().player).stream().anyMatch(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player))){
|
||||
|
||||
event.getButtonList().add(new GuiButtonResurrect(event.getButtonList().size(), event.getGui().width / 2 - 100,
|
||||
event.getGui().height / 4 + 120, "spell." + Spells.resurrection.getRegistryName() + ".button"));
|
||||
timeSinceDeath = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onGuiScreenActionPerformedEvent(GuiScreenEvent.ActionPerformedEvent event){
|
||||
|
||||
if(event.getGui() instanceof GuiGameOver){
|
||||
|
||||
ItemStack stack = WizardryUtilities.getHotbar(Minecraft.getMinecraft().player).stream()
|
||||
.filter(s -> Resurrection.canStackResurrect(s, Minecraft.getMinecraft().player)).findFirst().orElse(null);
|
||||
|
||||
if(stack != null){
|
||||
|
||||
if(event.getButton() instanceof GuiButtonResurrect && timeSinceDeath >= 0){
|
||||
// Cast resurrection on the client player and notify the server to do the same
|
||||
// ISpellCastingItem#canCast already checked in Resurrection#canStackResurrect
|
||||
((ISpellCastingItem)stack.getItem()).cast(stack, Spells.resurrection, Minecraft.getMinecraft().player, EnumHand.MAIN_HAND, 0, new SpellModifiers());
|
||||
WizardryPacketHandler.net.sendToServer(new PacketControlInput.Message(PacketControlInput.ControlType.RESURRECT_BUTTON));
|
||||
|
||||
}else if(!Minecraft.getMinecraft().world.getGameRules().getBoolean("keepInventory")){
|
||||
// Any other button drops the wand (N.B. this should be inside the stack != null check or it'll send
|
||||
// packets unnecessarily and generate incorrect warnings
|
||||
WizardryPacketHandler.net.sendToServer(new PacketControlInput.Message(PacketControlInput.ControlType.CANCEL_RESURRECT));
|
||||
}
|
||||
|
||||
timeSinceDeath = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +1,34 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import electroblob.wizardry.SpellGlyphData;
|
||||
import electroblob.wizardry.WizardData;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class GuiSpellBook extends GuiScreen {
|
||||
|
||||
private int xSize, ySize;
|
||||
private Spell spell;
|
||||
|
||||
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/spellbook.png");
|
||||
private static final Map<Tier, ResourceLocation> textures = ImmutableMap.of(
|
||||
Tier.NOVICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_novice.png"),
|
||||
Tier.APPRENTICE, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_apprentice.png"),
|
||||
Tier.ADVANCED, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_advanced.png"),
|
||||
Tier.MASTER, new ResourceLocation(Wizardry.MODID, "textures/gui/spell_book_master.png"));
|
||||
|
||||
public GuiSpellBook(Spell spell){
|
||||
super();
|
||||
@@ -39,45 +48,47 @@ public class GuiSpellBook extends GuiScreen {
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
boolean discovered = true;
|
||||
if(Wizardry.settings.discoveryMode && !player.capabilities.isCreativeMode && WizardData.get(player) != null
|
||||
if(Wizardry.settings.discoveryMode && !player.isCreative() && WizardData.get(player) != null
|
||||
&& !WizardData.get(player).hasSpellBeenDiscovered(spell)){
|
||||
discovered = false;
|
||||
}
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1); // Just in case
|
||||
|
||||
// Draws spell illustration on opposite page, underneath the book so it shows through the hole.
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
|
||||
DrawingUtils.drawTexturedRect(xPos + 146, yPos + 20, 0, 0, 128, 128, 128, 128);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.tier));
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(textures.get(spell.getTier()));
|
||||
DrawingUtils.drawTexturedRect(xPos, yPos, 0, 0, xSize, ySize, xSize, 256);
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawString(spell.getDisplayName(), xPos + 17, yPos + 15, 0);
|
||||
this.fontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 26, 0x777777);
|
||||
this.fontRenderer.drawString(spell.getType().getDisplayName(), xPos + 17, yPos + 26, 0x777777);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(spell, player.world), xPos + 17,
|
||||
yPos + 15, 0);
|
||||
this.mc.standardGalacticFontRenderer.drawString(spell.type.getDisplayName(), xPos + 17, yPos + 26,
|
||||
this.mc.standardGalacticFontRenderer.drawString(spell.getType().getDisplayName(), xPos + 17, yPos + 26,
|
||||
0x777777);
|
||||
}
|
||||
|
||||
this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
|
||||
//this.fontRenderer.drawString("-------------------", xPos + 17, yPos + 35, 0);
|
||||
|
||||
if(spell.tier == Tier.BASIC){
|
||||
if(spell.getTier() == Tier.NOVICE){
|
||||
// Basic is usually white but this doesn't show up.
|
||||
this.fontRenderer.drawString("Tier: \u00A77" + Tier.BASIC.getDisplayName(), xPos + 17, yPos + 45, 0);
|
||||
this.fontRenderer.drawString("Tier: \u00A77" + Tier.NOVICE.getDisplayName(), xPos + 17, yPos + 45, 0);
|
||||
}else{
|
||||
this.fontRenderer.drawString("Tier: " + spell.tier.getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
|
||||
this.fontRenderer.drawString("Tier: " + spell.getTier().getDisplayNameWithFormatting(), xPos + 17, yPos + 45, 0);
|
||||
}
|
||||
|
||||
String element = "Element: " + spell.element.getFormattingCode() + spell.element.getDisplayName();
|
||||
String element = "Element: " + spell.getElement().getFormattingCode() + spell.getElement().getDisplayName();
|
||||
if(!discovered) element = "Element: ?";
|
||||
this.fontRenderer.drawString(element, xPos + 17, yPos + 57, 0);
|
||||
|
||||
String manaCost = "Mana Cost: " + spell.cost;
|
||||
if(spell.isContinuous) manaCost = "Mana Cost: " + spell.cost + "/second";
|
||||
String manaCost = "Mana Cost: " + spell.getCost();
|
||||
if(spell.isContinuous) manaCost = "Mana Cost: " + spell.getCost() + "/second";
|
||||
if(!discovered) manaCost = "Mana Cost: ?";
|
||||
this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 69, 0);
|
||||
|
||||
@@ -93,10 +104,18 @@ public class GuiSpellBook extends GuiScreen {
|
||||
super.initGui();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
|
||||
this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1));
|
||||
}
|
||||
|
||||
public void onGuiClosed(){
|
||||
super.onGuiClosed();
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesGuiPauseGame(){
|
||||
return Wizardry.settings.booksPauseGame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,30 +1,17 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import electroblob.wizardry.Settings;
|
||||
import electroblob.wizardry.SpellGlyphData;
|
||||
import electroblob.wizardry.WizardData;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.ClientProxy;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.client.MixedFontRenderer;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.ISpellCastingItem;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
@@ -37,14 +24,22 @@ import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumHandSide;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class GuiSpellDisplay {
|
||||
|
||||
@@ -53,8 +48,9 @@ public class GuiSpellDisplay {
|
||||
/** A map which stores all loaded HUD skin objects. This gets wiped on resource pack reload and repopulated with
|
||||
* mappings as specified by {@code _index.json} (these stack between resource packs). The keys in the map correspond
|
||||
* to the keys in {@code _index.json}, and are sorted in that order, with skins belonging to resource packs sorted
|
||||
* from lowest to highest priority. The skins in the base mod will therefore always be first. */
|
||||
private static final Map<String, Skin> skins = new LinkedHashMap<>(12); // 12 is the number of skins packaged with the mod
|
||||
* from lowest to highest priority. The skins in the base mod will therefore always be first. (It should be noted,
|
||||
* however, that in the gui itself the skins are always sorted in alphabetical order for some reason.) */
|
||||
private static final Map<String, Skin> skins = new LinkedHashMap<>(14); // 14 is the number of skins packaged with the mod
|
||||
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
@@ -66,6 +62,9 @@ public class GuiSpellDisplay {
|
||||
private static final float SPELL_NAME_SCALE = 0.5f;
|
||||
/** Opacity of the next/previous spell names, as a fraction. */
|
||||
private static final float SPELL_NAME_OPACITY = 0.3f;
|
||||
|
||||
private static final int HALF_HOTBAR_WIDTH = 97; // Half the width of the hotbar, plus a bit for clearance
|
||||
private static final int OFFHAND_SLOT_WIDTH = 29; // Width of the offhand slot plus the gap between it and the hotbar
|
||||
|
||||
/** Controls the spell switching animation. Positive when switching to the next spell, negative when switching to
|
||||
* the previous spell. Decremented in magnitude by 1 each tick until it reaches 0 again. */
|
||||
@@ -103,14 +102,18 @@ public class GuiSpellDisplay {
|
||||
|
||||
EntityPlayer player = mc.player;
|
||||
|
||||
if(player.isSpectator()) return; // Spectators shouldn't have the spell HUD!
|
||||
|
||||
// If the player has a wand in each hand, only displays for the one in the main hand.
|
||||
|
||||
ItemStack wand = player.getHeldItemMainhand();
|
||||
boolean mainHand = true;
|
||||
|
||||
if(!(wand.getItem() instanceof ItemWand)){
|
||||
if(!(wand.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)wand.getItem()).showSpellHUD(player, wand))){
|
||||
wand = player.getHeldItemOffhand();
|
||||
// If the player isn't holding a wand, then nothing else needs to be done.
|
||||
if(!(wand.getItem() instanceof ItemWand)) return;
|
||||
mainHand = false;
|
||||
// If the player isn't holding a spellcasting item that shows the HUD, then nothing else needs to be done.
|
||||
if(!(wand.getItem() instanceof ISpellCastingItem && ((ISpellCastingItem)wand.getItem()).showSpellHUD(player, wand))) return;
|
||||
}
|
||||
|
||||
int width = event.getResolution().getScaledWidth();
|
||||
@@ -118,6 +121,11 @@ public class GuiSpellDisplay {
|
||||
|
||||
boolean flipX = Wizardry.settings.spellHUDPosition.flipX;
|
||||
boolean flipY = Wizardry.settings.spellHUDPosition.flipY;
|
||||
|
||||
if(Wizardry.settings.spellHUDPosition.dynamic){
|
||||
// ............. | This bit is true if the wand is on the left, false if it is on the right
|
||||
flipX = flipX == ((mainHand ? player.getPrimaryHand() : player.getPrimaryHand().opposite()) == EnumHandSide.LEFT);
|
||||
}
|
||||
|
||||
Skin skin = skins.get(Wizardry.settings.spellHUDSkin);
|
||||
|
||||
@@ -134,13 +142,32 @@ public class GuiSpellDisplay {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
// 'Origin' of the spell hud (bottom left corner of the actual texture, always in the corner of the screen)
|
||||
int x = flipX ? width : 0;
|
||||
int y = flipY ? 0: height;
|
||||
|
||||
// The space available to render the spell HUD
|
||||
float xSpace = (float)(width/2 - HALF_HOTBAR_WIDTH);
|
||||
if(!player.getHeldItemOffhand().isEmpty()
|
||||
// Tests whether the offhand slot is rendered on the same side of the hotbar as the spell HUD
|
||||
&& (player.getPrimaryHand() == EnumHandSide.LEFT) == flipX){
|
||||
xSpace -= OFFHAND_SLOT_WIDTH;
|
||||
}
|
||||
|
||||
// If the skin is at the bottom and the screen width is too small, scale it to avoid the hotbar and offhand
|
||||
if(!flipY && skin.getWidth() > xSpace){ // width/2 - 91 - 29 taken from GuiInGame line 547
|
||||
float scale = xSpace / skin.getWidth();
|
||||
GlStateManager.scale(scale, scale, 1);
|
||||
x = MathHelper.ceil(x/scale);
|
||||
y = MathHelper.ceil(y/scale);
|
||||
}
|
||||
|
||||
Spell spell = WandHelper.getCurrentSpell(wand);
|
||||
int cooldown = WandHelper.getCurrentCooldown(wand);
|
||||
int maxCooldown = WandHelper.getCurrentMaxCooldown(wand);
|
||||
|
||||
if(event.getType() == RenderGameOverlayEvent.ElementType.TEXT){
|
||||
|
||||
@@ -155,16 +182,9 @@ public class GuiSpellDisplay {
|
||||
|
||||
}else if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR){
|
||||
|
||||
float cooldownMultiplier = 1.0f - WandHelper.getUpgradeLevel(wand, WizardryItems.cooldown_upgrade) * Constants.COOLDOWN_REDUCTION_PER_LEVEL;
|
||||
|
||||
if(player.isPotionActive(WizardryPotions.font_of_mana)){
|
||||
// Dividing by this rather than setting it takes upgrades and font of mana into account simultaneously
|
||||
cooldownMultiplier /= 2 + player.getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier();
|
||||
}
|
||||
|
||||
boolean discovered = true;
|
||||
|
||||
if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){
|
||||
if(!player.isCreative() && WizardData.get(player) != null){
|
||||
discovered = WizardData.get(player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
|
||||
@@ -172,31 +192,23 @@ public class GuiSpellDisplay {
|
||||
|
||||
float progress = 1;
|
||||
// Doesn't really matter what progress is when in creative, but we might as well avoid the calculation.
|
||||
if(!player.capabilities.isCreativeMode && !spell.isContinuous){
|
||||
if(!player.isCreative() && !spell.isContinuous){
|
||||
// Subtracted partial tick time to make it smoother
|
||||
progress = (spell.cooldown * cooldownMultiplier - (float)cooldown + event.getPartialTicks())
|
||||
/(spell.cooldown * cooldownMultiplier);
|
||||
progress = maxCooldown == 0 ? 1 : (maxCooldown - (float)cooldown + event.getPartialTicks()) / maxCooldown;
|
||||
}
|
||||
|
||||
skin.drawBackground(x, y, flipX, flipY, icon, progress, player.capabilities.isCreativeMode);
|
||||
skin.drawBackground(x, y, flipX, flipY, icon, progress, player.isCreative());
|
||||
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the given opaque colour translucent with the given opacity.
|
||||
* @param colour An integer colour code, should be a 6-digit hexadecimal (i.e. opaque).
|
||||
* @param opacity The opacity to apply to the given colour, as a fraction between 0 and 1.
|
||||
* @return The resulting integer colour code, which will be an 8-digit hexadecimal.
|
||||
*/
|
||||
private static int makeTranslucent(int colour, float opacity){
|
||||
return colour + ((int)(0xff * opacity * 0x01000000));
|
||||
}
|
||||
|
||||
/** Gets the name of the given spell, with formatted added according to its cooldown and whether the given player
|
||||
* Gets the name of the given spell, with formatting added according to its cooldown and whether the given player
|
||||
* has discovered it.
|
||||
* @param spell The spell to get the name of.
|
||||
* @param The player to test for having discovered the given spell.
|
||||
* @param player The player to test for having discovered the given spell.
|
||||
* @param cooldown The spell's current cooldown.
|
||||
* @return The spell name, with relevant formatting added, for use with the {@link MixedFontRenderer}.
|
||||
*/
|
||||
@@ -204,12 +216,12 @@ public class GuiSpellDisplay {
|
||||
|
||||
boolean discovered = true;
|
||||
|
||||
if(!player.capabilities.isCreativeMode && WizardData.get(player) != null){
|
||||
if(!player.isCreative() && WizardData.get(player) != null){
|
||||
discovered = WizardData.get(player).hasSpellBeenDiscovered(spell);
|
||||
}
|
||||
|
||||
// Makes spells greyed out if they are in cooldown or if the player has the arcane jammer effect
|
||||
String format = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.element.getFormattingCode();
|
||||
String format = cooldown > 0 || player.isPotionActive(WizardryPotions.arcane_jammer) ? "\u00A78" : spell.getElement().getFormattingCode();
|
||||
if(!discovered) format = "\u00A79";
|
||||
|
||||
String name = discovered ? spell.getDisplayName() : SpellGlyphData.getGlyphName(spell, player.world);
|
||||
@@ -274,10 +286,15 @@ public class GuiSpellDisplay {
|
||||
}
|
||||
}
|
||||
|
||||
/** Instances of this class represent individual HUD skins, complete with texture and all necessary metadata. This
|
||||
/**
|
||||
* Instances of this class represent individual HUD skins, complete with texture and all necessary metadata. This
|
||||
* class serves to separate the logic behind the spell HUD from its actual rendering.
|
||||
* All information and processing done within this class relates only to the actual drawing; spells and such like
|
||||
* must be queried outside of this class and fed into the methods as appropriate. */
|
||||
* must be queried outside of this class and fed into the methods as appropriate.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2
|
||||
*/
|
||||
public static class Skin {
|
||||
|
||||
/** The texture file for this skin. */
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package electroblob.wizardry.client.gui.config;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.client.config.*;
|
||||
import net.minecraftforge.fml.client.config.GuiEditArrayEntries.StringEntry;
|
||||
import net.minecraftforge.fml.common.registry.EntityEntry;
|
||||
import net.minecraftforge.fml.common.registry.ForgeRegistries;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* [NYI] Intended as a way of choosing entities by name from all those currently registered, within the config file, so
|
||||
* that users don't have to look up the entity IDs. I can't get this to work correctly at the moment.
|
||||
*/
|
||||
public class EntityNameEntry extends StringEntry {
|
||||
|
||||
protected final GuiButtonExt btnValue;
|
||||
protected Object entityClass;
|
||||
|
||||
public EntityNameEntry(GuiEditArray owningScreen, GuiEditArrayEntries owningEntryList, IConfigElement configElement,
|
||||
Object value){
|
||||
super(owningScreen, owningEntryList, configElement, value);
|
||||
this.btnValue = new GuiButtonExt(0, 0, 0, owningEntryList.controlWidth, 18,
|
||||
I18n.format(this.textFieldValue.getText()));
|
||||
// this.btnValue.enabled = owningScreen.enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY,
|
||||
boolean isSelected, float partialTicks){
|
||||
//super.drawEntry(slotIndex, x, y, listWidth, slotHeight, mouseX, mouseY, isSelected, partial);
|
||||
this.btnValue.x = listWidth / 4;
|
||||
this.btnValue.y = y;
|
||||
|
||||
String trans = I18n.format(this.textFieldValue.getText());
|
||||
if(!trans.equals(this.textFieldValue.getText()))
|
||||
this.btnValue.displayString = trans;
|
||||
else
|
||||
this.btnValue.displayString = this.textFieldValue.getText();
|
||||
// btnValue.packedFGColour = value ? GuiUtils.getColorCode('2', true) : GuiUtils.getColorCode('4', true);
|
||||
|
||||
this.btnValue.drawButton(owningEntryList.getMC(), mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(int index, int x, int y, int mouseEvent, int relativeX, int relativeY){
|
||||
if(this.btnValue.mousePressed(owningEntryList.getMC(), x, y)){
|
||||
btnValue.playPressSound(owningEntryList.getMC().getSoundHandler());
|
||||
// Goodness only knows if this works, but the class is unimplemented right now so it doesn't really matter.
|
||||
Map<Object, String> map = ForgeRegistries.ENTITIES.getEntries().stream().collect(
|
||||
Collectors.<Entry<ResourceLocation, EntityEntry>, Object, String>toMap(e -> e.getValue().getClass(),
|
||||
e -> e.getValue().getName()));
|
||||
Minecraft.getMinecraft().displayGuiScreen(
|
||||
new GuiSelectString(this.owningScreen, configElement, index, map, this.getValue(), true));
|
||||
owningEntryList.recalculateState();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.mousePressed(index, x, y, mouseEvent, relativeX, relativeY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(int index, int x, int y, int mouseEvent, int relativeX, int relativeY){
|
||||
this.btnValue.mouseReleased(x, y);
|
||||
super.mouseReleased(index, x, y, mouseEvent, relativeX, relativeY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(){
|
||||
return this.textFieldValue.getText();
|
||||
}
|
||||
|
||||
}
|
||||
+43
-32
@@ -1,7 +1,4 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
package electroblob.wizardry.client.gui.config;
|
||||
|
||||
import electroblob.wizardry.Settings;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
@@ -15,6 +12,9 @@ import net.minecraftforge.fml.client.config.GuiConfigEntries;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.CategoryEntry;
|
||||
import net.minecraftforge.fml.client.config.IConfigElement;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GuiConfigWizardry extends GuiConfig {
|
||||
|
||||
public GuiConfigWizardry(GuiScreen parent){
|
||||
@@ -33,7 +33,8 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
configList.add(new DummyCategoryElement("clientConfig", "config." + Wizardry.MODID + ".category." + Settings.CLIENT_CATEGORY, ClientCategory.class));
|
||||
configList.add(new DummyCategoryElement("spellsConfig", "config." + Wizardry.MODID + ".category." + Settings.SPELLS_CATEGORY, SpellsCategory.class));
|
||||
configList.add(new DummyCategoryElement("resistancesConfig", "config." + Wizardry.MODID + ".category." + Settings.RESISTANCES_CATEGORY, ResistancesCategory.class));
|
||||
|
||||
configList.add(new DummyCategoryElement("compatibilityConfig", "config." + Wizardry.MODID + ".category." + Settings.COMPATIBILITY_CATEGORY, CompatibilityCategory.class));
|
||||
|
||||
configList.addAll(new ConfigElement(Wizardry.settings.getConfigCategory(Configuration.CATEGORY_GENERAL)).getChildElements());
|
||||
|
||||
return configList;
|
||||
@@ -41,7 +42,7 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
|
||||
// The reason this system is so convoluted is that it's designed for use with the @Config annotation. The problem is,
|
||||
// I'm not sure whether that will play well with the load phases. Hmmm...
|
||||
|
||||
|
||||
public static abstract class CategoryBase extends CategoryEntry {
|
||||
|
||||
public CategoryBase(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
@@ -77,6 +78,36 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
|
||||
@Override protected String getCategory() { return Settings.GAMEPLAY_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Worldgen category of the config gui. */
|
||||
public static class WorldgenCategory extends CategoryBase {
|
||||
|
||||
public WorldgenCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.WORLDGEN_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Commands category of the config gui. */
|
||||
public static class CommandsCategory extends CategoryBase {
|
||||
|
||||
public CommandsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.COMMANDS_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Client category of the config gui. */
|
||||
public static class ClientCategory extends CategoryBase {
|
||||
|
||||
public ClientCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.CLIENT_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Spells category of the config gui. */
|
||||
public static class SpellsCategory extends CategoryBase {
|
||||
@@ -97,34 +128,14 @@ public class GuiConfigWizardry extends GuiConfig {
|
||||
|
||||
@Override protected String getCategory() { return Settings.RESISTANCES_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Worldgen category of the config gui. */
|
||||
public static class WorldgenCategory extends CategoryBase {
|
||||
|
||||
public WorldgenCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.WORLDGEN_CATEGORY; }
|
||||
}
|
||||
|
||||
/** Client category of the config gui. */
|
||||
public static class ClientCategory extends CategoryBase {
|
||||
|
||||
public ClientCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.CLIENT_CATEGORY; }
|
||||
}
|
||||
|
||||
|
||||
/** Commands category of the config gui. */
|
||||
public static class CommandsCategory extends CategoryBase {
|
||||
|
||||
public CommandsCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
public static class CompatibilityCategory extends CategoryBase {
|
||||
|
||||
public CompatibilityCategory(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop);
|
||||
}
|
||||
|
||||
@Override protected String getCategory() { return Settings.COMMANDS_CATEGORY; }
|
||||
|
||||
@Override protected String getCategory() { return Settings.COMPATIBILITY_CATEGORY; }
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -1,12 +1,8 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
package electroblob.wizardry.client.gui.config;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.gui.GuiSpellDisplay;
|
||||
import electroblob.wizardry.client.gui.GuiSpellDisplay.Skin;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
@@ -16,6 +12,9 @@ import net.minecraft.client.resources.I18n;
|
||||
import net.minecraftforge.fml.client.config.GuiSelectString;
|
||||
import net.minecraftforge.fml.client.config.IConfigElement;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
|
||||
public class GuiSelectHUDSkin extends GuiSelectString {
|
||||
|
||||
public GuiSelectHUDSkin(GuiScreen parentScreen, IConfigElement configElement, int slotIndex, Map<Object, String> selectableValues, Object currentValue, boolean enabled){
|
||||
@@ -50,7 +49,7 @@ public class GuiSelectHUDSkin extends GuiSelectString {
|
||||
|
||||
if(this.currentValue instanceof String){
|
||||
|
||||
this.drawString(this.fontRenderer, I18n.format("config." + Wizardry.MODID + ":spell_hud_skin.preview"), 170, 44, 0xffffff);
|
||||
this.drawString(this.fontRenderer, I18n.format("config." + Wizardry.MODID + ".spell_hud_skin.preview"), 170, 44, 0xffffff);
|
||||
|
||||
int previewLeft = 170;
|
||||
int previewRight = width-10;
|
||||
@@ -0,0 +1,93 @@
|
||||
package electroblob.wizardry.client.gui.config;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraftforge.fml.client.config.GuiConfig;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries;
|
||||
import net.minecraftforge.fml.client.config.GuiUtils;
|
||||
import net.minecraftforge.fml.client.config.IConfigElement;
|
||||
|
||||
/**
|
||||
* Same as {@link net.minecraftforge.fml.client.config.GuiConfigEntries.BooleanEntry}, but instead of simply
|
||||
* displaying 'true' or 'false', allows the two display strings to be specified in the lang file.
|
||||
*/
|
||||
// BooleanEntry's constructors are private, so I had to copy the whole goddamn class to change one method. Thanks Forge.
|
||||
public class NamedBooleanEntry extends GuiConfigEntries.ButtonEntry {
|
||||
|
||||
protected final boolean beforeValue;
|
||||
protected boolean currentValue;
|
||||
|
||||
private static final String DEFAULT_KEY = "config.ebwizardry.generic";
|
||||
|
||||
public NamedBooleanEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement configElement){
|
||||
super(owningScreen, owningEntryList, configElement);
|
||||
this.beforeValue = Boolean.valueOf(configElement.get().toString());
|
||||
this.currentValue = beforeValue;
|
||||
this.btnValue.enabled = enabled();
|
||||
updateValueButtonText();
|
||||
}
|
||||
|
||||
// This is the only method that's any different
|
||||
@Override
|
||||
public void updateValueButtonText(){
|
||||
|
||||
String langKey = configElement.getLanguageKey() + "." + currentValue;
|
||||
this.btnValue.displayString = I18n.format(langKey);
|
||||
// If the key is unspecified, it defaults to the generic 'Enabled'/'Disabled' keys and adds a red/green colour
|
||||
if(this.btnValue.displayString.equals(langKey)){
|
||||
this.btnValue.displayString = I18n.format(DEFAULT_KEY + "." + currentValue);
|
||||
btnValue.packedFGColour = currentValue ? GuiUtils.getColorCode('a', true) : GuiUtils.getColorCode('c', true);
|
||||
}
|
||||
}
|
||||
|
||||
// Everything from here down is the same as BooleanEntry
|
||||
|
||||
@Override
|
||||
public void valueButtonPressed(int slotIndex){
|
||||
if(enabled()) currentValue = !currentValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefault(){
|
||||
return currentValue == Boolean.valueOf(configElement.getDefault().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToDefault(){
|
||||
if(enabled()){
|
||||
currentValue = Boolean.valueOf(configElement.getDefault().toString());
|
||||
updateValueButtonText();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged(){
|
||||
return currentValue != beforeValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undoChanges(){
|
||||
if(enabled()){
|
||||
currentValue = beforeValue;
|
||||
updateValueButtonText();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveConfigElement(){
|
||||
if(enabled() && isChanged()){
|
||||
configElement.set(currentValue);
|
||||
return configElement.requiresMcRestart();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getCurrentValue(){
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean[] getCurrentValues(){
|
||||
return new Boolean[]{getCurrentValue()};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package electroblob.wizardry.client.gui.config;
|
||||
|
||||
import electroblob.wizardry.client.gui.GuiSpellDisplay;
|
||||
import net.minecraftforge.client.gui.ForgeGuiFactory.ForgeConfigGui.ModIDEntry;
|
||||
import net.minecraftforge.fml.client.config.GuiConfig;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries;
|
||||
import net.minecraftforge.fml.client.config.GuiConfigEntries.SelectValueEntry;
|
||||
import net.minecraftforge.fml.client.config.IConfigElement;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Custom config GUI for spell HUD skin selection; displays a list of all the loaded skins and a preview of the currently
|
||||
* selected skin. based off of {@link ModIDEntry} from Forge.
|
||||
*/
|
||||
public class SpellHUDSkinChooserEntry extends SelectValueEntry {
|
||||
|
||||
public SpellHUDSkinChooserEntry(GuiConfig owningScreen, GuiConfigEntries owningEntryList, IConfigElement prop){
|
||||
super(owningScreen, owningEntryList, prop, getSelectableValues());
|
||||
if(this.selectableValues.size() == 0) this.btnValue.enabled = false;
|
||||
}
|
||||
|
||||
private static Map<Object, String> getSelectableValues(){
|
||||
return GuiSpellDisplay.getSkins().entrySet().stream().collect(Collectors.toMap(Entry::getKey,
|
||||
e -> e.getValue().getName()));
|
||||
}
|
||||
|
||||
@Override // Copied from superclass to use custom child screen GUI class
|
||||
public void valueButtonPressed(int slotIndex){
|
||||
mc.displayGuiScreen(new GuiSelectHUDSkin(this.owningScreen, configElement, slotIndex, selectableValues, currentValue, enabled()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,7 @@ class Contents {
|
||||
|
||||
// Final fields are mandatory, the rest are optional
|
||||
final String id;
|
||||
final Section section;
|
||||
private boolean hyperlinks = true;
|
||||
private boolean pageNumbers = true;
|
||||
private String separator = ".";
|
||||
@@ -37,10 +38,14 @@ class Contents {
|
||||
|
||||
private final List<Section> entries;
|
||||
|
||||
private Contents(String id){
|
||||
private List<Section> visibleEntries;
|
||||
|
||||
private Contents(String id, Section section){
|
||||
this.id = id;
|
||||
this.section = section;
|
||||
this.entries = new ArrayList<>();
|
||||
this.buttons = new ArrayList<>();
|
||||
this.visibleEntries = new ArrayList<>();
|
||||
}
|
||||
|
||||
/** Returns an unmodifiable, flattened collection of all the buttons in this contents. */
|
||||
@@ -83,26 +88,29 @@ class Contents {
|
||||
|
||||
for(int page : visiblePages){
|
||||
|
||||
if(page >= 0 && page < entries.size() / maxLineNumber + 1){
|
||||
if(page >= 0 && page < visibleEntries.size() / maxLineNumber + 1){
|
||||
|
||||
int x = left + (GuiWizardHandbook.isRightPage(startPage + page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X);
|
||||
int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT;
|
||||
|
||||
for(Section entry : this.entries){
|
||||
for(Section entry : this.visibleEntries){
|
||||
|
||||
int nameWidth = font.getStringWidth(entry.title);
|
||||
if(entry.isUnlocked()){
|
||||
|
||||
String dotsAndNumber = " " + entry.startPage;
|
||||
int nameWidth = font.getStringWidth(entry.title);
|
||||
|
||||
while(font.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){
|
||||
dotsAndNumber = separator + dotsAndNumber;
|
||||
String dotsAndNumber = " " + entry.startPage;
|
||||
|
||||
while(font.getStringWidth(dotsAndNumber) < GuiWizardHandbook.PAGE_WIDTH - nameWidth - 2){
|
||||
dotsAndNumber = separator + dotsAndNumber;
|
||||
}
|
||||
|
||||
font.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - font.getStringWidth(dotsAndNumber), y, DrawingUtils.BLACK, false);
|
||||
|
||||
if(!hyperlinks) font.drawString(entry.title, x, y, DrawingUtils.BLACK, false);
|
||||
|
||||
y += font.FONT_HEIGHT;
|
||||
}
|
||||
|
||||
font.drawString(dotsAndNumber, x + GuiWizardHandbook.PAGE_WIDTH - font.getStringWidth(dotsAndNumber), y, DrawingUtils.BLACK, false);
|
||||
|
||||
if(!hyperlinks) font.drawString(entry.title, x, y, DrawingUtils.BLACK, false);
|
||||
|
||||
y += font.FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,6 +132,10 @@ class Contents {
|
||||
|
||||
this.buttons.clear();
|
||||
|
||||
this.visibleEntries = new ArrayList<>(entries); // Need to copy the collection first!
|
||||
|
||||
this.visibleEntries.removeIf(s -> !s.isUnlocked());
|
||||
|
||||
if(hyperlinks){
|
||||
|
||||
// FONT_HEIGHT may change between fonts, so this is calculated here. With the default font it's 14.
|
||||
@@ -134,12 +146,12 @@ class Contents {
|
||||
|
||||
List<GuiButton> list = new ArrayList<>(maxLineNumber);
|
||||
|
||||
for(Section entry : this.entries){
|
||||
for(Section entry : this.visibleEntries){
|
||||
|
||||
int x = GuiWizardHandbook.isRightPage(startPage) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X;
|
||||
int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT;
|
||||
|
||||
list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, ""));
|
||||
list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "", maxLineNumber-startLine, GuiWizardHandbook.isRightPage(startPage)));
|
||||
|
||||
startLine++;
|
||||
|
||||
@@ -156,21 +168,22 @@ class Contents {
|
||||
|
||||
// Returning this is kind of trivial at the moment but if we ever wanted to add a header or something,
|
||||
// it would be more useful.
|
||||
return entries.size();
|
||||
return visibleEntries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given JSON object and constructs a new {@code Contents} from it, setting all the relevant fields
|
||||
* and references.
|
||||
*
|
||||
* @param parent The parent section for this contents.
|
||||
* @param json A JSON object representing the contents to be constructed. This must contain at least an "id"
|
||||
* string.
|
||||
* @return The resulting {@code Contents} object.
|
||||
* @throws JsonSyntaxException if at any point the JSON object is found to be invalid.
|
||||
*/
|
||||
static Contents fromJson(JsonObject json){
|
||||
static Contents fromJson(Section parent, JsonObject json){
|
||||
|
||||
Contents contents = new Contents(JsonUtils.getString(json, "id"));
|
||||
Contents contents = new Contents(JsonUtils.getString(json, "id"), parent);
|
||||
|
||||
contents.hyperlinks = JsonUtils.getBoolean(json, "hyperlinks", true);
|
||||
contents.pageNumbers = JsonUtils.getBoolean(json, "page_numbers", true);
|
||||
|
||||
@@ -1,43 +1,38 @@
|
||||
package electroblob.wizardry.client.gui.handbook;
|
||||
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.spell.Mine;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.recipebook.GuiRecipeBook;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.renderer.RenderItem;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.crafting.CraftingManager;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.stats.RecipeBook;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
class CraftingRecipe {
|
||||
|
||||
static final int WIDTH = 111, HEIGHT = 56;
|
||||
static final int BORDER = 7;
|
||||
static final int TEXTURE_INSET_X = 40, TEXTURE_INSET_Y = 190;
|
||||
static final int WIDTH = 121, HEIGHT = 66;
|
||||
|
||||
// Final fields are mandatory, the rest are optional
|
||||
private final ResourceLocation location;
|
||||
private final ResourceLocation[] locations;
|
||||
// Derived fields, not specifically defined in JSON
|
||||
private IRecipe recipe;
|
||||
private List<IRecipe> recipes;
|
||||
private final Set<int[]> instances = new HashSet<>();
|
||||
|
||||
private CraftingRecipe(ResourceLocation location){
|
||||
this.location = location;
|
||||
private CraftingRecipe(ResourceLocation[] locations){
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,9 +55,14 @@ class CraftingRecipe {
|
||||
* the recipes aren't necessarily loaded at that point. */
|
||||
void load(){
|
||||
|
||||
this.recipe = CraftingManager.getRecipe(location);
|
||||
recipes = new ArrayList<>(locations.length);
|
||||
|
||||
if(recipe == null) throw new JsonSyntaxException("No such recipe: " + location);
|
||||
for(ResourceLocation location : locations){
|
||||
|
||||
IRecipe recipe = CraftingManager.getRecipe(location);
|
||||
if(recipe == null) throw new JsonSyntaxException("No such recipe: " + location);
|
||||
recipes.add(recipe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,9 +75,12 @@ class CraftingRecipe {
|
||||
* @param top The y coordinate of the top of the GUI.
|
||||
*/
|
||||
void draw(FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top){
|
||||
|
||||
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000;
|
||||
|
||||
for(int[] instance : instances){
|
||||
if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){
|
||||
renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], this.recipe);
|
||||
renderCraftingRecipe(font, itemRenderer, left + instance[1], top + instance[2], recipes.get(index % recipes.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,9 +95,12 @@ class CraftingRecipe {
|
||||
* @param top The y coordinate of the top of the GUI.
|
||||
*/
|
||||
void drawTooltips(GuiWizardHandbook gui, FontRenderer font, RenderItem itemRenderer, int doublePage, int left, int top, int mouseX, int mouseY){
|
||||
|
||||
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000;
|
||||
|
||||
for(int[] instance : instances){
|
||||
if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){
|
||||
renderCraftingTooltips(gui, itemRenderer, left + instance[1], top + instance[2], mouseX, mouseY, this.recipe);
|
||||
renderCraftingTooltips(gui, itemRenderer, left + instance[1], top + instance[2], mouseX, mouseY, recipes.get(index % recipes.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,15 +109,16 @@ class CraftingRecipe {
|
||||
* Parses the given JSON object and constructs a new {@code Image} from it, setting all the relevant fields
|
||||
* and references.
|
||||
*
|
||||
* @param json A JSON object representing the image to be constructed. This must contain at least a "location"
|
||||
* @param json A JSON object representing the image to be constructed. This must contain at least a "locations"
|
||||
* string.
|
||||
* @return The resulting {@code Image} object.
|
||||
* @throws JsonSyntaxException if at any point the JSON object is found to be invalid.
|
||||
*/
|
||||
static CraftingRecipe fromJson(JsonObject json){
|
||||
|
||||
ResourceLocation location = new ResourceLocation(JsonUtils.getString(json, "location"));
|
||||
return new CraftingRecipe(location);
|
||||
ResourceLocation[] locations = Streams.stream(JsonUtils.getJsonArray(json, "locations"))
|
||||
.map(je -> new ResourceLocation(je.getAsString())).toArray(ResourceLocation[]::new);
|
||||
return new CraftingRecipe(locations);
|
||||
}
|
||||
|
||||
static void populate(Map<String, CraftingRecipe> map, JsonObject json){
|
||||
@@ -135,17 +142,15 @@ class CraftingRecipe {
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture);
|
||||
|
||||
DrawingUtils.drawTexturedRect(x - 2, y - 2, 60, 190, WIDTH, HEIGHT, 512, 256);
|
||||
DrawingUtils.drawTexturedRect(x, y, TEXTURE_INSET_X, TEXTURE_INSET_Y, WIDTH, HEIGHT, GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT);
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.enableRescaleNormal();
|
||||
GlStateManager.enableColorMaterial();
|
||||
GlStateManager.enableLighting();
|
||||
itemRenderer.zLevel = 100.0F;
|
||||
|
||||
// TODO: There may be a better way of doing this
|
||||
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000;
|
||||
|
||||
int i = 0;
|
||||
@@ -155,8 +160,8 @@ class CraftingRecipe {
|
||||
if(ingredient != Ingredient.EMPTY){
|
||||
ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length];
|
||||
if(!stack.isEmpty()){
|
||||
itemRenderer.renderItemAndEffectIntoGUI(stack, x + 18 * (i%3), y + 18 * (i/3));
|
||||
itemRenderer.renderItemOverlays(font, stack, x + 18 * (i%3), y + 18 * (i/3));
|
||||
itemRenderer.renderItemAndEffectIntoGUI(stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3));
|
||||
itemRenderer.renderItemOverlays(font, stack, x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,16 +169,15 @@ class CraftingRecipe {
|
||||
}
|
||||
|
||||
if(!result.isEmpty()){
|
||||
itemRenderer.renderItemAndEffectIntoGUI(result, x + 86, y + 18);
|
||||
itemRenderer.renderItemOverlays(font, result, x + 86, y + 18);
|
||||
itemRenderer.renderItemAndEffectIntoGUI(result, x + BORDER + 86, y + BORDER + 18);
|
||||
itemRenderer.renderItemOverlays(font, result, x + BORDER + 86, y + BORDER + 18);
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.disableColorMaterial();
|
||||
itemRenderer.zLevel = 0.0F;
|
||||
//RenderHelper.enableStandardItemLighting();
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
}
|
||||
|
||||
@@ -187,9 +191,7 @@ class CraftingRecipe {
|
||||
GlStateManager.enableRescaleNormal();
|
||||
GlStateManager.enableColorMaterial();
|
||||
itemRenderer.zLevel = 0.0F;
|
||||
GlStateManager.disableLighting();
|
||||
|
||||
// TODO: There may be a better way of doing this
|
||||
int index = (int)(Minecraft.getSystemTime() % Integer.MAX_VALUE)/2000;
|
||||
|
||||
int i = 0;
|
||||
@@ -198,7 +200,7 @@ class CraftingRecipe {
|
||||
|
||||
if(ingredient != Ingredient.EMPTY){
|
||||
ItemStack stack = ingredient.getMatchingStacks()[index % ingredient.getMatchingStacks().length];
|
||||
if(!stack.isEmpty() && isPointInRegion(x + 18 * (i%3), y + 18 * (i/3), 16, 16, mouseX, mouseY)){
|
||||
if(!stack.isEmpty() && isPointInRegion(x + BORDER + 18 * (i%3), y + BORDER + 18 * (i/3), 16, 16, mouseX, mouseY)){
|
||||
gui.renderToolTip(stack, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
@@ -206,15 +208,14 @@ class CraftingRecipe {
|
||||
i++;
|
||||
}
|
||||
|
||||
if(!result.isEmpty() && isPointInRegion(x + 86, y + 18, 16, 16, mouseX, mouseY)){
|
||||
if(!result.isEmpty() && isPointInRegion(x + BORDER + 86, y + BORDER + 18, 16, 16, mouseX, mouseY)){
|
||||
gui.renderToolTip(result, mouseX, mouseY);
|
||||
}
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.disableColorMaterial();
|
||||
RenderHelper.enableStandardItemLighting();
|
||||
RenderHelper.disableStandardItemLighting();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package electroblob.wizardry.client.gui.handbook;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.audio.SoundHandler;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
@@ -19,10 +21,14 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
|
||||
public static final String URL_REGEX = "^((https?|ftp)://|(www|ftp)\\.)?[a-z0-9-]+(\\.[a-z0-9-]+)+([/?].*)?$";
|
||||
|
||||
/** Pulse period of links to new sections, in milliseconds. */
|
||||
private static final float PULSATION_PERIOD = 1500;
|
||||
|
||||
final int indent;
|
||||
final List<String> lines;
|
||||
final int linesLeft;
|
||||
|
||||
GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix){
|
||||
GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix, int linesLeft, boolean rightPage){
|
||||
|
||||
super(id, x, y, font.getStringWidth(text), font.FONT_HEIGHT, text);
|
||||
|
||||
@@ -36,6 +42,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
}
|
||||
|
||||
this.indent = indent; // Assigned here in case it was corrected above
|
||||
this.linesLeft = linesLeft;
|
||||
|
||||
String line1 = font.listFormattedStringToWidth(linkWithSuffix, GuiWizardHandbook.PAGE_WIDTH - indent).get(0);
|
||||
// Without trim(), there will be at least 1 leading space due to the custom wrapping
|
||||
@@ -59,6 +66,11 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any lines that overflowed onto the next double-page
|
||||
if(rightPage){
|
||||
while(lines.size() > linesLeft) lines.remove(lines.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHovered(net.minecraft.client.gui.FontRenderer font, int mouseX, int mouseY){
|
||||
@@ -72,6 +84,11 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
|
||||
int t = y + font.FONT_HEIGHT * i;
|
||||
|
||||
if(i > linesLeft){
|
||||
l = l + GuiWizardHandbook.GUI_WIDTH - 2 * GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH;
|
||||
t -= GuiWizardHandbook.PAGE_HEIGHT - (GuiWizardHandbook.PAGE_HEIGHT % font.FONT_HEIGHT);
|
||||
}
|
||||
|
||||
if(mouseX >= l && mouseY >= t && mouseX < l + font.getStringWidth(line) && mouseY < t + font.FONT_HEIGHT){
|
||||
return true;
|
||||
}
|
||||
@@ -93,7 +110,6 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
if(this.visible){
|
||||
|
||||
this.hovered = isHovered(minecraft.fontRenderer, mouseX, mouseY);
|
||||
int colour = hovered ? GuiWizardHandbook.colours.get("highlight") : GuiWizardHandbook.colours.get("hyperlink");
|
||||
|
||||
int i = 0;
|
||||
|
||||
@@ -104,13 +120,22 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
|
||||
int t = y + minecraft.fontRenderer.FONT_HEIGHT * i;
|
||||
|
||||
minecraft.fontRenderer.drawString(line, l, t, colour);
|
||||
if(i > linesLeft){
|
||||
l = l + GuiWizardHandbook.GUI_WIDTH - 2 * GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH;
|
||||
t -= GuiWizardHandbook.PAGE_HEIGHT - (GuiWizardHandbook.PAGE_HEIGHT % minecraft.fontRenderer.FONT_HEIGHT);
|
||||
}
|
||||
|
||||
minecraft.fontRenderer.drawString(line, l, t, getColour());
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int getColour(){
|
||||
return hovered ? GuiWizardHandbook.colours.get("highlight") : GuiWizardHandbook.colours.get("hyperlink");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new hyperlink button from the given arguments, automatically differentiating between URLs and sections.
|
||||
* @param x The x position of the button
|
||||
@@ -124,7 +149,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
* @throws IllegalArgumentException if the given argument array is empty or contains more than 2 arguments
|
||||
* @throws JsonSyntaxException if the specified link target is not a URL or a valid section ID
|
||||
*/
|
||||
public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List<String> upToLink, String[] arguments, String suffix){
|
||||
public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List<String> upToLink, String[] arguments, String suffix, int linesLeft, boolean rightPage){
|
||||
|
||||
if(arguments.length == 0 || arguments.length > 2) throw new IllegalArgumentException("Incorrect array length!");
|
||||
|
||||
@@ -133,7 +158,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
if(arguments[0].matches(URL_REGEX)){
|
||||
|
||||
button = new GuiButtonHyperlink.External(0, x, y, font, arguments[arguments.length - 1], arguments[0],
|
||||
font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix);
|
||||
font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage);
|
||||
|
||||
}else{
|
||||
|
||||
@@ -142,7 +167,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
if(target == null) throw new JsonSyntaxException("Hyperlink points to nonexistent section id " + arguments[0]);
|
||||
|
||||
button = new GuiButtonHyperlink.Internal(0, x, y, font, arguments[arguments.length - 1],
|
||||
target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix);
|
||||
target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage);
|
||||
}
|
||||
|
||||
return button;
|
||||
@@ -152,26 +177,49 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
||||
|
||||
final Section target;
|
||||
|
||||
Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix){
|
||||
super(id, x, y, font, text, indent, suffix);
|
||||
Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix, int linesLeft, boolean rightPage){
|
||||
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY){
|
||||
if(!target.isUnlocked()) return false;
|
||||
return super.mousePressed(minecraft, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playPressSound(SoundHandler soundHandler){
|
||||
soundHandler.playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_PAGE_TURN, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getColour(){
|
||||
|
||||
if(!target.isUnlocked()) return GuiWizardHandbook.colours.get("text");
|
||||
|
||||
if(!hovered && target.isNew() && !Minecraft.getMinecraft().player.isCreative()){
|
||||
|
||||
int c = GuiWizardHandbook.colours.get("new_section");
|
||||
int d = GuiWizardHandbook.colours.get("hyperlink");
|
||||
float f = (MathHelper.sin((Minecraft.getSystemTime() % PULSATION_PERIOD) / PULSATION_PERIOD * 2 * (float)Math.PI) + 1) / 2f;
|
||||
|
||||
return DrawingUtils.mix(c, d, f);
|
||||
}
|
||||
|
||||
return super.getColour();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class External extends GuiButtonHyperlink {
|
||||
|
||||
final ITextComponent link;
|
||||
|
||||
External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix){
|
||||
super(id, x, y, font, text, indent, suffix);
|
||||
External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix, int linesLeft, boolean rightPage){
|
||||
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage);
|
||||
this.link = new TextComponentString(text);
|
||||
link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url));
|
||||
link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)).setColor(TextFormatting.DARK_BLUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,10 +9,8 @@ import net.minecraft.client.audio.SoundHandler;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
//@SideOnly(Side.CLIENT)
|
||||
class GuiButtonTurnPage extends GuiButton {
|
||||
|
||||
static final int WIDTH = 20;
|
||||
|
||||
@@ -3,6 +3,7 @@ package electroblob.wizardry.client.gui.handbook;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.ClientProxy;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
@@ -11,34 +12,28 @@ import electroblob.wizardry.client.gui.handbook.GuiButtonTurnPage.Type;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.packet.PacketRequestAdvancementSync;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
import net.minecraft.client.audio.SoundHandler;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.multiplayer.ClientAdvancementManager;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.event.entity.player.AdvancementEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.ReflectionHelper;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of
|
||||
@@ -54,7 +49,6 @@ import java.util.List;
|
||||
* @see Image
|
||||
* @see CraftingRecipe
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json");
|
||||
@@ -71,6 +65,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
static final String IMAGE_TAG = "image";
|
||||
static final String RECIPE_TAG = "recipe";
|
||||
static final String RULER_TAG = "ruler";
|
||||
|
||||
static final Map<String, String> FORMAT_TAGS = new HashMap<>();
|
||||
|
||||
@@ -79,6 +74,8 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
/** The dimensions of the rendered GUI area. */
|
||||
static final int GUI_WIDTH = 288, GUI_HEIGHT = 180;
|
||||
/** The dimensions of the GUI texture itself. */
|
||||
static final int TEXTURE_WIDTH = 512, TEXTURE_HEIGHT = 256;
|
||||
/** The dimensions of the area of a single page in which text can be drawn. */
|
||||
static final int PAGE_WIDTH = 120, PAGE_HEIGHT = 140;
|
||||
/** The distance of the text from the top outside corner of each page. */
|
||||
@@ -107,12 +104,12 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
* The <b>double-page</b> number where the bookmark is currently set, <b>relative to the section stored in
|
||||
* {@link GuiWizardHandbook#bookmarkSection}</b>. Static because it persists when the book is closed.
|
||||
*/
|
||||
private static int bookmarkPage = 1;
|
||||
private static int bookmarkPage = 0;
|
||||
/**
|
||||
* A reference to the section in which the bookmark is currently set. Static because it persists when the book is
|
||||
* closed. Storing a section means the bookmark doesn't change location when new sections are unlocked.
|
||||
* The key corresponding to the section in which the bookmark is currently set. Static because it persists when the
|
||||
* book is closed. Storing a section means the bookmark doesn't change location when new sections are unlocked.
|
||||
*/
|
||||
private static Section bookmarkSection;
|
||||
private static String bookmarkSection;
|
||||
|
||||
// Buttons
|
||||
private GuiButton bookmark, next, previous, nextSection, previousSection, menu;
|
||||
@@ -164,19 +161,6 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
*/
|
||||
static final Map<String, CraftingRecipe> recipes = new HashMap<>();
|
||||
|
||||
static String rulerText = "--------------------"; // Assigned here as a fallback
|
||||
|
||||
private static final List<Pair<ItemStack, NonNullList<NonNullList<ItemStack>>>> RECIPES = new ArrayList<>();
|
||||
|
||||
// Reflection
|
||||
|
||||
static final Field ADVANCEMENT_TO_PROGRESS;
|
||||
|
||||
static {
|
||||
// TODO: Obf field name
|
||||
ADVANCEMENT_TO_PROGRESS = ReflectionHelper.findField(ClientAdvancementManager.class, "advancementToProgress");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a format tag to the handbook. All occurrences of the given tag string preceded by a # will be replaced with
|
||||
* the result of the given value string on GUI load. The value string, therefore, can be anything that should be
|
||||
@@ -193,9 +177,9 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
addFormatTag("next_spell_key", ClientProxy.NEXT_SPELL.getDisplayName());
|
||||
addFormatTag("previous_spell_key", ClientProxy.PREVIOUS_SPELL.getDisplayName());
|
||||
addFormatTag("mana_per_crystal_minus_30", "" + (Constants.MANA_PER_CRYSTAL - 30));
|
||||
addFormatTag("example_charging_loss", "" + (Constants.MANA_PER_CRYSTAL - 30));
|
||||
addFormatTag("mana_per_crystal", "" + Constants.MANA_PER_CRYSTAL);
|
||||
addFormatTag("novice_max_charge", "" + Tier.BASIC.maxCharge);
|
||||
addFormatTag("novice_max_charge", "" + Tier.NOVICE.maxCharge);
|
||||
addFormatTag("apprentice_max_charge", "" + Tier.APPRENTICE.maxCharge);
|
||||
addFormatTag("advanced_max_charge", "" + Tier.ADVANCED.maxCharge);
|
||||
addFormatTag("master_max_charge", "" + Tier.MASTER.maxCharge);
|
||||
@@ -264,12 +248,14 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
|
||||
// Main background
|
||||
DrawingUtils.drawTexturedRect(left, top, 0, 0, GUI_WIDTH, GUI_HEIGHT, 512, 256);
|
||||
DrawingUtils.drawTexturedRect(left, top, 0, 0, GUI_WIDTH, GUI_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
// First page background
|
||||
if(currentPage == 0){
|
||||
DrawingUtils.drawTexturedRect(left, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, 512, 256);
|
||||
DrawingUtils.drawTexturedRect(left, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
previous.visible = false;
|
||||
previousSection.visible = false; // Not worth testing if we're in the first section every frame
|
||||
menu.visible = false;
|
||||
@@ -281,7 +267,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
// Last page background
|
||||
if(currentPage == singleToDoublePage(pageCount)){
|
||||
DrawingUtils.drawTexturedFlippedRect(left + GUI_WIDTH / 2, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, 512, 256, true, false);
|
||||
DrawingUtils.drawTexturedFlippedRect(left + GUI_WIDTH / 2, top, 368, 0, GUI_WIDTH / 2, GUI_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT, true, false);
|
||||
next.visible = false;
|
||||
nextSection.visible = false;
|
||||
}else{
|
||||
@@ -302,9 +288,10 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
}
|
||||
|
||||
// Main content
|
||||
contentsList.values().forEach(c -> { if(c.section.isUnlocked()) c.draw(fontRenderer, currentPage, left, top); } );
|
||||
sections.values().forEach(s -> { if(s.isUnlocked()) s.draw(fontRenderer, currentPage, left, top); } );
|
||||
// These only get populated if the sections are unlocked so no checks are necessary
|
||||
images.values().forEach(i -> i.draw(fontRenderer, currentPage, left, top));
|
||||
contentsList.values().forEach(c -> c.draw(fontRenderer, currentPage, left, top));
|
||||
sections.values().forEach(s -> s.draw(fontRenderer, currentPage, left, top));
|
||||
recipes.values().forEach(r -> r.draw(fontRenderer, itemRender, currentPage, left, top));
|
||||
|
||||
// Buttons
|
||||
@@ -314,14 +301,15 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
|
||||
|
||||
if(currentPage == singleToDoublePage(bookmarkSection.startPage) + bookmarkPage){
|
||||
if(currentPage == singleToDoublePage(sections.get(bookmarkSection).startPage) + bookmarkPage){
|
||||
// If the current page is the bookmarked page, the (invisible) bookmark button is disabled
|
||||
bookmark.visible = false;
|
||||
DrawingUtils.drawTexturedRect(left + 138, top, 299, 0, 11, 191, 512, 256);
|
||||
DrawingUtils.drawTexturedRect(left + 138, top, 299, 0, 11, 191, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
}else{
|
||||
bookmark.visible = true;
|
||||
bookmark.x = left + (currentPage > singleToDoublePage(bookmarkSection.startPage) + bookmarkPage ? 130 : 147);
|
||||
bookmark.x = left + (currentPage > singleToDoublePage(sections.get(bookmarkSection).startPage) + bookmarkPage ? 130 : 147);
|
||||
DrawingUtils.drawTexturedRect(bookmark.x, top,
|
||||
bookmark.isMouseOver() ? 310 : 288, 0, 11, 191, 512, 256);
|
||||
bookmark.isMouseOver() ? 310 : 288, 0, 11, 191, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
}
|
||||
|
||||
// Recipe tooltips
|
||||
@@ -426,8 +414,6 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
||||
JsonObject json = je.getAsJsonObject();
|
||||
|
||||
rulerText = JsonUtils.getString(json, "ruler_text");
|
||||
|
||||
JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(),
|
||||
Color.decode(e.getValue().getAsString()).getRGB()));
|
||||
|
||||
@@ -443,10 +429,12 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempts to find a suitable place to put the bookmark to start with
|
||||
bookmarkSection = sections.get("introduction");
|
||||
if(bookmarkSection == null) bookmarkSection = sectionList.get(0);
|
||||
bookmarkSection = JsonUtils.getString(json, "bookmark_start_section");
|
||||
if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined");
|
||||
}
|
||||
|
||||
// The first resource load on startup is done before the packet handler is loaded
|
||||
if(WizardryPacketHandler.net != null) WizardryPacketHandler.net.sendToServer(new PacketRequestAdvancementSync.Message());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,6 +448,8 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
*/
|
||||
private static IResource getHandbookResource(IResourceManager manager){
|
||||
|
||||
// TODO: Implement resource pack stacking to allow addon mods and texture packs to add/overwrite content
|
||||
|
||||
IResource handbookFile = null;
|
||||
|
||||
try{
|
||||
@@ -507,12 +497,15 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
if(currentSection != null){
|
||||
|
||||
int index = sectionList.indexOf(currentSection);
|
||||
List<Section> visibleSections = new ArrayList<>(sectionList);
|
||||
visibleSections.removeIf(s -> !s.isUnlocked());
|
||||
|
||||
if(button == nextSection && index + 1 < sections.size()){
|
||||
currentPage = singleToDoublePage(sectionList.get(index + 1).startPage);
|
||||
int index = visibleSections.indexOf(currentSection);
|
||||
|
||||
if(button == nextSection && index + 1 < visibleSections.size()){
|
||||
currentPage = singleToDoublePage(visibleSections.get(index + 1).startPage);
|
||||
}else if(index > 0){
|
||||
currentPage = singleToDoublePage(sectionList.get(index - 1).startPage);
|
||||
currentPage = singleToDoublePage(visibleSections.get(index - 1).startPage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +513,7 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
currentPage = singleToDoublePage(sections.get("main_contents").startPage);
|
||||
|
||||
}else if(button == bookmark && bookmarkSection != null){
|
||||
currentPage = singleToDoublePage(bookmarkSection.startPage) + bookmarkPage;
|
||||
currentPage = singleToDoublePage(sections.get(bookmarkSection).startPage) + bookmarkPage;
|
||||
|
||||
}else{
|
||||
if(button instanceof GuiButtonHyperlink.Internal){
|
||||
@@ -540,12 +533,12 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
this.selectedButton = bookmark;
|
||||
|
||||
for(Section section : sections.values()){
|
||||
for(String key : sections.keySet()){
|
||||
// The bookmark is assumed to bookmark the left-hand page
|
||||
if(section.containsPage(doubleToSinglePage(bookmarkPage, false))) bookmarkSection = section;
|
||||
if(sections.get(key).containsPage(doubleToSinglePage(currentPage, false))) bookmarkSection = key;
|
||||
}
|
||||
|
||||
bookmarkPage = currentPage - singleToDoublePage(bookmarkSection.startPage);
|
||||
bookmarkPage = currentPage - singleToDoublePage(sections.get(bookmarkSection).startPage);
|
||||
}
|
||||
}else{
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
@@ -558,9 +551,14 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
super.renderToolTip(stack, x, y);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onAdvancementEvent(AdvancementEvent event){
|
||||
sections.values().forEach(s -> s.onAdvancement(event.getEntityPlayer(), event.getAdvancement()));
|
||||
@Override
|
||||
public boolean doesGuiPauseGame(){
|
||||
return Wizardry.settings.booksPauseGame;
|
||||
}
|
||||
|
||||
|
||||
public static void updateUnlockStatus(boolean showToasts, ResourceLocation... completedAdvancements){
|
||||
sections.values().forEach(s -> s.updateUnlockStatus(showToasts, completedAdvancements));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package electroblob.wizardry.client.gui.handbook;
|
||||
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import net.minecraft.client.gui.toasts.GuiToast;
|
||||
import net.minecraft.client.gui.toasts.IToast;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderHelper;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
public class HandbookToast implements IToast {
|
||||
|
||||
private final Section section;
|
||||
|
||||
public HandbookToast(Section section){
|
||||
this.section = section;
|
||||
}
|
||||
|
||||
public IToast.Visibility draw(GuiToast toastGui, long delta){
|
||||
|
||||
toastGui.getMinecraft().getTextureManager().bindTexture(TEXTURE_TOASTS);
|
||||
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F);
|
||||
toastGui.drawTexturedModalRect(0, 0, 0, 32, 160, 32);
|
||||
|
||||
boolean firstPart = delta < 1500L;
|
||||
|
||||
int a = firstPart ? MathHelper.floor(MathHelper.clamp((float)(1500L - delta) / 300.0F, 0.0F, 1.0F) * 255.0F) << 24 | 67108864
|
||||
: MathHelper.floor(MathHelper.clamp((float)(delta - 1500L) / 300.0F, 0.0F, 1.0F) * 252.0F) << 24 | 67108864;
|
||||
|
||||
String s = firstPart ? I18n.format("handbook.toast.title") : section.title;
|
||||
|
||||
int c = firstPart ? -11534256 : -16777216;
|
||||
|
||||
List<String> list = toastGui.getMinecraft().fontRenderer.listFormattedStringToWidth(s, 125);
|
||||
|
||||
int h = 16 - list.size() * toastGui.getMinecraft().fontRenderer.FONT_HEIGHT / 2;
|
||||
|
||||
for(String line : list){
|
||||
toastGui.getMinecraft().fontRenderer.drawString(line, 30, h, c | a);
|
||||
h += toastGui.getMinecraft().fontRenderer.FONT_HEIGHT;
|
||||
}
|
||||
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
toastGui.getMinecraft().getRenderItem().renderItemAndEffectIntoGUI(null, new ItemStack(WizardryItems.wizard_handbook), 8, 8);
|
||||
|
||||
return delta >= 5000L ? IToast.Visibility.HIDE : IToast.Visibility.SHOW;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@@ -22,11 +23,15 @@ class Image {
|
||||
private int textureWidth, textureHeight;
|
||||
private int u = 0, v = 0;
|
||||
private String caption = "";
|
||||
private boolean border = true;
|
||||
// Derived fields, not specifically defined in JSON
|
||||
private final Set<int[]> instances = new HashSet<>();
|
||||
|
||||
private static final int CAPTION_OFFSET = 4;
|
||||
|
||||
private static final int TEXTURE_INSET_X = 180;
|
||||
private static final int BORDER = 1;
|
||||
|
||||
private Image(ResourceLocation location, int width, int height){
|
||||
this.location = location;
|
||||
this.width = width;
|
||||
@@ -68,6 +73,7 @@ class Image {
|
||||
* @param top The y coordinate of the top of the GUI.
|
||||
*/
|
||||
void draw(FontRenderer font, int doublePage, int left, int top){
|
||||
// Images
|
||||
for(int[] instance : instances){
|
||||
if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(location);
|
||||
@@ -77,6 +83,29 @@ class Image {
|
||||
top + instance[2] + height + CAPTION_OFFSET, GuiWizardHandbook.colours.get("caption"));
|
||||
}
|
||||
}
|
||||
|
||||
if(border){
|
||||
// Borders - do this after all the images are drawn so we only have to bind the handbook texture again once
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture);
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
for(int[] instance : instances){
|
||||
if(GuiWizardHandbook.singleToDoublePage(instance[0]) == doublePage){
|
||||
// Math.ceil accounts for odd-numbered image dimensions
|
||||
DrawingUtils.drawTexturedFlippedRect(left + instance[1] - BORDER, top + instance[2] - BORDER,
|
||||
TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, width / 2 + BORDER, height / 2 + BORDER,
|
||||
GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, false, false);
|
||||
DrawingUtils.drawTexturedFlippedRect(left + instance[1] + width / 2, top + instance[2] - BORDER,
|
||||
TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, MathHelper.ceil(width / 2f) + BORDER, height / 2 + BORDER,
|
||||
GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, true, false);
|
||||
DrawingUtils.drawTexturedFlippedRect(left + instance[1] - BORDER, top + instance[2] + height / 2,
|
||||
TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, width / 2 + BORDER, MathHelper.ceil(height / 2f) + BORDER,
|
||||
GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, false, true);
|
||||
DrawingUtils.drawTexturedFlippedRect(left + instance[1] + width / 2, top + instance[2] + height / 2,
|
||||
TEXTURE_INSET_X, GuiWizardHandbook.GUI_HEIGHT, MathHelper.ceil(width / 2f) + BORDER, MathHelper.ceil(height / 2f) + BORDER,
|
||||
GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,7 +127,7 @@ class Image {
|
||||
image.textureWidth = JsonUtils.getInt(json, "texture_width", image.width);
|
||||
image.textureHeight = JsonUtils.getInt(json, "texture_height", image.height);
|
||||
image.caption = JsonUtils.getString(json, "caption", "");
|
||||
|
||||
image.border = JsonUtils.getBoolean(json, "border", true);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,12 @@ import com.google.gson.JsonSyntaxException;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.advancements.AdvancementProgress;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
@@ -23,7 +22,7 @@ import java.util.*;
|
||||
* everything within the section itself, including JSON parsing, unlock triggers and drawing the actual rawText.
|
||||
* Sections may now also be nested and have other elements within them, such as images and a table of contents, a
|
||||
* behaviour which is also handled within this class.
|
||||
* <p>
|
||||
* <p></p>
|
||||
* The formatting of the book is now done 'dynamically' - that is, the exact positions and page numbers of
|
||||
* sections, images and so on are determined on GUI load and depend on which of the previous sections have been
|
||||
* unlocked, amongst other factors. This means that all of the unlocked sections must be formatted in order on GUI
|
||||
@@ -32,15 +31,15 @@ import java.util.*;
|
||||
* @author Electroblob
|
||||
* @since Wizardry 4.2
|
||||
*/
|
||||
// Because these are now generated on resource pack reload (not on handbook open, as before), this class must now
|
||||
// be static
|
||||
// Because these are now generated on resource pack reload (not on handbook open, as before), this class can no longer
|
||||
// be a non-static inner class
|
||||
class Section {
|
||||
|
||||
// Final fields are mandatory (none here though), the rest are optional
|
||||
String title;
|
||||
private String[] rawText;
|
||||
private Contents contents;
|
||||
private Advancement[] triggers;
|
||||
private ResourceLocation[] triggers;
|
||||
private Map<String, Section> subsections;
|
||||
private boolean centreX, centreY;
|
||||
|
||||
@@ -54,6 +53,9 @@ class Section {
|
||||
*/
|
||||
private final List<List<String>> pages;
|
||||
|
||||
private boolean unlocked = false;
|
||||
private boolean isNew = false;
|
||||
|
||||
private Section(){
|
||||
this.buttons = new ArrayList<>();
|
||||
this.pages = new ArrayList<>();
|
||||
@@ -65,10 +67,10 @@ class Section {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given page is within this section, false if not.
|
||||
* Returns true if the given page is within this section, false if not (or if the section is locked).
|
||||
*/
|
||||
boolean containsPage(int page){
|
||||
return startPage <= page && startPage + pages.size() > page;
|
||||
return this.isUnlocked() && startPage <= page && startPage + pages.size() > page;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,32 +79,24 @@ class Section {
|
||||
*/
|
||||
boolean isUnlocked(){
|
||||
|
||||
if(Minecraft.getMinecraft().player.isCreative()) return true;
|
||||
if(!Wizardry.settings.handbookProgression) return true; // Always unlocked if handbook progression is off
|
||||
if(triggers == null) return true; // If no triggers were defined, the section is unlocked from the start
|
||||
|
||||
// A section is automatically unlocked if one of its subsections is unlocked
|
||||
for(Section subsection : subsections.values()){
|
||||
if(subsection.isUnlocked()) return true;
|
||||
}
|
||||
|
||||
if(triggers == null) return true; // If no triggers were defined, the section is unlocked from the start
|
||||
return unlocked;
|
||||
}
|
||||
|
||||
for(Advancement trigger : triggers){
|
||||
|
||||
try{
|
||||
|
||||
// TESTME: Is this properly synced or do we need to do that as well?
|
||||
Map<Advancement, AdvancementProgress> advancements = (Map)GuiWizardHandbook.ADVANCEMENT_TO_PROGRESS.get(Minecraft.getMinecraft().player.connection.getAdvancementManager());
|
||||
|
||||
if(advancements.get(trigger).isDone()){
|
||||
return true;
|
||||
}
|
||||
|
||||
}catch(IllegalAccessException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
/**
|
||||
* Returns true if this section has been unlocked and not read yet. Also returns true if any subsections are new.
|
||||
*/
|
||||
boolean isNew(){
|
||||
if(!Wizardry.settings.handbookProgression) return false;
|
||||
return isNew || this.subsections.values().stream().anyMatch(Section::isNew);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,12 +137,19 @@ class Section {
|
||||
|
||||
for(String line : lines){
|
||||
|
||||
int lx = centreX ? x + GuiWizardHandbook.PAGE_WIDTH / 2 - font.getStringWidth(line) / 2 : x;
|
||||
|
||||
font.drawString(line, lx, y, DrawingUtils.BLACK, false);
|
||||
if(line.startsWith(GuiWizardHandbook.FORMAT_MARKER + GuiWizardHandbook.RULER_TAG)){
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(GuiWizardHandbook.texture);
|
||||
DrawingUtils.drawTexturedRect(x-1, y-1, 0, GuiWizardHandbook.GUI_HEIGHT, GuiWizardHandbook.PAGE_WIDTH + 2, 9, GuiWizardHandbook.TEXTURE_WIDTH, GuiWizardHandbook.TEXTURE_HEIGHT);
|
||||
}else{
|
||||
int lx = centreX ? x + GuiWizardHandbook.PAGE_WIDTH / 2 - font.getStringWidth(line) / 2 : x;
|
||||
font.drawString(line, lx, y, DrawingUtils.BLACK, false);
|
||||
}
|
||||
|
||||
y += font.FONT_HEIGHT;
|
||||
}
|
||||
|
||||
isNew = false; // Now a page has been drawn, the player must have seen it so it's not new any more
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,7 +181,7 @@ class Section {
|
||||
// Adds the header if present
|
||||
if(!this.title.isEmpty()){
|
||||
lines.add(this.title);
|
||||
lines.add(GuiWizardHandbook.rulerText);
|
||||
lines.add(GuiWizardHandbook.FORMAT_MARKER + GuiWizardHandbook.RULER_TAG);
|
||||
}
|
||||
|
||||
// Adds space for the contents if it exists
|
||||
@@ -212,7 +213,7 @@ class Section {
|
||||
+ StringUtils.abbreviate(raw, 50));
|
||||
|
||||
Image image = GuiWizardHandbook.images.get(arguments[1]);
|
||||
if(image == null) throw new JsonSyntaxException("Image with id " + arguments[1] + "is undefined");
|
||||
if(image == null) throw new JsonSyntaxException("Image with id " + arguments[1] + " is undefined");
|
||||
|
||||
// Starts a new page if the image will not fit on the current one
|
||||
if((lines.size() % maxLineNumber) * font.FONT_HEIGHT + image.getHeight(font) > GuiWizardHandbook.PAGE_HEIGHT){
|
||||
@@ -248,27 +249,35 @@ class Section {
|
||||
+ StringUtils.abbreviate(raw, 50));
|
||||
|
||||
CraftingRecipe recipe = GuiWizardHandbook.recipes.get(arguments[1]);
|
||||
if(recipe == null) throw new JsonSyntaxException("Recipe with id " + arguments[1] + "is undefined");
|
||||
if(recipe == null) throw new JsonSyntaxException("Recipe with id " + arguments[1] + " is undefined");
|
||||
|
||||
// Starts a new page if the recipe will not fit on the current one
|
||||
if((lines.size() % maxLineNumber) * font.FONT_HEIGHT + CraftingRecipe.HEIGHT > GuiWizardHandbook.PAGE_HEIGHT){
|
||||
// Remaining number of lines on the page
|
||||
lines.addAll(Collections.nCopies(maxLineNumber - (lines.size() % maxLineNumber), ""));
|
||||
// Remaining number of lines on the page, plus the first blank one on the new page
|
||||
lines.addAll(Collections.nCopies(maxLineNumber - (lines.size() % maxLineNumber), " "));
|
||||
}
|
||||
|
||||
int page = startPage + (lines.size() / maxLineNumber);
|
||||
|
||||
if(lines.size() % maxLineNumber == 0) lines.add(" ");
|
||||
int startLine = lines.size() % maxLineNumber - 1;
|
||||
|
||||
recipe.addInstance(page, GuiWizardHandbook.PAGE_WIDTH / 2 - CraftingRecipe.WIDTH / 2
|
||||
+ (GuiWizardHandbook.isRightPage(page) ? GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : GuiWizardHandbook.TEXT_INSET_X),
|
||||
GuiWizardHandbook.TEXT_INSET_Y + (lines.size() % maxLineNumber) * font.FONT_HEIGHT);
|
||||
GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT);
|
||||
|
||||
// Height of the recipe in lines, rounded up
|
||||
// Uses a single space instead of an empty string so that the page trimming doesn't remove them
|
||||
lines.addAll(Collections.nCopies(CraftingRecipe.HEIGHT / font.FONT_HEIGHT, " "));
|
||||
lines.addAll(Collections.nCopies(CraftingRecipe.HEIGHT / font.FONT_HEIGHT - 1, " "));
|
||||
// This time we're not adding an extra space because it's not really needed
|
||||
|
||||
}else{ // All other paragraphs
|
||||
|
||||
// Formatting
|
||||
for(Map.Entry<String, String> entry : GuiWizardHandbook.FORMAT_TAGS.entrySet()){
|
||||
paragraph = paragraph.replace(GuiWizardHandbook.FORMAT_MARKER + entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// Hyperlinks
|
||||
|
||||
int linkStart;
|
||||
@@ -284,15 +293,17 @@ class Section {
|
||||
|
||||
String linkRaw = paragraph.substring(linkStart, linkEnd + 1);
|
||||
String[] arguments = paragraph.substring(linkStart + 1, linkEnd).split("\\s", 2);
|
||||
String suffix = paragraph.substring(linkEnd).split("\\s", 2)[0];
|
||||
String suffix = paragraph.substring(linkEnd).split("\\s", 2)[0].substring(1); // substring(1) to remove the @
|
||||
|
||||
// The index of the single page currently being formatted, relative to the section
|
||||
int pageRelative = (lines.size() + upToLink.size() - 1) / maxLineNumber;
|
||||
// The overall index of the single page currently being formatted
|
||||
int page = startPage + pageRelative;
|
||||
// The line number on this page
|
||||
int lineNumber = (lines.size() + upToLink.size() - 1) % maxLineNumber;
|
||||
|
||||
int x = GuiWizardHandbook.isRightPage(page) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X;
|
||||
int y = top + GuiWizardHandbook.TEXT_INSET_Y + (((lines.size() + upToLink.size() - 1) % maxLineNumber)) * font.FONT_HEIGHT;
|
||||
int y = top + GuiWizardHandbook.TEXT_INSET_Y + lineNumber * font.FONT_HEIGHT;
|
||||
|
||||
// Adds any missing sub-lists
|
||||
while(this.buttons.size() <= pageRelative){
|
||||
@@ -300,18 +311,13 @@ class Section {
|
||||
}
|
||||
|
||||
// The button id only does what you use it for, so we're just not using it at all.
|
||||
this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix));
|
||||
this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix, maxLineNumber - lineNumber - 1, GuiWizardHandbook.isRightPage(page)));
|
||||
|
||||
// The link button should exactly overlay the display rawText in the main string
|
||||
// If the link has no display rawText specified, it displays the unformatted target string
|
||||
paragraph = paragraph.replace(linkRaw, arguments[arguments.length - 1]);
|
||||
}
|
||||
|
||||
// Formatting
|
||||
for(Map.Entry<String, String> entry : GuiWizardHandbook.FORMAT_TAGS.entrySet()){
|
||||
paragraph = paragraph.replace(GuiWizardHandbook.FORMAT_MARKER + entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
lines.addAll(font.listFormattedStringToWidth(paragraph, GuiWizardHandbook.PAGE_WIDTH));
|
||||
}
|
||||
|
||||
@@ -373,18 +379,22 @@ class Section {
|
||||
}
|
||||
|
||||
if(JsonUtils.hasField(json, "contents")){
|
||||
section.contents = Contents.fromJson(JsonUtils.getJsonObject(json, "contents"));
|
||||
section.contents = Contents.fromJson(section, JsonUtils.getJsonObject(json, "contents"));
|
||||
GuiWizardHandbook.contentsList.put(section.contents.id, section.contents);
|
||||
}
|
||||
|
||||
if(JsonUtils.hasField(json, "text")){
|
||||
// TESTME: Does this always preserve order?
|
||||
section.rawText = Streams.stream(JsonUtils.getJsonArray(json, "text"))
|
||||
.map(e -> JsonUtils.getString(e, "element of array rawText"))
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
// TODO: Triggers
|
||||
if(JsonUtils.hasField(json, "triggers")){
|
||||
section.triggers = Streams.stream(JsonUtils.getJsonArray(json, "triggers"))
|
||||
.map(e -> new ResourceLocation(JsonUtils.getString(e, "element of array triggers")))
|
||||
.toArray(ResourceLocation[]::new);
|
||||
// TODO: Can we validate this and throw a JSON exception if no such advancement exists?
|
||||
}
|
||||
|
||||
if(JsonUtils.hasField(json, "centre")){
|
||||
JsonObject centre = JsonUtils.getJsonObject(json,"centre");
|
||||
@@ -416,14 +426,26 @@ class Section {
|
||||
}
|
||||
}
|
||||
|
||||
public void onAdvancement(EntityPlayer player, Advancement advancement){
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
//System.out.println(title);
|
||||
if(triggers != null && Arrays.asList(triggers).contains(advancement) && player == minecraft.player){
|
||||
//minecraft.getToastGui().drawToast(IToast);
|
||||
/**
|
||||
* Called on login and advancement completion to update this section's unlock status and display toast
|
||||
* notifications if applicable.
|
||||
*/
|
||||
public void updateUnlockStatus(boolean showToasts, ResourceLocation... completedAdvancements){
|
||||
|
||||
// Debug
|
||||
//System.out.println(title);
|
||||
if(triggers == null) return;
|
||||
|
||||
List<ResourceLocation> completed = new ArrayList<>(Arrays.asList(completedAdvancements));
|
||||
completed.retainAll(Arrays.asList(triggers));
|
||||
|
||||
// Only shows the toast when the section was locked before and is now unlocked
|
||||
if(!this.unlocked && !completed.isEmpty() && showToasts && Wizardry.settings.handbookProgression){
|
||||
// Mmmmm toast...
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
minecraft.getToastGui().add(new HandbookToast(this));
|
||||
this.isNew = true;
|
||||
}
|
||||
|
||||
// Currently, this will not take subsections into account
|
||||
this.unlocked = !completed.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user