package shedar.mods.ic2.nuclearcontrol.tileentities; import ic2.api.network.INetworkClientTileEntityEventListener; import ic2.api.network.INetworkDataProvider; import ic2.api.network.INetworkUpdateListener; import ic2.api.tile.IWrenchable; import ic2.core.IC2; import ic2.core.network.ClientModifiable; import ic2.core.network.NetworkManager; import java.util.ArrayList; import java.util.List; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.Facing; import net.minecraftforge.common.util.Constants; import shedar.mods.ic2.nuclearcontrol.IC2NuclearControl; import shedar.mods.ic2.nuclearcontrol.IRotation; import shedar.mods.ic2.nuclearcontrol.ISlotItemFilter; import shedar.mods.ic2.nuclearcontrol.ITextureHelper; import shedar.mods.ic2.nuclearcontrol.api.*; import shedar.mods.ic2.nuclearcontrol.blocks.subblocks.RangeTrigger; import shedar.mods.ic2.nuclearcontrol.items.ItemUpgrade; import shedar.mods.ic2.nuclearcontrol.panel.CardWrapperImpl; import shedar.mods.ic2.nuclearcontrol.utils.BlockDamages; import cpw.mods.fml.common.FMLCommonHandler; public class TileEntityRangeTrigger extends TileEntity implements ISlotItemFilter, INetworkDataProvider, INetworkUpdateListener, IWrenchable, ITextureHelper, IRotation, IInventory, INetworkClientTileEntityEventListener { public static final int SLOT_CARD = 0; public static final int SLOT_UPGRADE = 1; private static final int LOCATION_RANGE = 8; private static final int STATE_UNKNOWN = -1; private static final int STATE_PASSIVE = 0; private static final int STATE_ACTIVE = 1; protected int updateTicker; protected int tickRate; protected boolean init; private ItemStack inventory[]; @ClientModifiable private ItemStack card; private int prevRotation; public int rotation; private short prevFacing; public short facing; private int prevOnFire; private int onFire; private boolean prevInvertRedstone; @ClientModifiable private boolean invertRedstone; private double prevLevelStart; @ClientModifiable public double levelStart; private double prevLevelEnd; @ClientModifiable public double levelEnd; @Override public short getFacing() { return (short) Facing.oppositeSide[facing]; } @Override public void setFacing(short f) { setSide((short) Facing.oppositeSide[f]); } public boolean isInvertRedstone() { return invertRedstone; } public void setInvertRedstone(boolean value) { invertRedstone = value; if (prevInvertRedstone != value) { //worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord)); worldObj.notifyBlockChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord)); IC2.network.get().updateTileEntityField(this, "invertRedstone"); } prevInvertRedstone = value; } private void setCard(ItemStack value) { card = value; IC2.network.get().updateTileEntityField(this, "card"); } private void setSide(short f) { facing = f; if(init && prevFacing != f) ((NetworkManager)IC2.network.get()).updateTileEntityField(this, "facing"); prevFacing = f; } @Override public void onNetworkUpdate(String field) { if (field.equals("facing") && prevFacing != facing) { worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); prevFacing = facing; } else if (field.equals("card")) { inventory[SLOT_CARD] = card; } else if (field.equals("rotation") && prevRotation != rotation) { worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); prevRotation = rotation; } else if (field.equals("onFire") && prevOnFire != onFire) { worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord)); prevOnFire = onFire; } else if (field.equals("invertRedstone") && prevInvertRedstone != invertRedstone) { worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord)); prevInvertRedstone = invertRedstone; } } @Override public void onNetworkEvent(EntityPlayer entityplayer, int i) { if (i < 0) { switch (i) { case -1: setInvertRedstone(false); break; case -2: setInvertRedstone(true); break; default: break; } } } public void setOnFire(int f) { onFire = f; if (prevOnFire != f) { IC2.network.get().updateTileEntityField(this, "onFire"); } prevOnFire = onFire; } public void setLevelStart(double start) { levelStart = start; if (prevLevelStart != start) { IC2.network.get().updateTileEntityField(this, "levelStart"); } prevLevelStart = levelStart; } public void setLevelEnd(double end) { levelEnd = end; if (prevLevelEnd != end) { IC2.network.get().updateTileEntityField(this, "levelEnd"); } prevLevelEnd = levelEnd; } public int getOnFire() { return onFire; } public TileEntityRangeTrigger() { super(); inventory = new ItemStack[2];// card + range upgrades card = null; init = false; tickRate = IC2NuclearControl.instance.rangeTriggerRefreshPeriod; updateTicker = tickRate; facing = 0; prevFacing = 0; prevRotation = 0; rotation = 0; onFire = prevOnFire = 0; prevInvertRedstone = invertRedstone = false; levelStart = 10000000; levelEnd = 9000000; } @Override public List<String> getNetworkedFields() { List<String> list = new ArrayList<String>(7); list.add("facing"); list.add("rotation"); list.add("card"); list.add("onFire"); list.add("invertRedstone"); list.add("levelStart"); list.add("levelEnd"); return list; } protected void initData() { if (!worldObj.isRemote) { worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord)); } init = true; } @Override public void updateEntity() { if (!init) { initData(); } if (!worldObj.isRemote) { if (updateTicker-- > 0) return; updateTicker = tickRate; markDirty(); } super.updateEntity(); } @Override public void readFromNBT(NBTTagCompound nbttagcompound) { super.readFromNBT(nbttagcompound); prevRotation = rotation = nbttagcompound.getInteger("rotation"); prevFacing = facing = nbttagcompound.getShort("facing"); prevInvertRedstone = invertRedstone = nbttagcompound.getBoolean("invert"); levelStart = nbttagcompound.getDouble("levelStart"); levelEnd = nbttagcompound.getDouble("levelEnd"); NBTTagList nbttaglist = nbttagcompound.getTagList("Items", Constants.NBT.TAG_COMPOUND); inventory = new ItemStack[getSizeInventory()]; for (int i = 0; i < nbttaglist.tagCount(); i++) { NBTTagCompound compound = nbttaglist.getCompoundTagAt(i); byte slotNum = compound.getByte("Slot"); if (slotNum >= 0 && slotNum < inventory.length) { inventory[slotNum] = ItemStack.loadItemStackFromNBT(compound); if (slotNum == SLOT_CARD) { card = inventory[slotNum]; } } } markDirty(); } @Override public void invalidate() { super.invalidate(); } @Override public void writeToNBT(NBTTagCompound nbttagcompound) { super.writeToNBT(nbttagcompound); nbttagcompound.setShort("facing", facing); nbttagcompound.setInteger("rotation", rotation); nbttagcompound.setBoolean("invert", isInvertRedstone()); nbttagcompound.setDouble("levelStart", levelStart); nbttagcompound.setDouble("levelEnd", levelEnd); NBTTagList nbttaglist = new NBTTagList(); for (int i = 0; i < inventory.length; i++) { if (inventory[i] != null) { NBTTagCompound compound = new NBTTagCompound(); compound.setByte("Slot", (byte) i); inventory[i].writeToNBT(compound); nbttaglist.appendTag(compound); } } nbttagcompound.setTag("Items", nbttaglist); } @Override public int getSizeInventory() { return inventory.length; } @Override public ItemStack getStackInSlot(int slotNum) { return inventory[slotNum]; } @Override public ItemStack decrStackSize(int slotNum, int amount) { if (inventory[slotNum] != null) { if (inventory[slotNum].stackSize <= amount) { ItemStack itemStack = inventory[slotNum]; inventory[slotNum] = null; if (slotNum == SLOT_CARD) setCard(null); return itemStack; } ItemStack taken = inventory[slotNum].splitStack(amount); if (inventory[slotNum].stackSize == 0) { inventory[slotNum] = null; if (slotNum == SLOT_CARD) setCard(null); } return taken; } return null; } @Override public ItemStack getStackInSlotOnClosing(int var1) { return null; } @Override public void setInventorySlotContents(int slotNum, ItemStack itemStack) { inventory[slotNum] = itemStack; if (slotNum == SLOT_CARD) setCard(itemStack); if (itemStack != null && itemStack.stackSize > getInventoryStackLimit()) { itemStack.stackSize = getInventoryStackLimit(); } } @Override public String getInventoryName() { return "block.RangeTrigger"; } @Override public int getInventoryStackLimit() { return 64; } @Override public boolean isUseableByPlayer(EntityPlayer player) { return worldObj.getTileEntity(xCoord, yCoord, zCoord) == this && player.getDistanceSq(xCoord + 0.5D, yCoord + 0.5D, zCoord + 0.5D) <= 64D; } @Override public void openInventory() {} @Override public void closeInventory() {} @Override public void markDirty() { super.markDirty(); if (worldObj != null && FMLCommonHandler.instance().getEffectiveSide().isServer()) { int upgradeCountRange = 0; ItemStack itemStack = inventory[SLOT_UPGRADE]; if (itemStack != null && itemStack.getItem() instanceof ItemUpgrade && itemStack.getItemDamage() == ItemUpgrade.DAMAGE_RANGE) { upgradeCountRange = itemStack.stackSize; } ItemStack card = inventory[SLOT_CARD]; int fire = STATE_UNKNOWN; if (card != null) { Item item = card.getItem(); if (item instanceof IPanelDataSource && item instanceof IRangeTriggerable) { boolean needUpdate = true; if (upgradeCountRange > 7) upgradeCountRange = 7; int range = LOCATION_RANGE * (int) Math.pow(2, upgradeCountRange); CardWrapperImpl cardHelper = new CardWrapperImpl(card,SLOT_CARD); if (item instanceof IRemoteSensor) { ChunkCoordinates target = cardHelper.getTarget(); if (target == null) { needUpdate = false; cardHelper.setState(CardState.INVALID_CARD); } else { int dx = target.posX - xCoord; int dy = target.posY - yCoord; int dz = target.posZ - zCoord; if (Math.abs(dx) > range || Math.abs(dy) > range || Math.abs(dz) > range) { needUpdate = false; cardHelper.setState(CardState.OUT_OF_RANGE); fire = STATE_UNKNOWN; } } } if (needUpdate) { CardState state = ((IPanelDataSource) item).update(this, cardHelper, range); cardHelper.setState(state); if (state == CardState.OK) { double min = Math.min(levelStart, levelEnd); double max = Math.max(levelStart, levelEnd); double cur = cardHelper.getDouble("range_trigger_amount"); if (cur > max){ fire = STATE_ACTIVE; }else if(cur < min) { fire = STATE_ACTIVE; }else if(onFire == STATE_UNKNOWN) { fire = STATE_PASSIVE; }else{ fire = STATE_PASSIVE; } }else{ fire = STATE_UNKNOWN; } } } } if(fire != getOnFire()){ setOnFire(fire); worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, worldObj.getBlock(xCoord, yCoord, zCoord)); } } }; @Override public boolean isItemValid(int slotIndex, ItemStack itemstack) { switch (slotIndex) { case SLOT_CARD: return itemstack.getItem() instanceof IRangeTriggerable; default: return itemstack.getItem() instanceof ItemUpgrade && itemstack.getItemDamage() == ItemUpgrade.DAMAGE_RANGE; } } @Override public boolean wrenchCanSetFacing(EntityPlayer entityPlayer, int face) { return !entityPlayer.isSneaking() && getFacing() != face; }; @Override public float getWrenchDropRate() { return 1; } @Override public boolean wrenchCanRemove(EntityPlayer entityPlayer) { return !entityPlayer.isSneaking(); } private int modifyTextureIndex(int texture, int x, int y, int z) { if (texture != RangeTrigger.I_FACE_GRAY) return texture; switch (getOnFire()) { case STATE_ACTIVE: texture = RangeTrigger.I_FACE_RED; break; case STATE_PASSIVE: texture = RangeTrigger.I_FACE_GREEN; break; } return texture; } @Override public int modifyTextureIndex(int texture) { return modifyTextureIndex(texture, xCoord, yCoord, zCoord); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + xCoord; result = prime * result + yCoord; result = prime * result + zCoord; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TileEntityRangeTrigger other = (TileEntityRangeTrigger) obj; if (xCoord != other.xCoord) return false; if (yCoord != other.yCoord) return false; if (zCoord != other.zCoord) return false; if (worldObj != other.worldObj) return false; return true; } /* * @Override //getStartInventorySide public int func_94127_c(int side) { * //DOWN if(side == 0) return 1; return 0; } * * @Override // getSizeInventorySide public int func_94128_d(int side) { * //DOWN || UP if(side == 0 || side == 1) return 1; return * inventory.length; } */ @Override public void rotate() { int r; switch (rotation) { case 0: r = 1; break; case 1: r = 3; break; case 3: r = 2; break; case 2: r = 0; break; default: r = 0; break; } setRotation(r); } @Override public int getRotation() { return rotation; } @Override public void setRotation(int value) { rotation = value; if (rotation != prevRotation) { IC2.network.get().updateTileEntityField(this, "rotation"); } prevRotation = rotation; } @Override public ItemStack getWrenchDrop(EntityPlayer entityPlayer) { return new ItemStack(IC2NuclearControl.blockNuclearControlMain, 1, BlockDamages.DAMAGE_RANGE_TRIGGER); } @Override public boolean hasCustomInventoryName() { return false; } @Override public boolean isItemValidForSlot(int slot, ItemStack itemstack) { return isItemValid(slot, itemstack); } }