package pneumaticCraft.common.tileentity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemDye;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidHandler;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.oredict.OreDictionary;
import pneumaticCraft.api.IHeatExchangerLogic;
import pneumaticCraft.api.PneumaticRegistry;
import pneumaticCraft.api.tileentity.IHeatExchanger;
import pneumaticCraft.common.AchievementHandler;
import pneumaticCraft.common.block.Blockss;
import pneumaticCraft.common.fluid.FluidPlastic;
import pneumaticCraft.common.fluid.Fluids;
import pneumaticCraft.common.item.Itemss;
import pneumaticCraft.common.network.GuiSynced;
import pneumaticCraft.common.thirdparty.computercraft.LuaMethod;
import pneumaticCraft.lib.PneumaticValues;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class TileEntityPlasticMixer extends TileEntityBase implements IFluidHandler, ISidedInventory, IHeatExchanger,
IRedstoneControlled{
private final FluidTank tank = new FluidTank(PneumaticValues.NORMAL_TANK_CAPACITY);
private final ItemStack[] inventory = new ItemStack[9];
private int lastTickInventoryStacksize;
private static int BASE_TEMPERATURE = FluidRegistry.WATER.getTemperature();
@GuiSynced
private final IHeatExchangerLogic hullLogic = PneumaticRegistry.getInstance().getHeatExchangerLogic();
@GuiSynced
private final IHeatExchangerLogic itemLogic = PneumaticRegistry.getInstance().getHeatExchangerLogic();
@GuiSynced
public int selectedPlastic = -1;
@GuiSynced
private int redstoneMode;
@GuiSynced
public boolean lockSelection;
@GuiSynced
public int[] dyeBuffers = new int[3];
public static final int DYE_PER_DYE = 0xFF * 10;
public static final int DYE_BUFFER_MAX = 0xFF * 2 * PneumaticValues.NORMAL_TANK_CAPACITY / 1000;
public static final String[] DYES = {"dyeBlack", "dyeRed", "dyeGreen", "dyeBrown", "dyeBlue", "dyePurple", "dyeCyan", "dyeLightGray", "dyeGray", "dyePink", "dyeLime", "dyeYellow", "dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite"};
private static final int[] SLOTS = {0, 1, 2, 3, 4, 5, 6, 7, 8};
public static final int INV_INPUT = 4, INV_OUTPUT = 5, INV_DYE_RED = 6, INV_DYE_GREEN = 7, INV_DYE_BLUE = 8;
public TileEntityPlasticMixer(){
super(0, 1, 2, 3);
hullLogic.addConnectedExchanger(itemLogic);
hullLogic.setThermalCapacity(100);
}
@SideOnly(Side.CLIENT)
public IHeatExchangerLogic getLogic(int index){
switch(index){
case 0:
return hullLogic;
case 1:
return itemLogic;
}
throw new IllegalArgumentException("Invalid index: " + index);
}
@SideOnly(Side.CLIENT)
public IFluidTank getFluidTank(){
return tank;
}
@Override
public void updateEntity(){
super.updateEntity();
if(!worldObj.isRemote) {
refillDyeBuffers();
itemLogic.update();
if(worldObj.getTotalWorldTime() % 20 == 0) {//We don't need to run _that_ often.
if(inventory[INV_INPUT] != null && inventory[INV_INPUT].stackSize > lastTickInventoryStacksize) {
int stackIncrease = inventory[INV_INPUT].stackSize - lastTickInventoryStacksize;
double ratio = (double)inventory[INV_INPUT].stackSize / (inventory[INV_INPUT].stackSize + stackIncrease);
itemLogic.setTemperature((int)(ratio * itemLogic.getTemperature() + (1 - ratio) * BASE_TEMPERATURE));
} else if(inventory[INV_INPUT] == null) {
itemLogic.setTemperature(BASE_TEMPERATURE);
}
if(itemLogic.getTemperature() >= PneumaticValues.PLASTIC_MIXER_MELTING_TEMP) {
FluidStack moltenPlastic = new FluidStack(Fluids.plastic, inventory[INV_INPUT].stackSize * 1000);
int maxFill = fill(ForgeDirection.UNKNOWN, moltenPlastic, false) / 1000;
if(maxFill > 0) {
inventory[INV_INPUT].stackSize -= maxFill;
if(inventory[INV_INPUT].stackSize <= 0) inventory[INV_INPUT] = null;
fill(ForgeDirection.UNKNOWN, new FluidStack(moltenPlastic, maxFill * 1000), true);
}
}
lastTickInventoryStacksize = inventory[INV_INPUT] != null ? inventory[INV_INPUT].stackSize : 0;
itemLogic.setThermalCapacity(inventory[INV_INPUT] == null ? 0 : inventory[INV_INPUT].stackSize);
}
if(tank.getFluid() != null && selectedPlastic >= 0 && redstoneAllows()) {
ItemStack solidifiedStack = new ItemStack(Itemss.plastic, tank.getFluid().amount / 1000, selectedPlastic);
if(solidifiedStack.stackSize > 0) {
solidifiedStack.stackSize = 1;
if(inventory[INV_OUTPUT] == null) {
solidifiedStack.stackSize = useDye(solidifiedStack.stackSize);
if(solidifiedStack.stackSize > 0) {
inventory[INV_OUTPUT] = solidifiedStack;
tank.drain(inventory[INV_OUTPUT].stackSize * 1000, true);
sendDescriptionPacket();
}
} else if(solidifiedStack.isItemEqual(inventory[INV_OUTPUT])) {
int solidifiedItems = Math.min(64 - inventory[INV_OUTPUT].stackSize, solidifiedStack.stackSize);
solidifiedItems = useDye(solidifiedItems);
inventory[INV_OUTPUT].stackSize += solidifiedItems;
tank.drain(solidifiedItems * 1000, true);
sendDescriptionPacket();
}
}
}
if(!lockSelection) selectedPlastic = -1;
if(redstoneMode == 3) selectedPlastic = poweredRedstone;
}
}
private void refillDyeBuffers(){
for(int i = 0; i < 3; i++) {
if(getStackInSlot(INV_DYE_RED + i) != null && dyeBuffers[i] <= DYE_BUFFER_MAX - DYE_PER_DYE) {
decrStackSize(INV_DYE_RED + i, 1);
dyeBuffers[i] += DYE_PER_DYE;
}
}
}
private int useDye(int maxItems){
int desiredColor = ItemDye.field_150922_c[selectedPlastic];
if(selectedPlastic == 15) return maxItems;//Converting to white plastic is free.
for(int i = 0; i < 3; i++) {
int colorComponent = desiredColor >> 8 * i & 0xFF;
colorComponent = 0xFF - colorComponent;//Invert, because we start out with white, and we darken the plastic.
if(colorComponent > 0) {
maxItems = Math.min(maxItems, dyeBuffers[i] / colorComponent);
}
}
for(int i = 0; i < 3; i++) {
int colorComponent = desiredColor >> 8 * i & 0xFF;
colorComponent = 0xFF - colorComponent;//Invert, because we start out with white, and we darken the plastic.
dyeBuffers[i] -= colorComponent * maxItems;
}
return maxItems;
}
@Override
public void readFromNBT(NBTTagCompound tag){
super.readFromNBT(tag);
readInventoryFromNBT(tag, inventory, "Items");
lastTickInventoryStacksize = tag.getInteger("lastTickInventoryStacksize");
selectedPlastic = tag.getInteger("selectedPlastic");
lockSelection = tag.getBoolean("lockSelection");
dyeBuffers[0] = tag.getInteger("dyeBuffer0");
dyeBuffers[1] = tag.getInteger("dyeBuffer1");
dyeBuffers[2] = tag.getInteger("dyeBuffer2");
redstoneMode = tag.getInteger("redstoneMode");
itemLogic.readFromNBT(tag.getCompoundTag("itemLogic"));
}
@Override
public void writeToNBT(NBTTagCompound tag){
super.writeToNBT(tag);
writeInventoryToNBT(tag, inventory, "Items");
tag.setInteger("lastTickInventoryStacksize", lastTickInventoryStacksize);
tag.setInteger("selectedPlastic", selectedPlastic);
tag.setBoolean("lockSelection", lockSelection);
tag.setInteger("dyeBuffer0", dyeBuffers[0]);
tag.setInteger("dyeBuffer1", dyeBuffers[1]);
tag.setInteger("dyeBuffer2", dyeBuffers[2]);
tag.setInteger("redstoneMode", redstoneMode);
NBTTagCompound heatTag = new NBTTagCompound();
itemLogic.writeToNBT(heatTag);
tag.setTag("itemLogic", heatTag);
}
@Override
public void readFromPacket(NBTTagCompound tag){
super.readFromPacket(tag);
tank.setFluid(null);
tank.readFromNBT(tag.getCompoundTag("fluid"));
}
@Override
public void writeToPacket(NBTTagCompound tag){
super.writeToPacket(tag);
NBTTagCompound tankTag = new NBTTagCompound();
tank.writeToNBT(tankTag);
tag.setTag("fluid", tankTag);
}
/******************* Tank methods *******************/
@Override
public int fill(ForgeDirection from, FluidStack resource, boolean doFill){
if(resource == null || !Fluids.areFluidsEqual(resource.getFluid(), Fluids.plastic)) return 0;
int fillingAmount = Math.min(tank.getCapacity() - tank.getFluidAmount(), resource.amount);
if(doFill && fillingAmount > 0) {
tank.setFluid(FluidPlastic.mixFluid(tank.getFluid(), new FluidStack(resource, fillingAmount)));
sendDescriptionPacket();
}
return fillingAmount;
}
@Override
public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain){
if(resource == null || Fluids.areFluidsEqual(resource.getFluid(), Fluids.plastic)) return drain(from, PneumaticValues.MAX_DRAIN, doDrain);
else return null;
}
@Override
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain){
FluidStack drained = tank.drain(Math.min(PneumaticValues.MAX_DRAIN, maxDrain), doDrain);
if(doDrain && drained != null && drained.getFluid() != null) sendDescriptionPacket();
return drained;
}
@Override
public boolean canFill(ForgeDirection from, Fluid fluid){
return Fluids.areFluidsEqual(fluid, Fluids.plastic);
}
@Override
public boolean canDrain(ForgeDirection from, Fluid fluid){
return canFill(from, fluid);
}
@Override
public FluidTankInfo[] getTankInfo(ForgeDirection from){
return new FluidTankInfo[]{tank.getInfo()};
}
/****************** End Tank methods *******************/
/****************** IInventory *********************/
@Override
public void openInventory(){}
@Override
public void closeInventory(){}
/**
* Returns the number of slots in the inventory.
*/
@Override
public int getSizeInventory(){
return inventory.length;
}
/**
* Returns the stack in slot i
*/
@Override
public ItemStack getStackInSlot(int slot){
return inventory[slot];
}
@Override
public ItemStack decrStackSize(int slot, int amount){
ItemStack itemStack = getStackInSlot(slot);
if(itemStack != null) {
if(itemStack.stackSize <= amount) {
setInventorySlotContents(slot, null);
} else {
itemStack = itemStack.splitStack(amount);
if(itemStack.stackSize == 0) {
setInventorySlotContents(slot, null);
}
}
}
return itemStack;
}
@Override
public ItemStack getStackInSlotOnClosing(int slot){
ItemStack itemStack = getStackInSlot(slot);
if(itemStack != null) {
setInventorySlotContents(slot, null);
}
return itemStack;
}
@Override
public void setInventorySlotContents(int slot, ItemStack itemStack){
inventory[slot] = itemStack;
if(itemStack != null && itemStack.stackSize > getInventoryStackLimit()) {
itemStack.stackSize = getInventoryStackLimit();
}
}
@Override
public String getInventoryName(){
return Blockss.plasticMixer.getUnlocalizedName();
}
@Override
public int getInventoryStackLimit(){
return 64;
}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack){
if(itemstack == null) return true;
switch(i){
case INV_INPUT:
return itemstack.getItem() == Itemss.plastic;
case INV_OUTPUT:
return false;
case INV_DYE_RED:
return getDyeIndex(itemstack) == 1;
case INV_DYE_GREEN:
return getDyeIndex(itemstack) == 2;
case INV_DYE_BLUE:
return getDyeIndex(itemstack) == 4;
default:
return itemstack.getItem() == Itemss.machineUpgrade;
}
}
@Override
public boolean hasCustomInventoryName(){
return false;
}
@Override
public boolean isUseableByPlayer(EntityPlayer var1){
return isGuiUseableByPlayer(var1);
}
@Override
public IHeatExchangerLogic getHeatExchangerLogic(ForgeDirection side){
return hullLogic;
}
public static int getDyeIndex(ItemStack stack){
int[] ids = OreDictionary.getOreIDs(stack);
for(int id : ids) {
String name = OreDictionary.getOreName(id);
for(int i = 0; i < DYES.length; i++) {
if(DYES[i].equals(name)) return i;
}
}
return -1;
}
@Override
public int[] getAccessibleSlotsFromSide(int side){
return SLOTS;
}
@Override
public boolean canInsertItem(int slot, ItemStack stack, int side){
return isItemValidForSlot(slot, stack);
}
@Override
public boolean canExtractItem(int slot, ItemStack stack, int side){
return slot == INV_OUTPUT;
}
@Override
public void handleGUIButtonPress(int guiID, EntityPlayer player){
super.handleGUIButtonPress(guiID, player);
if(guiID == 0) {
if(++redstoneMode > 3) {
redstoneMode = 0;
}
} else if(guiID >= 1 && guiID < 17) {
if(selectedPlastic != guiID) {
selectedPlastic = guiID - 1;
if(tank.getFluidAmount() >= 1000) {
AchievementHandler.giveAchievement(player, new ItemStack(Itemss.plastic));
}
} else {
selectedPlastic = -1;
}
} else if(guiID == 17) {
lockSelection = !lockSelection;
}
}
@Override
public int getRedstoneMode(){
return redstoneMode;
}
@Override
public boolean redstoneAllows(){
return redstoneMode == 3 ? true : super.redstoneAllows();
}
@Override
protected void addLuaMethods(){
super.addLuaMethods();
luaMethods.add(new LuaMethod("selectColor"){
@Override
public Object[] call(Object[] args) throws Exception{
if(args.length == 1) {
int selection = ((Double)args[0]).intValue();
if(selection >= 0 && selection <= 16) {
selectedPlastic = selection - 1;
return null;
} else {
throw new IllegalArgumentException("selectColor method only accepts a value ranging from 0-16. The value passed was: " + selection);
}
} else {
throw new IllegalArgumentException("selectColor method requires 1 argument (int color index, with 0 being no color");
}
}
});
}
}