/*******************************************************************************
* Copyright (c) 2013 Aroma1997.
* All rights reserved. This program and other files related to this program are
* licensed with a extended GNU General Public License v. 3
* License informations are at:
* https://github.com/Aroma1997/CompactWindmills/blob/master/license.txt
******************************************************************************/
package aroma1997.compactwindmills;
import ic2.api.energy.event.EnergyTileLoadEvent;
import ic2.api.energy.event.EnergyTileUnloadEvent;
import ic2.api.energy.tile.IEnergySource;
import ic2.api.tile.IWrenchable;
import java.util.Random;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.ForgeDirection;
import aroma1997.core.client.inventories.GUIContainer;
import aroma1997.core.inventories.AromaContainer;
import aroma1997.core.inventories.ContainerBasic;
import aroma1997.core.inventories.ISpecialInventory;
import aroma1997.core.items.wrench.IAromaWrenchable;
import aroma1997.core.log.LogHelper;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
/**
*
* @author Aroma1997
*
*/
public class TileEntityWindmill extends TileEntity implements IEnergySource, IWrenchable, ISpecialInventory, IAromaWrenchable {
public TileEntityWindmill() {
this(WindType.ELV);
}
public TileEntityWindmill(WindType type) {
super();
this.type = type;
tick = random.nextInt(CompactWindmills.updateTick);
inventoryContent = new ItemStack[1];
}
private static int getNonAirBlocks(World world, int x, int y, int z, WindType type) {
int nonAirBlocks = 0;
int radius = type.checkRadius;
// This is the radius of the Windmill, where it detects, if there is air
// or not
for (int xTest = - radius; xTest <= radius; xTest++) {
for (int yTest = - radius; yTest <= radius; yTest++) {
for (int zTest = - radius; zTest <= radius; zTest++) {
// This will check if the block is air
if (! world.isAirBlock(x + xTest, y + yTest, z + zTest)) {
nonAirBlocks++;
}
}
}
}
return nonAirBlocks - type.checkRadius - 1;
}
private static float getWeather(World world) {
if (world.isThundering()) {
return 1.5F;
}
if (world.isRaining()) {
return 1.2F;
}
return 1.0F;
}
private Random random = new Random();
private WindType type;
private boolean initialized;
private int tick;
private boolean compatibilityMode;
private int output;
private ItemStack[] inventoryContent;
private short facing = 2;
private short prevFacing = 2;
@Override
public ItemStack decrStackSize(int par1, int par2) {
if (inventoryContent[par1] != null) {
ItemStack itemstack;
if (inventoryContent[par1].stackSize <= par2) {
itemstack = inventoryContent[par1];
inventoryContent[par1] = null;
markDirty();
return itemstack;
}
else {
itemstack = inventoryContent[par1].splitStack(par2);
if (inventoryContent[par1].stackSize == 0) {
inventoryContent[par1] = null;
}
markDirty();
return itemstack;
}
}
else {
return null;
}
}
public ItemStack[] getContents() {
return inventoryContent;
}
@Override
public Packet getDescriptionPacket() {
NBTTagCompound nbtTag = new NBTTagCompound();
writeToNBT(nbtTag);
return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 1, nbtTag);
}
@Override
public short getFacing() {
return facing;
}
@Override
public int getInventoryStackLimit() {
return 1;
}
public int getOutputUntilNexttTick() {
return output;
}
@Override
public int getSizeInventory() {
return 1;
}
@Override
public ItemStack getStackInSlot(int slot) {
return inventoryContent[slot];
}
@Override
public ItemStack getStackInSlotOnClosing(int var1) {
if (inventoryContent[var1] != null) {
ItemStack var2 = inventoryContent[var1];
inventoryContent[var1] = null;
return var2;
}
else {
return null;
}
}
public WindType getType() {
return type;
}
@Override
public ItemStack getWrenchDrop(EntityPlayer entityPlayer) {
return new ItemStack(CompactWindmills.windMill, 1, type.ordinal());
}
@Override
public float getWrenchDropRate() {
return 1.0F;
}
@Override
public void invalidate() {
if (!worldObj.isRemote) {
EnergyTileUnloadEvent unloadEvent = new EnergyTileUnloadEvent(this);
MinecraftForge.EVENT_BUS.post(unloadEvent);
}
super.invalidate();
}
@Override
public boolean isItemValidForSlot(int slot, ItemStack itemStack) {
if (itemStack == null) {
return false;
}
if (itemStack.getItem() instanceof IItemRotor) {
IItemRotor rotor = (IItemRotor) itemStack.getItem();
return rotor.doesRotorFitInWindmill(type);
}
return false;
}
@Override
public boolean isUseableByPlayer(EntityPlayer entityplayer) {
return true;
}
@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity packet) {
readFromNBT(packet.func_148857_g());
}
@Override
public void readFromNBT(NBTTagCompound nBTTagCompound) {
super.readFromNBT(nBTTagCompound);
NBTTagList nBTTagList = nBTTagCompound.getTagList("Items", new NBTTagCompound().getId());
inventoryContent = new ItemStack[getSizeInventory()];
for (int i = 0; i < nBTTagList.tagCount(); i++) {
NBTTagCompound nBTTagCompoundTemp = nBTTagList.getCompoundTagAt(i);
int slotNumb = nBTTagCompoundTemp.getByte("Slot") & 0xff;
if (slotNumb >= 0 && slotNumb < inventoryContent.length) {
inventoryContent[slotNumb] = ItemStack.loadItemStackFromNBT(nBTTagCompoundTemp);
}
}
prevFacing = facing = nBTTagCompound.getShort("facing");
}
@Override
public void setFacing(short facing) {
if (facing == 0) {
return;
}
this.facing = facing;
LogHelper.debugLog("Setting Windmill to facing:" + facing);
if (prevFacing != facing) {
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
prevFacing = facing;
worldObj.addBlockEvent(xCoord, yCoord, zCoord, getBlockType(), 0, this.facing);
}
@Override
public void setInventorySlotContents(int i, ItemStack itemstack) {
inventoryContent[i] = itemstack;
if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) {
itemstack.stackSize = getInventoryStackLimit();
}
markDirty();
}
private boolean damageRotor = false;
private int setOutput(World world, int x, int y, int z) {
int nonAirBlocks = getNonAirBlocks(world, x, y, z, type);
float weather = getWeather(world);
float totalEfficiency = Math.min(1.0F, (y - 64 - nonAirBlocks / type.checkRadius) / 37.5F) * weather;
float energy = type.output * totalEfficiency;
if (! CompactWindmills.vanillaIC2Stuff) {
energy *= tickRotor();
}
else {
energy *= 0.5F + random.nextFloat() / 2;
}
if ((int) energy > type.output) {
return type.output;
}
if ((int) energy <= 0) {
return 0;
}
return (int) energy;
}
private float tickRotor() {
if (inventoryContent[0] != null && inventoryContent[0].getItem() instanceof IItemRotor) {
IItemRotor rotor = (IItemRotor) inventoryContent[0].getItem();
if (worldObj.isRemote) {
return rotor.getEfficiency();
}
rotor.tickRotor(inventoryContent[0], this, worldObj);
if (!rotor.isInfinite() && damageRotor) {
if ((inventoryContent[0].getItemDamage() + CompactWindmills.updateTick) > inventoryContent[0].getMaxDamage()) {
inventoryContent[0] = null;
}
else {
int damage = inventoryContent[0].getItemDamage() + CompactWindmills.updateTick;
inventoryContent[0].setItemDamage(damage);
}
markDirty();
}
damageRotor = false;
return rotor.getEfficiency();
}
return 0.0F;
}
@Override
public void updateEntity() {
if (compatibilityMode) {
worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord,
type.ordinal(), 0);
compatibilityMode = false;
}
if (! initialized && worldObj != null) {
if (worldObj.isRemote) {
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
else {
EnergyTileLoadEvent loadEvent = new EnergyTileLoadEvent(this);
MinecraftForge.EVENT_BUS.post(loadEvent);
}
initialized = true;
}
if (tick-- == 0) {
output = setOutput(worldObj, xCoord, yCoord, zCoord);
tick = CompactWindmills.updateTick;
}
}
@Override
public boolean wrenchCanRemove(EntityPlayer entityPlayer) {
return true;
}
@Override
public boolean wrenchCanSetFacing(EntityPlayer entityPlayer, int side) {
return facing != side && side != 0;
}
@Override
public void writeToNBT(NBTTagCompound nBTTagCompound) {
super.writeToNBT(nBTTagCompound);
NBTTagList nBTTagList = new NBTTagList();
for (int i = 0; i < inventoryContent.length; i++) {
if (inventoryContent[i] != null) {
NBTTagCompound nBTTagCompoundTemp = new NBTTagCompound();
nBTTagCompoundTemp.setByte("Slot", (byte) i);
inventoryContent[i].writeToNBT(nBTTagCompoundTemp);
nBTTagList.appendTag(nBTTagCompoundTemp);
}
}
nBTTagCompound.setTag("Items", nBTTagList);
nBTTagCompound.setShort("facing", facing);
}
public IItemRotor getRotor() {
if (inventoryContent[0] != null
&& inventoryContent[0].getItem() instanceof IItemRotor) {
return (IItemRotor) inventoryContent[0].getItem();
}
return null;
}
@Override
public double getOfferedEnergy() {
return this.getOutputUntilNexttTick();
}
@Override
public void drawEnergy(double amount) {
if (amount != 0) {
damageRotor = true;
}
}
@Override
public void onChunkUnload() {
if (!worldObj.isRemote) {
EnergyTileUnloadEvent unloadEvent = new EnergyTileUnloadEvent(this);
MinecraftForge.EVENT_BUS.post(unloadEvent);
}
super.onChunkUnload();
}
@Override
public Slot getSlot(int slot, int index, int x, int y) {
return new SlotWindmill(this, index, x, y, type);
}
@Override
@SideOnly(Side.CLIENT)
public void drawGuiContainerForegroundLayer(GUIContainer gui, ContainerBasic container,
int par1, int par2) {
gui.getFontRender().drawString("Rotor:", 40, 14, 0x404040);
gui.getFontRender().drawSplitString(StatCollector.translateToLocalFormatted("info.compactwindmills:gui.output",
"" + getOutputUntilNexttTick()), 95, 10, 70, 0x404040);
}
@Override
@SideOnly(Side.CLIENT)
public void drawGuiContainerBackgroundLayer(GUIContainer gui, ContainerBasic container,
float f, int i, int j) {
}
@Override
public AromaContainer getContainer(EntityPlayer player, int i) {
return new ContainerBasic(player.inventory, this);
}
@Override
public boolean emitsEnergyTo(TileEntity receiver, ForgeDirection direction) {
return true;
}
@Override
public String getInventoryName() {
return type.getUnlocalizedName() + ".name";
}
@Override
public boolean hasCustomInventoryName() {
return false;
}
@Override
public void openInventory() {
}
@Override
public void closeInventory() {
}
@SideOnly(Side.CLIENT)
@Override
public double getMaxRenderDistanceSquared()
{
return super.getMaxRenderDistanceSquared() * 16;
}
@Override
public void markDirty() {
super.markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
@Override
public boolean onWrenchUsed(ItemStack wrench, EntityPlayer player,
ForgeDirection side) {
if (wrenchCanSetFacing(player, (side.ordinal() + 2) % 6)) {
setFacing((short) ((side.ordinal() + 2) % 6));
return true;
}
return false;
}
@Override
public boolean canPickup(ItemStack wrench, EntityPlayer player,
ForgeDirection side) {
return true;
}
@Override
public ItemStack shouldBeExact() {
return getWrenchDrop(null);
}
@Override
public boolean receiveClientEvent(int arg, int value) {
if (arg == 0) {
facing = (short) value;
return true;
}
return false;
}
@Override
public int getSourceTier() {
return type.ordinal();
}
}