Add bookshelves
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
package electroblob.wizardry.inventory;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.event.SpellBindEvent;
|
||||
import electroblob.wizardry.item.IWorkbenchItem;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.registry.WizardryAdvancementTriggers;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
|
||||
import electroblob.wizardry.util.WandHelper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ContainerArcaneWorkbench extends Container {
|
||||
|
||||
/** The arcane workbench tile entity associated with this container. */
|
||||
public TileEntityArcaneWorkbench tileentity;
|
||||
|
||||
public static final ResourceLocation EMPTY_SLOT_CRYSTAL = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_crystal");
|
||||
public static final ResourceLocation EMPTY_SLOT_UPGRADE = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_upgrade");
|
||||
|
||||
public static final int CRYSTAL_SLOT = 8;
|
||||
public static final int CENTRE_SLOT = 9;
|
||||
public static final int UPGRADE_SLOT = 10;
|
||||
|
||||
public static final int SLOT_RADIUS = 42;
|
||||
|
||||
public ContainerArcaneWorkbench(IInventory inventory, TileEntityArcaneWorkbench tileentity){
|
||||
|
||||
this.tileentity = tileentity;
|
||||
|
||||
ItemStack wand = tileentity.getStackInSlot(CENTRE_SLOT);
|
||||
|
||||
for(int i = 0; i < 8; i++){
|
||||
Slot slot = new SlotItemClassList(tileentity, i, -999, -999, 1, ItemSpellBook.class);
|
||||
this.addSlotToContainer(slot);
|
||||
}
|
||||
|
||||
this.addSlotToContainer(new SlotItemList(tileentity, CRYSTAL_SLOT, 13, 101, 64,
|
||||
WizardryItems.magic_crystal, WizardryItems.crystal_shard, WizardryItems.grand_crystal))
|
||||
.setBackgroundName(EMPTY_SLOT_CRYSTAL.toString());
|
||||
|
||||
this.addSlotToContainer(new SlotWorkbenchItem(tileentity, CENTRE_SLOT, 80, 64, this));
|
||||
|
||||
Set<Item> upgrades = new HashSet<>(WandHelper.getSpecialUpgrades()); // Can't be done statically.
|
||||
upgrades.add(WizardryItems.arcane_tome);
|
||||
upgrades.add(WizardryItems.armour_upgrade);
|
||||
|
||||
this.addSlotToContainer(new SlotItemList(tileentity, UPGRADE_SLOT, 147, 17, 1, upgrades.toArray(new Item[0])))
|
||||
.setBackgroundName(EMPTY_SLOT_UPGRADE.toString());
|
||||
|
||||
for(int x = 0; x < 9; x++){
|
||||
this.addSlotToContainer(new Slot(inventory, x, 8 + x * 18, 196));
|
||||
}
|
||||
|
||||
for(int y = 0; y < 3; y++){
|
||||
for(int x = 0; x < 9; x++){
|
||||
this.addSlotToContainer(new Slot(inventory, 9 + x + y * 9, 8 + x * 18, 138 + y * 18));
|
||||
}
|
||||
}
|
||||
|
||||
this.onSlotChanged(CENTRE_SLOT, wand, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInteractWith(EntityPlayer player){
|
||||
return this.tileentity.isUsableByPlayer(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the given slot in the container GUI at the given position. Intended to do the opposite of
|
||||
* {@link ContainerArcaneWorkbench#hideSlot(int, EntityPlayer)}.
|
||||
* @param index The index of the slot to show.
|
||||
* @param x The x position to put the slot in.
|
||||
* @param y The y position to put the slot in.
|
||||
*/
|
||||
private void showSlot(int index, int x, int y){
|
||||
|
||||
Slot slot = this.getSlot(index);
|
||||
slot.xPos = x;
|
||||
slot.yPos = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the given slot from the container GUI (moves it off the screen) and returns its contents to the given
|
||||
* player. If some or all of the items do not fit in the player's inventory, or if the player is null, they are
|
||||
* dropped on the floor.
|
||||
* @param index The index of the slot to hide.
|
||||
* @param player The player that is using this container.
|
||||
*/
|
||||
private void hideSlot(int index, EntityPlayer player){
|
||||
|
||||
Slot slot = this.getSlot(index);
|
||||
|
||||
// 'Removes' the slot from the container (moves it off the screen)
|
||||
slot.xPos = -999;
|
||||
slot.yPos = -999;
|
||||
|
||||
ItemStack stack = slot.getStack();
|
||||
// This doesn't cause an infinite loop because slot i can never be a SlotWandArmour. In effect, it's
|
||||
// exactly the same as shift-clicking the slot, so why re-invent the wheel?
|
||||
ItemStack remainder = this.transferStackInSlot(player, index);
|
||||
|
||||
if(remainder == ItemStack.EMPTY && stack != ItemStack.EMPTY){
|
||||
slot.putStack(ItemStack.EMPTY);
|
||||
// The second parameter is never used...
|
||||
if(player != null) player.dropItem(stack, false);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called from the central wand/armour slot when its item is changed or removed. */
|
||||
// In case I forget again and think it should have @Override: I wrote this!
|
||||
public void onSlotChanged(int slotNumber, ItemStack stack, EntityPlayer player){
|
||||
|
||||
if(slotNumber == CENTRE_SLOT){
|
||||
|
||||
if(stack.isEmpty()){
|
||||
// If the stack has been removed, hide all the spell book slots
|
||||
for(int i = 0; i < CRYSTAL_SLOT; i++){
|
||||
this.hideSlot(i, player);
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
if(stack.getItem() instanceof IWorkbenchItem){ // Should always be true here.
|
||||
|
||||
int spellSlots = ((IWorkbenchItem)stack.getItem()).getSpellSlotCount(stack);
|
||||
|
||||
int centreX = this.getSlot(CENTRE_SLOT).xPos;
|
||||
int centreY = this.getSlot(CENTRE_SLOT).yPos;
|
||||
|
||||
// Show however many spell book slots are necessary
|
||||
for(int i = 0; i < spellSlots; i++){
|
||||
|
||||
float angle = i * (2 * (float)Math.PI)/spellSlots;
|
||||
int x = centreX + Math.round(SLOT_RADIUS * MathHelper.sin(angle));
|
||||
// -cos because +y is downwards
|
||||
int y = centreY + Math.round(SLOT_RADIUS * -MathHelper.cos(angle));
|
||||
|
||||
showSlot(i, x, y);
|
||||
}
|
||||
|
||||
// Hide the rest
|
||||
for(int i = spellSlots; i < CRYSTAL_SLOT; i++){
|
||||
hideSlot(i, player);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: It only seems to be syncing correctly when a stack is put into the slot, not taken out.
|
||||
// This is because markDirty isn't called in the tileentity, I think.
|
||||
// You can simulate this using hoppers!
|
||||
this.tileentity.sync();
|
||||
}
|
||||
|
||||
// FIXME: Shift-clicking a stack of special upgrades when in the arcane workbench causes the whole stack to be
|
||||
// transferred when it should be just one (this is a bug with vanilla as well - try putting a stack of
|
||||
// bottles into a brewing stand). I have at least made it so only one gets used now, so it has no impact on
|
||||
// the game.
|
||||
@Override
|
||||
public ItemStack transferStackInSlot(EntityPlayer player, int clickedSlotId){
|
||||
|
||||
ItemStack remainder = ItemStack.EMPTY;
|
||||
Slot slot = this.inventorySlots.get(clickedSlotId);
|
||||
|
||||
if(slot != null && slot.getHasStack()){
|
||||
|
||||
ItemStack stack = slot.getStack(); // The stack that was there originally
|
||||
remainder = stack.copy(); // A copy of that stack
|
||||
|
||||
// Workbench -> inventory
|
||||
if(clickedSlotId <= UPGRADE_SLOT){
|
||||
// Tries to move the stack into the player's inventory. If this fails...
|
||||
if(!this.mergeItemStack(stack, UPGRADE_SLOT + 1, this.inventorySlots.size(), true)){
|
||||
return ItemStack.EMPTY; // ...nothing else happens.
|
||||
}
|
||||
}
|
||||
// Inventory -> workbench
|
||||
else{
|
||||
// The following logic prevents shift-clicking transferring the items to the wrong slot.
|
||||
int minSlotId = 0;
|
||||
int maxSlotId = UPGRADE_SLOT;
|
||||
|
||||
if(stack.getItem() instanceof ItemSpellBook){
|
||||
minSlotId = 0;
|
||||
maxSlotId = CRYSTAL_SLOT - 1;
|
||||
}else if(getSlot(CRYSTAL_SLOT).isItemValid(stack)){
|
||||
minSlotId = CRYSTAL_SLOT;
|
||||
maxSlotId = CRYSTAL_SLOT;
|
||||
}else if(getSlot(CENTRE_SLOT).isItemValid(stack)){
|
||||
minSlotId = CENTRE_SLOT;
|
||||
maxSlotId = CENTRE_SLOT;
|
||||
}else if(getSlot(UPGRADE_SLOT).isItemValid(stack)){
|
||||
minSlotId = UPGRADE_SLOT;
|
||||
maxSlotId = UPGRADE_SLOT;
|
||||
}else{
|
||||
// If none of the above cases were true, then the item won't fit in the workbench.
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
if(!this.mergeItemStack(stack, minSlotId, maxSlotId + 1, false)){
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if(stack.getCount() == 0){
|
||||
slot.putStack(ItemStack.EMPTY);
|
||||
}else{
|
||||
slot.onSlotChanged();
|
||||
}
|
||||
|
||||
if(stack.getCount() == remainder.getCount()){
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
slot.onTake(player, stack);
|
||||
}
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
// Overridden to stop stacks merging into 'removed' slots.
|
||||
@Override
|
||||
protected boolean mergeItemStack(ItemStack stack, int minSlotID, int maxSlotID, boolean p_75135_4_){
|
||||
|
||||
for(int i = minSlotID; i < maxSlotID; i++){
|
||||
// System.out.println(this.getSlot(i).xDisplayPosition);
|
||||
if(this.getSlot(i).xPos >= 0 && this.getSlot(i).yPos >= 0 && !this.getSlot(i).getHasStack()){
|
||||
return super.mergeItemStack(stack, minSlotID, maxSlotID, p_75135_4_);
|
||||
}
|
||||
}
|
||||
// Only returns false if none of the slots given are enabled and empty
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called (via {@link electroblob.wizardry.packet.PacketControlInput PacketControlInput}) when the apply button in
|
||||
* the arcane workbench GUI is pressed.
|
||||
*/
|
||||
// As of 2.1, for the sake of events and neatness of code, this was moved here from TileEntityArcaneWorkbench.
|
||||
// As of 4.2, the spell binding/charging/upgrading code was delegated (via IWorkbenchItem) to the items themselves.
|
||||
public void onApplyButtonPressed(EntityPlayer player){
|
||||
|
||||
if(MinecraftForge.EVENT_BUS.post(new SpellBindEvent(player, this))) return;
|
||||
|
||||
Slot centre = this.getSlot(CENTRE_SLOT);
|
||||
|
||||
if(centre.getStack().getItem() instanceof IWorkbenchItem){ // Should always be true, but no harm in checking.
|
||||
|
||||
Slot[] spellBooks = this.inventorySlots.subList(0, 8).toArray(new Slot[8]);
|
||||
|
||||
if(((IWorkbenchItem)centre.getStack().getItem())
|
||||
.onApplyButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks)){
|
||||
|
||||
if(player instanceof EntityPlayerMP){
|
||||
WizardryAdvancementTriggers.arcane_workbench.trigger((EntityPlayerMP)player, centre.getStack());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package electroblob.wizardry.inventory;
|
||||
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Container;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
public class ContainerBookshelf extends Container {
|
||||
|
||||
/** The bookshelf tile entity associated with this container. */
|
||||
public TileEntityBookshelf tileentity;
|
||||
|
||||
public ContainerBookshelf(IInventory inventory, TileEntityBookshelf tileentity){
|
||||
|
||||
this.tileentity = tileentity;
|
||||
|
||||
for(int y = 0; y < 2; y++){
|
||||
for(int x = 0; x < BlockBookshelf.SLOT_COUNT / 2; x++){
|
||||
this.addSlotToContainer(new SlotBookshelf(tileentity, x + BlockBookshelf.SLOT_COUNT / 2 * y, 35 + x * 18, 17 + y * 18, 64, ItemSpellBook.class));
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = 0; x < 9; x++){
|
||||
this.addSlotToContainer(new Slot(inventory, x, 8 + x * 18, 124));
|
||||
}
|
||||
|
||||
for(int y = 0; y < 3; y++){
|
||||
for(int x = 0; x < 9; x++){
|
||||
this.addSlotToContainer(new Slot(inventory, 9 + x + y * 9, 8 + x * 18, 66 + y * 18));
|
||||
}
|
||||
}
|
||||
|
||||
this.onSlotChanged();
|
||||
|
||||
}
|
||||
|
||||
/** Called from individual slots when their item is changed or removed. */
|
||||
public void onSlotChanged(){
|
||||
this.tileentity.sync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInteractWith(EntityPlayer player){
|
||||
return this.tileentity.isUsableByPlayer(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack transferStackInSlot(EntityPlayer player, int clickedSlotId){
|
||||
|
||||
ItemStack remainder = ItemStack.EMPTY;
|
||||
Slot slot = this.inventorySlots.get(clickedSlotId);
|
||||
|
||||
if(slot != null && slot.getHasStack()){
|
||||
|
||||
ItemStack stack = slot.getStack(); // The stack that was there originally
|
||||
remainder = stack.copy(); // A copy of that stack
|
||||
|
||||
// Bookshelf -> inventory
|
||||
if(clickedSlotId < BlockBookshelf.SLOT_COUNT){
|
||||
// Tries to move the stack into the player's inventory. If this fails...
|
||||
if(!this.mergeItemStack(stack, BlockBookshelf.SLOT_COUNT, this.inventorySlots.size(), true)){
|
||||
return ItemStack.EMPTY; // ...nothing else happens.
|
||||
}
|
||||
}
|
||||
// Inventory -> bookshelf
|
||||
else{
|
||||
|
||||
int minSlotId = 0;
|
||||
int maxSlotId = BlockBookshelf.SLOT_COUNT - 1;
|
||||
|
||||
if(!(stack.getItem() instanceof ItemSpellBook)) return ItemStack.EMPTY;
|
||||
|
||||
if(!this.mergeItemStack(stack, minSlotId, maxSlotId + 1, false)){
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if(stack.getCount() == 0){
|
||||
slot.putStack(ItemStack.EMPTY);
|
||||
}else{
|
||||
slot.onSlotChanged();
|
||||
}
|
||||
|
||||
if(stack.getCount() == remainder.getCount()){
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
slot.onTake(player, stack);
|
||||
}
|
||||
|
||||
return remainder;
|
||||
}
|
||||
|
||||
public class SlotBookshelf extends SlotItemClassList {
|
||||
|
||||
@SafeVarargs
|
||||
public SlotBookshelf(IInventory inventory, int index, int x, int y, int stackLimit, Class<? extends Item>... allowedItemClasses){
|
||||
super(inventory, index, x, y, stackLimit, allowedItemClasses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putStack(ItemStack stack){
|
||||
boolean statusChanged = this.getStack().isEmpty() != stack.isEmpty();
|
||||
super.putStack(stack);
|
||||
if(statusChanged) ContainerBookshelf.this.onSlotChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack onTake(EntityPlayer player, ItemStack stack){
|
||||
ItemStack result = super.onTake(player, stack);
|
||||
ContainerBookshelf.this.onSlotChanged();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package electroblob.wizardry.inventory;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.inventory.ContainerWorkbench;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ContainerPortableWorkbench extends ContainerWorkbench {
|
||||
|
||||
public ContainerPortableWorkbench(InventoryPlayer inventory, World world, BlockPos pos){
|
||||
|
||||
super(inventory, world, pos);
|
||||
}
|
||||
|
||||
// Overriden to stop the crafting gui from closing when there is no crafting table.
|
||||
@Override
|
||||
public boolean canInteractWith(EntityPlayer player){
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package electroblob.wizardry.inventory;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Simple extension of {@link Slot} which only accepts items from an array of item classes defined in the constructor.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
public class SlotItemClassList extends Slot {
|
||||
|
||||
private final Class<? extends Item>[] itemClasses;
|
||||
private int stackLimit;
|
||||
|
||||
@SafeVarargs
|
||||
public SlotItemClassList(IInventory inventory, int index, int x, int y, int stackLimit, Class<? extends Item>... allowedItemClasses){
|
||||
super(inventory, index, x, y);
|
||||
this.itemClasses = allowedItemClasses;
|
||||
this.stackLimit = stackLimit;
|
||||
}
|
||||
|
||||
public int getSlotStackLimit(){
|
||||
return stackLimit;
|
||||
}
|
||||
|
||||
public boolean isItemValid(ItemStack stack){
|
||||
|
||||
for(Class<? extends Item> itemClass : itemClasses){
|
||||
if(itemClass.isAssignableFrom(stack.getItem().getClass())){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package electroblob.wizardry.inventory;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* Simple extension of {@link Slot} which only accepts items from an array of items defined in the constructor.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
public class SlotItemList extends Slot {
|
||||
|
||||
private final Item[] items;
|
||||
private int stackLimit;
|
||||
|
||||
public SlotItemList(IInventory inventory, int index, int x, int y, int stackLimit, Item... allowedItems){
|
||||
super(inventory, index, x, y);
|
||||
this.items = allowedItems;
|
||||
this.stackLimit = stackLimit;
|
||||
}
|
||||
|
||||
public int getSlotStackLimit(){
|
||||
return stackLimit;
|
||||
}
|
||||
|
||||
public boolean isItemValid(ItemStack stack){
|
||||
|
||||
for(Item item : items){
|
||||
if(stack.getItem() == item){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package electroblob.wizardry.inventory;
|
||||
|
||||
import electroblob.wizardry.item.IWorkbenchItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* The central wand/armour/scroll slot in the arcane workbench GUI.
|
||||
*
|
||||
* @author Electroblob
|
||||
* @since Wizardry 1.0
|
||||
*/
|
||||
public class SlotWorkbenchItem extends Slot {
|
||||
|
||||
private ContainerArcaneWorkbench container;
|
||||
|
||||
public SlotWorkbenchItem(IInventory inventory, int index, int x, int y, ContainerArcaneWorkbench container){
|
||||
super(inventory, index, x, y);
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putStack(ItemStack stack){
|
||||
super.putStack(stack);
|
||||
this.container.onSlotChanged(slotNumber, stack, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack onTake(EntityPlayer player, ItemStack stack){
|
||||
ItemStack result = super.onTake(player, stack);
|
||||
this.container.onSlotChanged(slotNumber, ItemStack.EMPTY, player);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotStackLimit(){
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(ItemStack stack){
|
||||
return stack.getItem() instanceof IWorkbenchItem && ((IWorkbenchItem)stack.getItem()).canPlace(stack);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user