Add lecterns
This commit is contained in:
@@ -7,6 +7,7 @@ import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.item.ItemWizardHandbook;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -23,6 +24,7 @@ public class WizardryGuiHandler implements IGuiHandler {
|
||||
public static final int WIZARD_HANDBOOK = nextGuiId++;
|
||||
public static final int PORTABLE_CRAFTING = nextGuiId++;
|
||||
public static final int BOOKSHELF = nextGuiId++;
|
||||
public static final int LECTERN = nextGuiId++;
|
||||
|
||||
@Override
|
||||
public Object getServerGuiElement(int id, EntityPlayer player, World world, int x, int y, int z){
|
||||
@@ -87,6 +89,14 @@ public class WizardryGuiHandler implements IGuiHandler {
|
||||
(TileEntityBookshelf)tileEntity);
|
||||
}
|
||||
|
||||
}else if(id == LECTERN){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(new BlockPos(x, y, z));
|
||||
|
||||
if(tileEntity instanceof TileEntityLectern){
|
||||
return new electroblob.wizardry.client.gui.GuiLectern((TileEntityLectern)tileEntity);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.InventoryHelper;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
@@ -22,8 +23,11 @@ import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.property.IExtendedBlockState;
|
||||
import net.minecraftforge.common.property.Properties;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvider {
|
||||
|
||||
@@ -134,4 +138,37 @@ public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvid
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of nearby bookshelves' inventories, where 'bookshelves' are any tile entities with inventories
|
||||
* whose blocks are specified in the config file under the {@code bookshelfBlocks} option.
|
||||
* @param world The world to search in
|
||||
* @param centre The position to search around
|
||||
* @param exclude Any tile entities that should be excluded from the returned list
|
||||
* @return A list of nearby {@link IInventory} objects that count as valid bookshelves
|
||||
*/
|
||||
public static List<IInventory> findNearbyBookshelves(World world, BlockPos centre, TileEntity... exclude){
|
||||
|
||||
List<IInventory> bookshelves = new ArrayList<>();
|
||||
|
||||
int searchRadius = 4; // TODO: Config option for this
|
||||
|
||||
for(int x = -searchRadius; x <= searchRadius; x++){
|
||||
for(int y = -searchRadius; y <= searchRadius; y++){
|
||||
for(int z = -searchRadius; z <= searchRadius; z++){
|
||||
|
||||
BlockPos pos = centre.add(x, y, z);
|
||||
// TODO: Config option for allowed containers
|
||||
if(world.getBlockState(pos).getBlock() instanceof BlockBookshelf){
|
||||
TileEntity te = world.getTileEntity(pos);
|
||||
if(te instanceof IInventory && !ArrayUtils.contains(exclude, te)) bookshelves.add((IInventory)te);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bookshelves;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.WizardryGuiHandler;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import net.minecraft.block.BlockHorizontal;
|
||||
import net.minecraft.block.ITileEntityProvider;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Random;
|
||||
|
||||
public class BlockLectern extends BlockHorizontal implements ITileEntityProvider {
|
||||
|
||||
public BlockLectern(){
|
||||
super(Material.WOOD);
|
||||
this.setDefaultState(this.blockState.getBaseState().withProperty(FACING, EnumFacing.NORTH));
|
||||
this.setCreativeTab(WizardryTabs.WIZARDRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockStateContainer createBlockState(){
|
||||
return new BlockStateContainer.Builder(this).add(FACING).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateFromMeta(int meta){
|
||||
EnumFacing enumfacing = EnumFacing.byIndex(meta);
|
||||
if(enumfacing.getAxis() == EnumFacing.Axis.Y) enumfacing = EnumFacing.NORTH;
|
||||
return this.getDefaultState().withProperty(FACING, enumfacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetaFromState(IBlockState state){
|
||||
return state.getValue(FACING).getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void randomDisplayTick(IBlockState state, World world, BlockPos pos, Random rand){
|
||||
|
||||
EntityPlayer entityplayer = world.getClosestPlayer(pos.getX() + 0.5, pos.getY() + 0.5,
|
||||
pos.getZ() + 0.5, TileEntityLectern.BOOK_OPEN_DISTANCE, false);
|
||||
|
||||
if(entityplayer != null){
|
||||
ParticleBuilder.create(Type.DUST).pos(pos.getX() + rand.nextFloat(), pos.getY() + 1, pos.getZ() + rand.nextFloat())
|
||||
.vel(0, 0.03, 0).clr(1, 1, 0.65f).fade(0.7f, 0, 1).shaded(false).spawn(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullBlock(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNormalCube(IBlockState state){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceTorchOnTop(IBlockState state, IBlockAccess world, BlockPos pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFaceShape getBlockFaceShape(IBlockAccess world, IBlockState state, BlockPos pos, EnumFacing face){
|
||||
return face == EnumFacing.DOWN ? BlockFaceShape.SOLID : BlockFaceShape.UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer){
|
||||
return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TileEntity createNewTileEntity(World world, int meta){
|
||||
return new TileEntityLectern();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBlockActivated(World world, BlockPos pos, IBlockState block, EntityPlayer player, EnumHand hand,
|
||||
EnumFacing side, float hitX, float hitY, float hitZ){
|
||||
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
|
||||
if(tileEntity == null || player.isSneaking()){
|
||||
return false;
|
||||
}
|
||||
|
||||
player.openGui(Wizardry.instance, WizardryGuiHandler.LECTERN, world, pos.getX(), pos.getY(), pos.getZ());
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,10 +32,7 @@ import electroblob.wizardry.packet.*;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.*;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.tileentity.TileEntityMagicLight;
|
||||
import electroblob.wizardry.tileentity.TileEntityShrineCore;
|
||||
import electroblob.wizardry.tileentity.TileEntityStatue;
|
||||
import electroblob.wizardry.tileentity.*;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
@@ -310,6 +307,7 @@ public class ClientProxy extends CommonProxy {
|
||||
public void registerParticles(){
|
||||
// I'll be a good programmer and use the API method rather than the one above. Lead by example, as they say...
|
||||
ParticleWizardry.registerParticle(Type.BEAM, ParticleBeam::new);
|
||||
ParticleWizardry.registerParticle(Type.BLOCK_HIGHLIGHT, ParticleBlockHighlight::new);
|
||||
ParticleWizardry.registerParticle(Type.BUFF, ParticleBuff::new);
|
||||
ParticleWizardry.registerParticle(Type.DARK_MAGIC, ParticleDarkMagic::new);
|
||||
ParticleWizardry.registerParticle(Type.DUST, ParticleDust::new);
|
||||
@@ -762,6 +760,7 @@ public class ClientProxy extends CommonProxy {
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityArcaneWorkbench.class, new RenderArcaneWorkbench());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityStatue.class, renderStatue = new RenderStatue());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityMagicLight.class, new RenderMagicLight());
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityLectern.class, new RenderLectern());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.util.ISpellSortable;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.audio.PositionedSoundRecord;
|
||||
@@ -115,9 +116,9 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3));
|
||||
this.buttonList.add(new GuiButtonSort(1, this.guiLeft - 44, this.guiTop + 8, ContainerArcaneWorkbench.SortType.TIER));
|
||||
this.buttonList.add(new GuiButtonSort(2, this.guiLeft - 31, this.guiTop + 8, ContainerArcaneWorkbench.SortType.ELEMENT));
|
||||
this.buttonList.add(new GuiButtonSort(3, this.guiLeft - 18, this.guiTop + 8, ContainerArcaneWorkbench.SortType.ALPHABETICAL));
|
||||
this.buttonList.add(new GuiButtonSpellSort(1, this.guiLeft - 44, this.guiTop + 8, ISpellSortable.SortType.TIER, arcaneWorkbenchContainer, this));
|
||||
this.buttonList.add(new GuiButtonSpellSort(2, this.guiLeft - 31, this.guiTop + 8, ISpellSortable.SortType.ELEMENT, arcaneWorkbenchContainer, this));
|
||||
this.buttonList.add(new GuiButtonSpellSort(3, this.guiLeft - 18, this.guiTop + 8, ISpellSortable.SortType.ALPHABETICAL, arcaneWorkbenchContainer, this));
|
||||
|
||||
this.searchField = new GuiTextField(0, this.fontRenderer, this.guiLeft - 113, this.guiTop + 22, 104, this.fontRenderer.FONT_HEIGHT);
|
||||
this.searchField.setMaxStringLength(50);
|
||||
@@ -294,7 +295,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
// Scroll bar
|
||||
DrawingUtils.drawTexturedRect(guiLeft - BOOKSHELF_UI_WIDTH + SCROLL_BAR_LEFT,
|
||||
guiTop + SCROLL_BAR_TOP + (int)(scroll * (SCROLL_BAR_HEIGHT - SCROLL_HANDLE_HEIGHT) + 0.5f),
|
||||
getMaxScrollRows() > 0 ? 30 : 30 + SCROLL_BAR_WIDTH, 476,
|
||||
getMaxScrollRows() > 0 ? 0 : SCROLL_BAR_WIDTH, 476,
|
||||
SCROLL_BAR_WIDTH, SCROLL_HANDLE_HEIGHT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
// Tooltip only drawn if there is a wand
|
||||
@@ -507,7 +508,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
}
|
||||
}
|
||||
|
||||
this.buttonList.forEach(b -> b.drawButtonForegroundLayer(mouseX, mouseY));
|
||||
this.buttonList.forEach(b -> b.drawButtonForegroundLayer(mouseX - guiLeft, mouseY - guiTop));
|
||||
}
|
||||
|
||||
// Controls
|
||||
@@ -528,7 +529,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
animationTimer = 20;
|
||||
}
|
||||
|
||||
if(button instanceof GuiButtonSort) this.arcaneWorkbenchContainer.setSortType(((GuiButtonSort)button).sortType);
|
||||
if(button instanceof GuiButtonSpellSort) this.arcaneWorkbenchContainer.setSortType(((GuiButtonSpellSort)button).sortType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,45 +588,6 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
}
|
||||
}
|
||||
|
||||
// Nested classes
|
||||
|
||||
private class GuiButtonSort extends GuiButton {
|
||||
|
||||
private final ContainerArcaneWorkbench.SortType sortType;
|
||||
|
||||
public GuiButtonSort(int id, int x, int y, ContainerArcaneWorkbench.SortType sortType){
|
||||
super(id, x, y, 10, 10, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.sort_" + sortType.name));
|
||||
this.sortType = sortType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
if(this.visible){
|
||||
|
||||
// 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 = 0;
|
||||
int l = 476 + this.sortType.ordinal() * this.height;
|
||||
|
||||
if(sortType == GuiArcaneWorkbench.this.arcaneWorkbenchContainer.getSortType()){
|
||||
k += this.width;
|
||||
if(GuiArcaneWorkbench.this.arcaneWorkbenchContainer.isSortDescending()) k += this.width;
|
||||
}
|
||||
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButtonForegroundLayer(int mouseX, int mouseY){
|
||||
if(hovered) drawHoveringText(this.displayString, mouseX - guiLeft, mouseY - guiTop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class GuiButtonApply extends GuiButton {
|
||||
|
||||
public GuiButtonApply(int id, int x, int y){
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.util.ISpellSortable;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class GuiButtonSpellSort extends GuiButton {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/gui/spell_sort_buttons.png");
|
||||
private static final int TEXTURE_WIDTH = 32;
|
||||
private static final int TEXTURE_HEIGHT = 32;
|
||||
|
||||
public final ISpellSortable.SortType sortType;
|
||||
|
||||
private final ISpellSortable sortable;
|
||||
private final GuiScreen parent;
|
||||
|
||||
public GuiButtonSpellSort(int id, int x, int y, ISpellSortable.SortType sortType, ISpellSortable sortable, GuiScreen parent){
|
||||
super(id, x, y, 10, 10, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.sort_" + sortType.name));
|
||||
this.sortType = sortType;
|
||||
this.sortable = sortable;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
if(this.visible){
|
||||
|
||||
// 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 = 0;
|
||||
int l = this.sortType.ordinal() * this.height;
|
||||
|
||||
if(sortType == sortable.getSortType()){
|
||||
k += this.width;
|
||||
if(sortable.isSortDescending()) k += this.width;
|
||||
}
|
||||
|
||||
parent.mc.getTextureManager().bindTexture(TEXTURE);
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButtonForegroundLayer(int mouseX, int mouseY){
|
||||
if(hovered) parent.drawHoveringText(this.displayString, mouseX, mouseY);
|
||||
}
|
||||
|
||||
}
|
||||
+14
-10
@@ -1,6 +1,5 @@
|
||||
package electroblob.wizardry.client.gui.handbook;
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -11,12 +10,12 @@ import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
class GuiButtonTurnPage extends GuiButton {
|
||||
public class GuiButtonTurnPage extends GuiButton {
|
||||
|
||||
static final int WIDTH = 20;
|
||||
static final int HEIGHT = 12;
|
||||
public static final int WIDTH = 20;
|
||||
public static final int HEIGHT = 12;
|
||||
|
||||
enum Type {
|
||||
public enum Type {
|
||||
|
||||
NEXT_PAGE(0, 196),
|
||||
PREVIOUS_PAGE(0, 208),
|
||||
@@ -34,11 +33,15 @@ class GuiButtonTurnPage extends GuiButton {
|
||||
|
||||
public final Type type;
|
||||
|
||||
private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook.png");
|
||||
private final ResourceLocation texture;
|
||||
private final int textureWidth, textureHeight;
|
||||
|
||||
public GuiButtonTurnPage(int id, int x, int y, Type type){
|
||||
public GuiButtonTurnPage(int id, int x, int y, Type type, ResourceLocation texture, int textureWidth, int textureHeight){
|
||||
super(id, x, y, WIDTH, HEIGHT, "");
|
||||
this.type = type;
|
||||
this.texture = texture;
|
||||
this.textureWidth = textureWidth;
|
||||
this.textureHeight = textureHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,12 +53,13 @@ class GuiButtonTurnPage extends GuiButton {
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
if(this.visible){
|
||||
|
||||
|
||||
boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
||||
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
minecraft.getTextureManager().bindTexture(texture);
|
||||
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, flag ? type.u + width : type.u, type.v, width, height, 512, 256);
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, flag ? type.u + width : type.u, type.v, width, height, textureWidth, textureHeight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.client.gui.GuiButtonTurnPage.Type;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.packet.PacketLectern;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import electroblob.wizardry.util.ISpellSortable;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.WizardryUtilities;
|
||||
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.GuiTextField;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.play.client.CPacketCloseWindow;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/gui/lectern.png");
|
||||
/** The distance of the page buttons from the bottom outside corners of the GUI. */
|
||||
private static final int PAGE_BUTTON_INSET_X = 22, PAGE_BUTTON_INSET_Y = 13;
|
||||
/** The distance between adjacent page turn buttons. */
|
||||
private static final int PAGE_BUTTON_SPACING = 20;
|
||||
/** The distance of the sort buttons from the top left corner of the GUI. */
|
||||
private static final int SORT_BUTTON_INSET_X = 96, SORT_BUTTON_INSET_Y = 20;
|
||||
/** The distance between adjacent sort buttons. */
|
||||
private static final int SORT_BUTTON_SPACING = 13;
|
||||
/** The distance of the spell buttons from the top outside corners of the GUI. */
|
||||
private static final int SPELL_BUTTON_INSET_X = 23, SPELL_BUTTON_INSET_Y = 44;
|
||||
/** The distance between adjacent spell buttons (in both x and y). */
|
||||
private static final int SPELL_BUTTON_SPACING = 38;
|
||||
|
||||
private static final int SPELL_ROWS = 3, SPELL_COLUMNS = 3;
|
||||
public static final int SPELL_BUTTON_COUNT = SPELL_ROWS * SPELL_COLUMNS * 2; // x2 because there are 2 pages
|
||||
|
||||
private final TileEntityLectern lectern;
|
||||
|
||||
private GuiButton nextPageButton;
|
||||
private GuiButton prevPageButton;
|
||||
private GuiButton lastPageButton;
|
||||
private GuiButton firstPageButton;
|
||||
private GuiButton indexButton;
|
||||
private GuiButton locateButton;
|
||||
|
||||
private GuiButton[] sortButtons = new GuiButton[3];
|
||||
private GuiButtonSpell[] spellButtons = new GuiButtonSpell[SPELL_BUTTON_COUNT];
|
||||
|
||||
/** The spell currently being viewed, or null if the index is being viewed. */
|
||||
private Spell currentSpell;
|
||||
/** The available spells in nearby bookshelves; should not contain duplicates. */
|
||||
private List<Spell> availableSpells = new ArrayList<>();
|
||||
/** The spells matching the current search criteria, sorted according to the current sort settings. Will be a subset
|
||||
* of {@link GuiLectern#availableSpells}. */
|
||||
private List<Spell> matchingSpells;
|
||||
|
||||
private ISpellSortable.SortType sortType = ISpellSortable.SortType.TIER;
|
||||
private boolean sortDescending = false;
|
||||
|
||||
private GuiTextField searchField;
|
||||
private boolean searchNeedsClearing;
|
||||
|
||||
private int currentPage = 0;
|
||||
|
||||
public GuiLectern(TileEntityLectern lectern){
|
||||
super(288, 180);
|
||||
this.lectern = lectern;
|
||||
this.currentSpell = lectern.currentSpell;
|
||||
this.setTextureSize(512, 512);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spell getSpell(){
|
||||
return currentSpell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(){
|
||||
return TEXTURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortType getSortType(){
|
||||
return sortType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSortDescending(){
|
||||
return sortDescending;
|
||||
}
|
||||
|
||||
private int getPageCount(){
|
||||
return MathHelper.ceil((float)matchingSpells.size() / SPELL_BUTTON_COUNT);
|
||||
}
|
||||
|
||||
private Spell getSpellForButton(GuiButtonSpell button){
|
||||
return matchingSpells.get(currentPage * SPELL_BUTTON_COUNT + button.index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui(){
|
||||
|
||||
super.initGui();
|
||||
|
||||
updateAvailableSpells();
|
||||
|
||||
final int left = this.width / 2 - this.xSize / 2;
|
||||
final int top = this.height / 2 - this.ySize / 2;
|
||||
|
||||
int buttonID = 0;
|
||||
|
||||
// Page buttons
|
||||
this.buttonList.add(nextPageButton = new GuiButtonTurnPage(buttonID++, left + xSize - PAGE_BUTTON_INSET_X - GuiButtonTurnPage.WIDTH,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_PAGE, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(prevPageButton = new GuiButtonTurnPage(buttonID++, left + PAGE_BUTTON_INSET_X,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_PAGE, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(lastPageButton = new GuiButtonTurnPage(buttonID++, left + xSize - PAGE_BUTTON_INSET_X - GuiButtonTurnPage.WIDTH - PAGE_BUTTON_SPACING,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_SECTION, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(firstPageButton = new GuiButtonTurnPage(buttonID++, left + PAGE_BUTTON_INSET_X + PAGE_BUTTON_SPACING,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_SECTION, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(indexButton = new GuiButtonTurnPage(buttonID++, left + xSize/2 - 23,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.CONTENTS, TEXTURE, textureWidth, textureHeight));
|
||||
|
||||
this.buttonList.add(locateButton = new GuiButtonLocateBook(buttonID++, left + xSize/2 - 34,
|
||||
top + ySize - PAGE_BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT));
|
||||
|
||||
// Sort buttons
|
||||
for(SortType sortType : SortType.values()){
|
||||
this.buttonList.add(sortButtons[sortType.ordinal()] = new GuiButtonSpellSort(buttonID++,
|
||||
left + SORT_BUTTON_INSET_X + SORT_BUTTON_SPACING * sortType.ordinal(),
|
||||
top + SORT_BUTTON_INSET_Y, sortType, this, this));
|
||||
}
|
||||
|
||||
// Spell buttons
|
||||
for(int i = 0; i < SPELL_BUTTON_COUNT; i++){
|
||||
|
||||
int row = i % SPELL_COLUMNS;
|
||||
int column = (i / SPELL_COLUMNS) % SPELL_ROWS;
|
||||
|
||||
int x = i < SPELL_BUTTON_COUNT/2 ? SPELL_BUTTON_INSET_X + row * SPELL_BUTTON_SPACING
|
||||
: xSize - SPELL_BUTTON_INSET_X - GuiButtonSpell.WIDTH - (2-row) * SPELL_BUTTON_SPACING;
|
||||
int y = SPELL_BUTTON_INSET_Y + column * SPELL_BUTTON_SPACING;
|
||||
|
||||
this.buttonList.add(spellButtons[i] = new GuiButtonSpell(buttonID++, left + x, top + y, i));
|
||||
}
|
||||
|
||||
this.searchField = new GuiTextField(0, this.fontRenderer, left + 157, top + 21, 106, this.fontRenderer.FONT_HEIGHT);
|
||||
this.searchField.setMaxStringLength(50);
|
||||
this.searchField.setEnableBackgroundDrawing(false);
|
||||
this.searchField.setVisible(true);
|
||||
this.searchField.setTextColor(16777215);
|
||||
this.searchField.setCanLoseFocus(false);
|
||||
this.searchField.setFocused(true);
|
||||
|
||||
updateMatchingSpells();
|
||||
updateButtonVisiblity();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed(){
|
||||
WizardryPacketHandler.net.sendToServer(new PacketLectern.Message(lectern.getPos(), currentSpell));
|
||||
super.onGuiClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackgroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
if(currentSpell == Spells.none){
|
||||
drawIndexPage(left, top);
|
||||
}else{
|
||||
super.drawBackgroundLayer(left, top, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawForegroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
|
||||
if(currentSpell == Spells.none){
|
||||
this.fontRenderer.drawString(I18n.format("gui." + Wizardry.MODID + ":lectern.title"),
|
||||
left + 20, top + SORT_BUTTON_INSET_Y, 0);
|
||||
}else{
|
||||
super.drawForegroundLayer(left, top, mouseX, mouseY);
|
||||
}
|
||||
|
||||
this.buttonList.forEach(b -> b.drawButtonForegroundLayer(mouseX, mouseY));
|
||||
}
|
||||
|
||||
private void drawIndexPage(int left, int top){
|
||||
|
||||
for(int i = 0; i < SPELL_BUTTON_COUNT; i++){
|
||||
|
||||
int index = currentPage * SPELL_BUTTON_COUNT + i;
|
||||
Spell spell = index < matchingSpells.size() ? matchingSpells.get(index) : Spells.none;
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(spell, null);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(discovered ? spell.getIcon() : Spells.none.getIcon());
|
||||
|
||||
int row = i % SPELL_COLUMNS;
|
||||
int column = (i / SPELL_COLUMNS) % SPELL_ROWS;
|
||||
|
||||
int x = i < SPELL_BUTTON_COUNT/2 ? SPELL_BUTTON_INSET_X + row * SPELL_BUTTON_SPACING
|
||||
: xSize - SPELL_BUTTON_INSET_X - GuiButtonSpell.WIDTH - (2-row) * SPELL_BUTTON_SPACING;
|
||||
int y = SPELL_BUTTON_INSET_Y + column * SPELL_BUTTON_SPACING;
|
||||
|
||||
DrawingUtils.drawTexturedRect(left + x + 1, top + y + 1, 0, 0, 32, 32, 32, 32);
|
||||
}
|
||||
|
||||
mc.renderEngine.bindTexture(getTexture());
|
||||
DrawingUtils.drawTexturedRect(left, top, 0, 256, xSize, ySize, textureWidth, textureHeight);
|
||||
|
||||
this.searchField.drawTextBox();
|
||||
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
mc.renderEngine.bindTexture(getTexture());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
searchNeedsClearing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton button){
|
||||
|
||||
int lastPage = getPageCount() - 1;
|
||||
|
||||
if(button == indexButton){
|
||||
currentSpell = Spells.none;
|
||||
currentPage = 0;
|
||||
|
||||
}else if(button == locateButton){
|
||||
// Close the GUI
|
||||
this.mc.player.connection.sendPacket(new CPacketCloseWindow(this.mc.player.openContainer.windowId));
|
||||
this.mc.displayGuiScreen(null);
|
||||
|
||||
// Find the location(s) of the current spell's book(s) and highlight them
|
||||
for(IInventory bookshelf : BlockBookshelf.findNearbyBookshelves(lectern.getWorld(), lectern.getPos())){
|
||||
|
||||
for(int i = 0; i < bookshelf.getSizeInventory(); i++){
|
||||
|
||||
ItemStack stack = bookshelf.getStackInSlot(i);
|
||||
|
||||
if(stack.getItem() instanceof ItemSpellBook){
|
||||
|
||||
Spell spell = Spell.byMetadata(stack.getMetadata());
|
||||
|
||||
if(spell == this.currentSpell){
|
||||
BlockPos pos = (((TileEntity)bookshelf).getPos());
|
||||
for(EnumFacing side : EnumFacing.VALUES){
|
||||
ParticleBuilder.create(ParticleBuilder.Type.BLOCK_HIGHLIGHT).pos(
|
||||
WizardryUtilities.getFaceCentre(pos, side)
|
||||
.add(new Vec3d(side.getDirectionVec())
|
||||
.scale(WizardryUtilities.ANTI_Z_FIGHTING_OFFSET)))
|
||||
.face(side).clr(0.9f, 0.5f, 0.8f).fade(0.7f, 0, 1).spawn(mc.world);
|
||||
}
|
||||
break; // This bookshelf has the spell, skip to the next bookshelf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else if(button == nextPageButton){
|
||||
if(currentPage < lastPage) currentPage++;
|
||||
|
||||
}else if(button == prevPageButton){
|
||||
if(currentPage > 0) currentPage--;
|
||||
|
||||
}else if(button == lastPageButton){
|
||||
currentPage = lastPage;
|
||||
|
||||
}else if(button == firstPageButton){
|
||||
currentPage = 0;
|
||||
|
||||
}else if(button instanceof GuiButtonSpell){
|
||||
currentSpell = getSpellForButton((GuiButtonSpell)button);
|
||||
|
||||
}else if(button instanceof GuiButtonSpellSort){
|
||||
|
||||
SortType sortType = (((GuiButtonSpellSort)button).sortType);
|
||||
|
||||
if(this.sortType == sortType){
|
||||
this.sortDescending = !this.sortDescending;
|
||||
}else{
|
||||
this.sortType = sortType;
|
||||
this.sortDescending = false;
|
||||
}
|
||||
|
||||
updateMatchingSpells();
|
||||
}
|
||||
|
||||
updateButtonVisiblity();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
|
||||
if(this.searchNeedsClearing){
|
||||
this.searchNeedsClearing = false;
|
||||
this.searchField.setText("");
|
||||
this.currentPage = 0;
|
||||
}
|
||||
|
||||
if(this.searchField.textboxKeyTyped(typedChar, keyCode)){
|
||||
this.currentPage = 0;
|
||||
updateMatchingSpells();
|
||||
updateButtonVisiblity();
|
||||
}else{
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateButtonVisiblity(){
|
||||
|
||||
if(currentSpell == Spells.none){
|
||||
|
||||
this.searchField.setVisible(true);
|
||||
|
||||
int lastPage = getPageCount() - 1;
|
||||
|
||||
prevPageButton.visible = currentPage > 0;
|
||||
firstPageButton.visible = currentPage > 0;
|
||||
nextPageButton.visible = currentPage < lastPage;
|
||||
lastPageButton.visible = currentPage < lastPage;
|
||||
|
||||
indexButton.visible = false;
|
||||
locateButton.visible = false;
|
||||
|
||||
for(GuiButton button : sortButtons) button.visible = true;
|
||||
|
||||
for(GuiButtonSpell button : spellButtons){
|
||||
button.visible = currentPage * SPELL_BUTTON_COUNT + button.index < matchingSpells.size();
|
||||
}
|
||||
|
||||
}else{
|
||||
this.searchField.setVisible(false);
|
||||
this.buttonList.forEach(b -> b.visible = false); // Hide all buttons...
|
||||
indexButton.visible = true; // ... except the index button and locate button
|
||||
locateButton.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMatchingSpells(){
|
||||
matchingSpells = availableSpells.stream()
|
||||
.filter(s -> s.matches(searchField.getText().toLowerCase(Locale.ROOT)))
|
||||
.sorted(sortDescending ? sortType.comparator.reversed() : sortType.comparator)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// TODO: Call this when a bookshelf is added or removed
|
||||
// TODO: Config option to always display all spells when in creative
|
||||
private void updateAvailableSpells(){
|
||||
|
||||
availableSpells.clear();
|
||||
|
||||
// No need to exclude the lectern TE because it's not an IInventory!
|
||||
for(IInventory bookshelf : BlockBookshelf.findNearbyBookshelves(lectern.getWorld(), lectern.getPos())){
|
||||
|
||||
for(int i=0; i<bookshelf.getSizeInventory(); i++){
|
||||
|
||||
ItemStack stack = bookshelf.getStackInSlot(i);
|
||||
|
||||
if(stack.getItem() instanceof ItemSpellBook){
|
||||
Spell spell = Spell.byMetadata(stack.getMetadata());
|
||||
if(!availableSpells.contains(spell)) availableSpells.add(spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!availableSpells.contains(currentSpell)) currentSpell = Spells.none; // TODO: Do we want this?
|
||||
|
||||
}
|
||||
|
||||
private class GuiButtonLocateBook extends GuiButton {
|
||||
|
||||
public GuiButtonLocateBook(int id, int x, int y){
|
||||
super(id, x, y, 12, 12, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
|
||||
if(this.visible){
|
||||
|
||||
boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
||||
GlStateManager.color(1, 1, 1, 1);
|
||||
minecraft.getTextureManager().bindTexture(TEXTURE);
|
||||
|
||||
DrawingUtils.drawTexturedRect(this.x, this.y, flag ? width : 0, 184, width, height, textureWidth, textureHeight);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GuiButtonSpell extends GuiButtonInvisible {
|
||||
|
||||
private static final int WIDTH = 34, HEIGHT = 34;
|
||||
|
||||
private final int index;
|
||||
|
||||
public GuiButtonSpell(int id, int x, int y, int index){
|
||||
super(id, x, y, WIDTH, HEIGHT);
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playPressSound(SoundHandler soundHandler){
|
||||
soundHandler.playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_PAGE_TURN, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||
if(visible){
|
||||
super.drawButton(minecraft, mouseX, mouseY, partialTicks);
|
||||
if(hovered){
|
||||
mc.renderEngine.bindTexture(getTexture());
|
||||
DrawingUtils.drawTexturedRect(x, y, 40, 180, width, height, textureWidth, textureHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawButtonForegroundLayer(int mouseX, int mouseY){
|
||||
if(visible && hovered){
|
||||
Spell spell = getSpellForButton(this);
|
||||
if(Wizardry.proxy.shouldDisplayDiscovered(spell, null)){
|
||||
drawHoveringText(Collections.singletonList(spell.getDisplayName()), mouseX, mouseY, fontRenderer);
|
||||
}else{
|
||||
drawHoveringText(Collections.singletonList(SpellGlyphData.getGlyphName(spell, mc.world)),
|
||||
mouseX, mouseY, mc.standardGalacticFontRenderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,113 +1,35 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
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.item.ItemSpellBook;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
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.client.resources.I18n;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class GuiSpellBook extends GuiScreen {
|
||||
public class GuiSpellBook extends GuiSpellInfo {
|
||||
|
||||
private int xSize, ySize;
|
||||
private ItemSpellBook book;
|
||||
private Spell spell;
|
||||
private final ItemSpellBook book;
|
||||
private final Spell spell;
|
||||
|
||||
public GuiSpellBook(ItemStack stack){
|
||||
super();
|
||||
xSize = 288;
|
||||
ySize = 180;
|
||||
if(!(stack.getItem() instanceof ItemSpellBook)) throw new ClassCastException("Cannot create spell book GUI for item that does not extend ItemSpellBook!");
|
||||
|
||||
super(288, 180);
|
||||
|
||||
if(!(stack.getItem() instanceof ItemSpellBook)){
|
||||
throw new ClassCastException("Cannot create spell book GUI for item that does not extend ItemSpellBook!");
|
||||
}
|
||||
|
||||
this.book = (ItemSpellBook)stack.getItem();
|
||||
this.spell = Spell.byMetadata(stack.getItemDamage());
|
||||
this.spell = (Spell.byMetadata(stack.getItemDamage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int par1, int par2, float par3){
|
||||
|
||||
int xPos = this.width / 2 - xSize / 2;
|
||||
int yPos = this.height / 2 - this.ySize / 2;
|
||||
|
||||
EntityPlayer player = Minecraft.getMinecraft().player;
|
||||
|
||||
boolean discovered = true;
|
||||
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(book.getGuiTexture(spell));
|
||||
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.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.getType().getDisplayName(), xPos + 17, yPos + 26,
|
||||
0x777777);
|
||||
}
|
||||
|
||||
// Novice is usually white but this doesn't show up
|
||||
String tier = I18n.format("gui.ebwizardry:spell_book.tier", spell.getTier() == Tier.NOVICE ?
|
||||
"\u00A77" + spell.getTier().getDisplayName() : spell.getTier().getDisplayNameWithFormatting());
|
||||
this.fontRenderer.drawString(tier, xPos + 17, yPos + 45, 0);
|
||||
|
||||
String element = I18n.format("gui.ebwizardry:spell_book.element", spell.getElement().getFormattingCode() + spell.getElement().getDisplayName());
|
||||
if(!discovered) element = I18n.format("gui.ebwizardry:spell_book.element_undiscovered");
|
||||
this.fontRenderer.drawString(element, xPos + 17, yPos + 57, 0);
|
||||
|
||||
String manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost", spell.getCost());
|
||||
if(spell.isContinuous) manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost_continuous", spell.getCost());
|
||||
if(!discovered) manaCost = I18n.format("gui.ebwizardry:spell_book.mana_cost_undiscovered");
|
||||
this.fontRenderer.drawString(manaCost, xPos + 17, yPos + 69, 0);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawSplitString(spell.getDescription(), xPos + 17, yPos + 83, 118, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawSplitString(
|
||||
SpellGlyphData.getGlyphDescription(spell, player.world), xPos + 17, yPos + 83, 118, 0);
|
||||
}
|
||||
public Spell getSpell(){
|
||||
return spell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui(){
|
||||
super.initGui();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
|
||||
this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed(){
|
||||
super.onGuiClosed();
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesGuiPauseGame(){
|
||||
return Wizardry.settings.booksPauseGame;
|
||||
public ResourceLocation getTexture(){
|
||||
return book.getGuiTexture(spell);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
package electroblob.wizardry.client.gui;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.data.SpellGlyphData;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
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.client.resources.I18n;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
/** Abstract base class for both {@link GuiSpellBook} and {@link GuiLectern}. Centralises code common to both
|
||||
* those classes. */
|
||||
public abstract class GuiSpellInfo extends GuiScreen {
|
||||
|
||||
protected static final String TRANSLATION_KEY_PREFIX = "gui." + Wizardry.MODID + ":spell_book";
|
||||
|
||||
protected final int xSize, ySize;
|
||||
protected int textureWidth = 512;
|
||||
protected int textureHeight = 256;
|
||||
|
||||
public GuiSpellInfo(int xSize, int ySize){
|
||||
super();
|
||||
this.xSize = xSize;
|
||||
this.ySize = ySize;
|
||||
}
|
||||
|
||||
protected void setTextureSize(int width, int height){
|
||||
this.textureWidth = width;
|
||||
this.textureHeight = height;
|
||||
}
|
||||
|
||||
/** Returns the spell to be displayed by this GUI. */
|
||||
public abstract Spell getSpell();
|
||||
|
||||
/** Returns the main texture for the background of this GUI. */
|
||||
public abstract ResourceLocation getTexture();
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks){
|
||||
int left = this.width/2 - xSize/2;
|
||||
int top = this.height/2 - this.ySize/2;
|
||||
this.drawBackgroundLayer(left, top, mouseX, mouseY);
|
||||
super.drawScreen(mouseX, mouseY, partialTicks); // Just draws the buttons
|
||||
this.drawForegroundLayer(left, top, mouseX, mouseY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the background of the spell info GUI. This is called before buttons are drawn.
|
||||
* @param left The x-coordinate of the left-hand edge of the GUI
|
||||
* @param top The y-coordinate of the top edge of the GUI
|
||||
* @param mouseX The current x position of the mouse pointer
|
||||
* @param mouseY The current y position of the mouse pointer
|
||||
*/
|
||||
protected void drawBackgroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(getSpell(), null);
|
||||
|
||||
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 ? getSpell().getIcon() : Spells.none.getIcon());
|
||||
DrawingUtils.drawTexturedRect(left + 146, top + 20, 0, 0, 128, 128, 128, 128);
|
||||
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(getTexture());
|
||||
DrawingUtils.drawTexturedRect(left, top, 0, 0, xSize, ySize, textureWidth, textureHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the foreground of the spell info GUI. This is called after buttons are drawn.
|
||||
* @param left The x-coordinate of the left-hand edge of the GUI
|
||||
* @param top The y-coordinate of the top edge of the GUI
|
||||
* @param mouseX The current x position of the mouse pointer
|
||||
* @param mouseY The current y position of the mouse pointer
|
||||
*/
|
||||
protected void drawForegroundLayer(int left, int top, int mouseX, int mouseY){
|
||||
|
||||
boolean discovered = Wizardry.proxy.shouldDisplayDiscovered(getSpell(), null);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawString(getSpell().getDisplayName(), left + 17, top + 15, 0);
|
||||
this.fontRenderer.drawString(getSpell().getType().getDisplayName(), left + 17, top + 26, 0x777777);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawString(SpellGlyphData.getGlyphName(getSpell(), mc.world), left + 17,
|
||||
top + 15, 0);
|
||||
this.mc.standardGalacticFontRenderer.drawString(getSpell().getType().getDisplayName(), left + 17, top + 26,
|
||||
0x777777);
|
||||
}
|
||||
|
||||
// Novice is usually white but this doesn't show up
|
||||
String tier = I18n.format(TRANSLATION_KEY_PREFIX + ".tier", getSpell().getTier() == Tier.NOVICE ?
|
||||
"\u00A77" + getSpell().getTier().getDisplayName() : getSpell().getTier().getDisplayNameWithFormatting());
|
||||
this.fontRenderer.drawString(tier, left + 17, top + 45, 0);
|
||||
|
||||
String element = I18n.format(TRANSLATION_KEY_PREFIX + ".element", getSpell().getElement().getFormattingCode() + getSpell().getElement().getDisplayName());
|
||||
if(!discovered) element = I18n.format(TRANSLATION_KEY_PREFIX + ".element_undiscovered");
|
||||
this.fontRenderer.drawString(element, left + 17, top + 57, 0);
|
||||
|
||||
String manaCost = I18n.format(TRANSLATION_KEY_PREFIX + ".mana_cost", getSpell().getCost());
|
||||
if(getSpell().isContinuous) manaCost = I18n.format(TRANSLATION_KEY_PREFIX + ".mana_cost_continuous", getSpell().getCost());
|
||||
if(!discovered) manaCost = I18n.format(TRANSLATION_KEY_PREFIX + ".mana_cost_undiscovered");
|
||||
this.fontRenderer.drawString(manaCost, left + 17, top + 69, 0);
|
||||
|
||||
if(discovered){
|
||||
this.fontRenderer.drawSplitString(getSpell().getDescription(), left + 17, top + 83, 118, 0);
|
||||
}else{
|
||||
this.mc.standardGalacticFontRenderer.drawSplitString(
|
||||
SpellGlyphData.getGlyphDescription(getSpell(), mc.world), left + 17, top + 83, 118, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initGui(){
|
||||
super.initGui();
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
this.mc.getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(WizardrySounds.MISC_BOOK_OPEN, 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed(){
|
||||
super.onGuiClosed();
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesGuiPauseGame(){
|
||||
return Wizardry.settings.booksPauseGame;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,8 @@ import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.ClientProxy;
|
||||
import electroblob.wizardry.client.DrawingUtils;
|
||||
import electroblob.wizardry.client.gui.GuiButtonInvisible;
|
||||
import electroblob.wizardry.client.gui.handbook.GuiButtonTurnPage.Type;
|
||||
import electroblob.wizardry.client.gui.GuiButtonTurnPage;
|
||||
import electroblob.wizardry.client.gui.GuiButtonTurnPage.Type;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
@@ -348,19 +349,19 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
this.buttonList.clear();
|
||||
|
||||
this.buttonList.add(next = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH - BUTTON_INSET_X - GuiButtonTurnPage.WIDTH,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_PAGE));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_PAGE, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(previous = new GuiButtonTurnPage(nextButtonId++, left + BUTTON_INSET_X,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_PAGE));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_PAGE, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(nextSection = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH - BUTTON_INSET_X - GuiButtonTurnPage.WIDTH - BUTTON_SPACING,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_SECTION));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.NEXT_SECTION, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(previousSection = new GuiButtonTurnPage(nextButtonId++, left + BUTTON_INSET_X + BUTTON_SPACING,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_SECTION));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.PREVIOUS_SECTION, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(menu = new GuiButtonTurnPage(nextButtonId++, left + GUI_WIDTH/2 - 28,
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.CONTENTS));
|
||||
top + GUI_HEIGHT - BUTTON_INSET_Y - GuiButtonTurnPage.HEIGHT, Type.CONTENTS, texture, TEXTURE_WIDTH, TEXTURE_HEIGHT));
|
||||
|
||||
this.buttonList.add(bookmark = new GuiButtonInvisible(nextButtonId++, left + 130, top + 172, 11, 19) {
|
||||
@Override
|
||||
|
||||
@@ -84,6 +84,13 @@ public final class WizardryModels {
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.acacia_bookshelf));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.dark_oak_bookshelf));
|
||||
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.oak_lectern));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.spruce_lectern));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.birch_lectern));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.jungle_lectern));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.acacia_lectern));
|
||||
registerItemModel(Item.getItemFromBlock(WizardryBlocks.dark_oak_lectern));
|
||||
|
||||
// Items
|
||||
|
||||
registerMultiTexturedModel((ItemCrystal)WizardryItems.magic_crystal);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package electroblob.wizardry.client.particle;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
|
||||
//@SideOnly(Side.CLIENT)
|
||||
@Mod.EventBusSubscriber(Side.CLIENT)
|
||||
public class ParticleBlockHighlight extends ParticleWizardry {
|
||||
|
||||
private static final ResourceLocation TEXTURE = new ResourceLocation(Wizardry.MODID, "particle/block_highlight");
|
||||
|
||||
public ParticleBlockHighlight(World world, double x, double y, double z){
|
||||
|
||||
super(world, x, y, z, TEXTURE);
|
||||
|
||||
this.particleGravity = 0;
|
||||
this.setMaxAge(160);
|
||||
this.particleScale = 5;
|
||||
this.shaded = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDisableDepth(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(){
|
||||
|
||||
super.onUpdate();
|
||||
|
||||
// Fading
|
||||
if(this.particleAge > this.particleMaxAge/2){
|
||||
this.setAlphaF(1 - ((float)this.particleAge - this.particleMaxAge/2f) / (this.particleMaxAge/2f));
|
||||
}
|
||||
|
||||
EnumFacing facing = EnumFacing.fromAngle(yaw);
|
||||
if(pitch == 90) facing = EnumFacing.UP;
|
||||
if(pitch == -90) facing = EnumFacing.DOWN;
|
||||
|
||||
// Disappears if there is no block behind it (this is the same check used to spawn it)
|
||||
if(!world.getBlockState(new BlockPos(posX, posY, posZ).offset(facing.getOpposite())).getMaterial().isSolid()){
|
||||
this.setExpired();
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onTextureStitchEvent(TextureStitchEvent.Pre event){
|
||||
event.getMap().registerSprite(TEXTURE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package electroblob.wizardry.client.renderer;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import net.minecraft.block.BlockHorizontal;
|
||||
import net.minecraft.client.model.ModelBook;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class RenderLectern extends TileEntitySpecialRenderer<TileEntityLectern> {
|
||||
|
||||
private static final ResourceLocation BOOK_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/lectern_book.png");
|
||||
private final ModelBook modelBook = new ModelBook();
|
||||
|
||||
@Override
|
||||
public void render(TileEntityLectern te, double x, double y, double z, float partialTicks, int destroyStage, float alpha){
|
||||
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.translate((float)x + 0.5F, (float)y + 1, (float)z + 0.5F);
|
||||
GlStateManager.rotate(90 - te.getWorld().getBlockState(te.getPos()).getValue(BlockHorizontal.FACING).getHorizontalAngle(), 0, 1, 0);
|
||||
|
||||
float time = (float)te.ticksExisted + partialTicks;
|
||||
|
||||
float spread = te.bookSpreadPrev + (te.bookSpread - te.bookSpreadPrev) * partialTicks;
|
||||
|
||||
GlStateManager.translate(0, 0.12, 0);
|
||||
if(spread > 0.3) GlStateManager.translate(0, MathHelper.sin(time * 0.1F) * 0.01F, 0);
|
||||
|
||||
GlStateManager.rotate(112.5F, 0, 0, 1);
|
||||
|
||||
GlStateManager.translate(0, 0.04 + (1 - spread) * 0.09, (1 - spread) * -0.1875);
|
||||
|
||||
GlStateManager.rotate((1 - spread) * -90, 0, 1, 0);
|
||||
|
||||
this.bindTexture(BOOK_TEXTURE);
|
||||
|
||||
float f3 = te.pageFlipPrev + (te.pageFlip - te.pageFlipPrev) * partialTicks + 0.25F;
|
||||
float f4 = te.pageFlipPrev + (te.pageFlip - te.pageFlipPrev) * partialTicks + 0.75F;
|
||||
f3 = (f3 - (float)MathHelper.fastFloor(f3)) * 1.6F - 0.3F;
|
||||
f4 = (f4 - (float)MathHelper.fastFloor(f4)) * 1.6F - 0.3F;
|
||||
|
||||
f3 = MathHelper.clamp(f3, 0, 1);
|
||||
f4 = MathHelper.clamp(f4, 0, 1);
|
||||
|
||||
GlStateManager.enableCull();
|
||||
this.modelBook.render(null, time, f3, f4, spread, 0.0F, 0.0625F);
|
||||
GlStateManager.popMatrix();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import electroblob.wizardry.registry.WizardryAdvancementTriggers;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.util.ISpellSortable;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
@@ -18,9 +19,7 @@ import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
@@ -47,7 +46,7 @@ import java.util.stream.Collectors;
|
||||
* for consistency, just in case). The bookshelf slot delegates to a virtual slot on the client side (which is where
|
||||
* the search and sorting is done), and <i>then</i> the click is sent to the server.
|
||||
*/
|
||||
public class ContainerArcaneWorkbench extends Container {
|
||||
public class ContainerArcaneWorkbench extends Container implements ISpellSortable {
|
||||
|
||||
/** The arcane workbench tile entity associated with this container. */
|
||||
public TileEntityArcaneWorkbench tileentity;
|
||||
@@ -70,7 +69,7 @@ public class ContainerArcaneWorkbench extends Container {
|
||||
private List<VirtualSlot> activeBookshelfSlots = new ArrayList<>();
|
||||
|
||||
private int scroll = 0;
|
||||
private SortType sortType = SortType.TIER;
|
||||
private ISpellSortable.SortType sortType = ISpellSortable.SortType.TIER;
|
||||
private boolean sortDescending = false;
|
||||
private String searchText = "";
|
||||
|
||||
@@ -369,7 +368,7 @@ public class ContainerArcaneWorkbench extends Container {
|
||||
}
|
||||
|
||||
/** Sets the sorting type to the given type, or toggles the sort direction if it is already that type. */
|
||||
public void setSortType(SortType sortType){
|
||||
public void setSortType(ISpellSortable.SortType sortType){
|
||||
|
||||
if(this.sortType == sortType){
|
||||
this.sortDescending = !this.sortDescending;
|
||||
@@ -381,12 +380,12 @@ public class ContainerArcaneWorkbench extends Container {
|
||||
updateActiveBookshelfSlots();
|
||||
}
|
||||
|
||||
/** Returns the current sorting type. */
|
||||
public SortType getSortType(){
|
||||
@Override
|
||||
public ISpellSortable.SortType getSortType(){
|
||||
return sortType;
|
||||
}
|
||||
|
||||
/** Returns true if the current sorting is in descending order, false otherwise. */
|
||||
@Override
|
||||
public boolean isSortDescending(){
|
||||
return sortDescending;
|
||||
}
|
||||
@@ -435,6 +434,7 @@ public class ContainerArcaneWorkbench extends Container {
|
||||
// N.B. If we drop the requirement of it working with any container it could potentially be a lot easier since
|
||||
// we then always have control over the bookshelf classes
|
||||
|
||||
// TODO: Call this when a bookshelf is added or removed
|
||||
/** Called on initialisation, and whenever a bookshelf is added or removed. */
|
||||
private void refreshBookshelfSlots(){
|
||||
|
||||
@@ -442,7 +442,7 @@ public class ContainerArcaneWorkbench extends Container {
|
||||
// TESTME: May need to do this for inventoryItemStacks (probably not though, seems like MC handles it)
|
||||
bookshelfSlots.clear();
|
||||
|
||||
for(IInventory bookshelf : findNearbyBookshelves()){
|
||||
for(IInventory bookshelf : BlockBookshelf.findNearbyBookshelves(tileentity.getWorld(), tileentity.getPos(), tileentity)){
|
||||
for(int i=0; i<bookshelf.getSizeInventory(); i++){
|
||||
VirtualSlot slot = new VirtualSlot(bookshelf, i); // This sets the slot INDEX (for the INVENTORY)
|
||||
bookshelfSlots.add(slot);
|
||||
@@ -454,45 +454,4 @@ public class ContainerArcaneWorkbench extends Container {
|
||||
|
||||
}
|
||||
|
||||
/** Returns a list of nearby tile entities that have inventories. */
|
||||
public List<IInventory> findNearbyBookshelves(){
|
||||
|
||||
List<IInventory> bookshelves = new ArrayList<>();
|
||||
|
||||
int searchRadius = 4; // TODO: Config option for this
|
||||
|
||||
for(int x = -searchRadius; x <= searchRadius; x++){
|
||||
for(int y = -searchRadius; y <= searchRadius; y++){
|
||||
for(int z = -searchRadius; z <= searchRadius; z++){
|
||||
|
||||
BlockPos pos = this.tileentity.getPos().add(x, y, z);
|
||||
// TODO: Config option for allowed containers
|
||||
if(this.tileentity.getWorld().getBlockState(pos).getBlock() instanceof BlockBookshelf){
|
||||
TileEntity te = this.tileentity.getWorld().getTileEntity(pos);
|
||||
if(te instanceof IInventory && te != this.tileentity) bookshelves.add((IInventory)te);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bookshelves;
|
||||
|
||||
}
|
||||
|
||||
public enum SortType {
|
||||
|
||||
TIER("tier", Comparator.naturalOrder()),
|
||||
ELEMENT("element", Comparator.comparing(Spell::getElement).thenComparing(Spell::getTier)),
|
||||
ALPHABETICAL("alphabetical", Comparator.comparing(Spell::getUnlocalisedName));
|
||||
|
||||
public String name;
|
||||
public Comparator<? super Spell> comparator;
|
||||
|
||||
SortType(String name, Comparator<? super Spell> comparator){
|
||||
this.name = name;
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package electroblob.wizardry.packet;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.tileentity.TileEntityLectern;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||
|
||||
/** <b>[Client -> Server]</b> This packet is sent when a player closes the lectern GUI to send the last-viewed spell to
|
||||
* the server. */
|
||||
public class PacketLectern implements IMessageHandler<PacketLectern.Message, IMessage> {
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(Message message, MessageContext ctx){
|
||||
|
||||
// Just to make sure that the side is correct
|
||||
if(ctx.side.isServer()){
|
||||
|
||||
final EntityPlayerMP player = ctx.getServerHandler().player;
|
||||
|
||||
player.getServerWorld().addScheduledTask(() -> {
|
||||
|
||||
TileEntity tileentity = player.world.getTileEntity(message.pos);
|
||||
|
||||
if(tileentity instanceof TileEntityLectern){
|
||||
|
||||
((TileEntityLectern)tileentity).currentSpell = message.spell;
|
||||
((TileEntityLectern)tileentity).sync(); // Update other clients with the new state
|
||||
|
||||
}else{
|
||||
Wizardry.logger.warn("Received a PacketLectern, but no lectern existed at the position specified!");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class Message implements IMessage {
|
||||
|
||||
private BlockPos pos;
|
||||
private Spell spell;
|
||||
|
||||
// This constructor is required otherwise you'll get errors (used somewhere in fml through reflection)
|
||||
public Message(){}
|
||||
|
||||
public Message(BlockPos pos, Spell spell){
|
||||
this.pos = pos;
|
||||
this.spell = spell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromBytes(ByteBuf buf){
|
||||
// The order is important
|
||||
pos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
|
||||
spell = Spell.byNetworkID(buf.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(ByteBuf buf){
|
||||
buf.writeInt(pos.getX());
|
||||
buf.writeInt(pos.getY());
|
||||
buf.writeInt(pos.getZ());
|
||||
buf.writeInt(spell.networkID());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ public class WizardryPacketHandler {
|
||||
registerMessage(PacketEmitterData.class, PacketEmitterData.Message.class);
|
||||
registerMessage(PacketPossession.class, PacketPossession.Message.class);
|
||||
registerMessage(PacketConquerShrine.class, PacketConquerShrine.Message.class);
|
||||
registerMessage(PacketLectern.class, PacketLectern.Message.class);
|
||||
}
|
||||
|
||||
private static int nextPacketId = 0;
|
||||
|
||||
@@ -64,6 +64,12 @@ public final class WizardryBlocks {
|
||||
public static final Block jungle_bookshelf = placeholder();
|
||||
public static final Block acacia_bookshelf = placeholder();
|
||||
public static final Block dark_oak_bookshelf = placeholder();
|
||||
public static final Block oak_lectern = placeholder();
|
||||
public static final Block spruce_lectern = placeholder();
|
||||
public static final Block birch_lectern = placeholder();
|
||||
public static final Block jungle_lectern = placeholder();
|
||||
public static final Block acacia_lectern = placeholder();
|
||||
public static final Block dark_oak_lectern = placeholder();
|
||||
|
||||
/**
|
||||
* Sets both the registry and unlocalised names of the given block, then registers it with the given registry. Use
|
||||
@@ -110,6 +116,12 @@ public final class WizardryBlocks {
|
||||
registerBlock(registry, "jungle_bookshelf", new BlockBookshelf());
|
||||
registerBlock(registry, "acacia_bookshelf", new BlockBookshelf());
|
||||
registerBlock(registry, "dark_oak_bookshelf", new BlockBookshelf());
|
||||
registerBlock(registry, "oak_lectern", new BlockLectern());
|
||||
registerBlock(registry, "birch_lectern", new BlockLectern());
|
||||
registerBlock(registry, "spruce_lectern", new BlockLectern());
|
||||
registerBlock(registry, "jungle_lectern", new BlockLectern());
|
||||
registerBlock(registry, "acacia_lectern", new BlockLectern());
|
||||
registerBlock(registry, "dark_oak_lectern", new BlockLectern());
|
||||
|
||||
}
|
||||
|
||||
@@ -124,5 +136,6 @@ public final class WizardryBlocks {
|
||||
GameRegistry.registerTileEntity(TileEntityPlayerSaveTimed.class, new ResourceLocation(Wizardry.MODID, "player_save_timed"));
|
||||
GameRegistry.registerTileEntity(TileEntityShrineCore.class, new ResourceLocation(Wizardry.MODID, "shrine_core"));
|
||||
GameRegistry.registerTileEntity(TileEntityBookshelf.class, new ResourceLocation(Wizardry.MODID, "bookshelf"));
|
||||
GameRegistry.registerTileEntity(TileEntityLectern.class, new ResourceLocation(Wizardry.MODID, "lectern"));
|
||||
}
|
||||
}
|
||||
@@ -407,6 +407,13 @@ public final class WizardryItems {
|
||||
registerItemBlock(registry, WizardryBlocks.acacia_bookshelf);
|
||||
registerItemBlock(registry, WizardryBlocks.dark_oak_bookshelf);
|
||||
|
||||
registerItemBlock(registry, WizardryBlocks.oak_lectern);
|
||||
registerItemBlock(registry, WizardryBlocks.spruce_lectern);
|
||||
registerItemBlock(registry, WizardryBlocks.birch_lectern);
|
||||
registerItemBlock(registry, WizardryBlocks.jungle_lectern);
|
||||
registerItemBlock(registry, WizardryBlocks.acacia_lectern);
|
||||
registerItemBlock(registry, WizardryBlocks.dark_oak_lectern);
|
||||
|
||||
// Items
|
||||
|
||||
registerItem(registry, "magic_crystal", new ItemCrystal());
|
||||
|
||||
@@ -552,6 +552,9 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
return ((ForgeRegistry<Spell>)registry).getID(this);
|
||||
}
|
||||
|
||||
// N.B. You don't *have* to use the network ID for networking, metadata is consistent within a world and will work
|
||||
// fine, *however* when syncing a list/array of spells it is much more convenient to use network IDs.
|
||||
|
||||
/** Returns this spell's network ID number, similar to mod-specific entity IDs.<br>
|
||||
* <br>
|
||||
* Unlike {@link Spell#metadata()}, this is guaranteed to be sequential so is suitable for indexed lookup.
|
||||
@@ -947,7 +950,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
return spell == null ? Spells.none : spell;
|
||||
}
|
||||
|
||||
/** Gets a spell instance from its network ID. Or the {@link None} spell if no such spell exists. */
|
||||
/** Gets a spell instance from its network ID, or the {@link None} spell if no such spell exists. */
|
||||
public static Spell byNetworkID(int id){
|
||||
if(id < 0 || id >= registry.getValuesCollection().size()){
|
||||
return Spells.none;
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package electroblob.wizardry.tileentity;
|
||||
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ITickable;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/** Controls the book animations and remembers the GUI state when not in use. */
|
||||
public class TileEntityLectern extends TileEntity implements ITickable {
|
||||
|
||||
public static final double BOOK_OPEN_DISTANCE = 5;
|
||||
|
||||
private static final Random rand = new Random();
|
||||
|
||||
public int ticksExisted;
|
||||
public float pageFlip;
|
||||
public float pageFlipPrev;
|
||||
public float flipT;
|
||||
public float flipA;
|
||||
public float bookSpread;
|
||||
public float bookSpreadPrev;
|
||||
|
||||
public Spell currentSpell = Spells.none;
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
this.bookSpreadPrev = this.bookSpread;
|
||||
|
||||
EntityPlayer entityplayer = this.world.getClosestPlayer(this.pos.getX() + 0.5, this.pos.getY() + 0.5,
|
||||
this.pos.getZ() + 0.5, BOOK_OPEN_DISTANCE, false);
|
||||
|
||||
if(entityplayer != null){
|
||||
|
||||
this.bookSpread += 0.1f;
|
||||
|
||||
if(this.bookSpread < 0.5f || rand.nextInt(40) == 0){
|
||||
float f1 = this.flipT;
|
||||
while(f1 == flipT) this.flipT += (float)(rand.nextInt(4) - rand.nextInt(4));
|
||||
}
|
||||
|
||||
}else{
|
||||
this.bookSpread -= 0.1f;
|
||||
}
|
||||
|
||||
this.bookSpread = MathHelper.clamp(this.bookSpread, 0.0f, 1.0f);
|
||||
|
||||
this.ticksExisted++;
|
||||
|
||||
this.pageFlipPrev = this.pageFlip;
|
||||
float f = (this.flipT - this.pageFlip) * 0.4f;
|
||||
f = MathHelper.clamp(f, -0.2f, 0.2f);
|
||||
this.flipA += (f - this.flipA) * 0.9f;
|
||||
this.pageFlip += this.flipA;
|
||||
|
||||
}
|
||||
|
||||
/** Called to manually sync the tile entity with clients. */
|
||||
public void sync(){
|
||||
this.world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTTagCompound writeToNBT(NBTTagCompound compound){
|
||||
super.writeToNBT(compound); // Confusingly, this method both writes to the supplied compound and returns it
|
||||
compound.setInteger("spell", currentSpell.metadata());
|
||||
return compound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFromNBT(NBTTagCompound compound){
|
||||
super.readFromNBT(compound);
|
||||
currentSpell = Spell.byMetadata(compound.getInteger("spell"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final NBTTagCompound getUpdateTag(){
|
||||
return this.writeToNBT(new NBTTagCompound());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SPacketUpdateTileEntity getUpdatePacket(){
|
||||
return new SPacketUpdateTileEntity(pos, getBlockMetadata(), this.getUpdateTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt){
|
||||
readFromNBT(pkt.getNbtCompound());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package electroblob.wizardry.util;
|
||||
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/** Interface for things that have a list of spells that can be sorted using {@link SortType}. This allows
|
||||
* {@link electroblob.wizardry.client.gui.GuiButtonSpellSort GuiButtonSpellSort} to change its appearance based on the
|
||||
* current sort setting. */
|
||||
public interface ISpellSortable {
|
||||
|
||||
/** Returns the current sort type this {@code ISpellSortable} is set to sort by. */
|
||||
SortType getSortType();
|
||||
|
||||
/** Returns true if this {@code ISpellSortable} is currently set to sort in descending order, false if it is
|
||||
* set to sort in ascending order. */
|
||||
boolean isSortDescending();
|
||||
|
||||
enum SortType {
|
||||
|
||||
TIER("tier", Comparator.naturalOrder()),
|
||||
ELEMENT("element", Comparator.comparing(Spell::getElement).thenComparing(Spell::getTier)),
|
||||
ALPHABETICAL("alphabetical", Comparator.comparing(Spell::getUnlocalisedName));
|
||||
|
||||
public String name;
|
||||
public Comparator<? super Spell> comparator;
|
||||
|
||||
SortType(String name, Comparator<? super Spell> comparator){
|
||||
this.name = name;
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,6 +93,8 @@ public final class ParticleBuilder {
|
||||
public static class Type {
|
||||
/** 3D-rendered light-beam particle.<p></p><b>Defaults:</b><br>Lifetime: 1 tick<br> Colour: white */
|
||||
public static final ResourceLocation BEAM = new ResourceLocation(Wizardry.MODID,"beam");
|
||||
/** Square block face highlight particle.<p></p><b>Defaults:</b><br>Lifetime: 160 ticks<br>Colour: white */
|
||||
public static final ResourceLocation BLOCK_HIGHLIGHT = new ResourceLocation(Wizardry.MODID,"block_highlight");
|
||||
/** Helical animated 'buffing' particle.<p></p><b>Defaults:</b><br>Lifetime: 15 ticks
|
||||
* <br>Velocity: (0, 0.27, 0)<br>Colour: white */
|
||||
public static final ResourceLocation BUFF = new ResourceLocation(Wizardry.MODID,"buff");
|
||||
|
||||
Reference in New Issue
Block a user