package edx.quantum.machine.accelerator import cpw.mods.fml.relauncher.{Side, SideOnly} import edx.core.{Electrodynamics, Reference, Settings} import edx.quantum.QuantumContent import edx.quantum.items.ItemAntimatter import io.netty.buffer.ByteBuf import net.minecraft.block.Block import net.minecraft.block.material.Material import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.util.IIcon import net.minecraftforge.common.util.ForgeDirection import resonantengine.api.tile.{IElectromagnet, IRotatable} import resonantengine.core.network.discriminator.{PacketTile, PacketType} import resonantengine.lib.content.prefab.TInventory import resonantengine.lib.grid.energy.EnergyStorage import resonantengine.lib.modcontent.block.ResonantTile import resonantengine.lib.transform.vector.Vector3 import resonantengine.lib.utility.BlockUtility import resonantengine.prefab.block.impl.TEnergyProvider import resonantengine.prefab.network.{TPacketReceiver, TPacketSender} import scala.collection.JavaConversions._ class TileAccelerator extends ResonantTile(Material.iron) with TInventory with IElectromagnet with IRotatable with TPacketReceiver with TPacketSender with TEnergyProvider { final val DESC_PACKET_ID = 2 /** * The total amount of energy consumed by this particle. In Joules. */ var totalEnergyConsumed: Double = 0 /** * The amount of anti-matter stored within the accelerator. Measured in milligrams. */ var antimatter: Int = 0 var entityParticle: EntityParticle = null var velocity: Float = 0 var clientEnergy: Double = 0 var lastSpawnTick: Int = 0 /** * Multiplier that is used to give extra anti-matter based on density (hardness) of a given ore. */ private var antiMatterDensityMultiplyer: Int = Settings.ACCELERATOR_ANITMATTER_DENSITY_MULTIPLIER //Constructor //TODO: Dummy energy = new EnergyStorage override def getSizeInventory: Int = 4 override def update { super.update if (!worldObj.isRemote) { clientEnergy = energy.value velocity = getParticleVel() outputAntimatter() if (worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord)) { if (energy >= Settings.ACCELERATOR_ENERGY_COST_PER_TICK) { if (entityParticle == null) { //Create new particle if we have materials to spawn it with if (getStackInSlot(0) != null && lastSpawnTick >= 40) { val spawn_vec: Vector3 = toVectorWorld spawn_vec.add(getDirection.getOpposite) spawn_vec.add(0.5f) if (EntityParticle.canSpawnParticle(worldObj, spawn_vec)) { totalEnergyConsumed = 0 entityParticle = new EntityParticle(worldObj, spawn_vec, toVectorWorld, getDirection.getOpposite) worldObj.spawnEntityInWorld(entityParticle) CalculateParticleDensity decrStackSize(0, 1) lastSpawnTick = 0 } } } else { if (entityParticle.isDead) { //Handle strange matter creation if (entityParticle.didParticleCollide) { if (worldObj.rand.nextFloat <= Settings.darkMatterSpawnChance) { incrStackSize(3, new ItemStack(QuantumContent.itemDarkMatter)) } } entityParticle = null } else if (velocity > EntityParticle.ANITMATTER_CREATION_SPEED) { //Create antimatter if we have hit max speed worldObj.playSoundEffect(xCoord, yCoord, zCoord, Reference.prefix + "antimatter", 2f, 1f - worldObj.rand.nextFloat * 0.3f) val generatedAntimatter: Int = 5 + worldObj.rand.nextInt(antiMatterDensityMultiplyer) antimatter += generatedAntimatter //Cleanup totalEnergyConsumed = 0 entityParticle.setDead entityParticle = null } if (entityParticle != null) { worldObj.playSoundEffect(xCoord, yCoord, zCoord, Reference.prefix + "accelerator", 1.5f, (0.6f + (0.4 * (entityParticle.getParticleVelocity) / EntityParticle.ANITMATTER_CREATION_SPEED)).asInstanceOf[Float]) } } energy -= Settings.ACCELERATOR_ENERGY_COST_PER_TICK } else { if (entityParticle != null) { entityParticle.setDead } entityParticle = null } } else { if (entityParticle != null) { entityParticle.setDead } entityParticle = null } if (ticks % 5 == 0) { for (player <- getPlayersUsing) { sendPacket(getDescPacket, player) } } lastSpawnTick += 1 } } /** * Converts antimatter storage into item if the condition are meet */ def outputAntimatter() { //Do we have an empty cell in slot one if (QuantumContent.isItemStackEmptyCell(getStackInSlot(1)) && getStackInSlot(1).stackSize > 0) { // Each cell can only hold 125mg of antimatter TODO maybe a config for this? if (antimatter >= 125) { if (getStackInSlot(2) != null) { // If the output slot is not empty we must increase stack size if (getStackInSlot(2).getItem == QuantumContent.itemAntimatter) { val newStack: ItemStack = getStackInSlot(2).copy if (newStack.stackSize < newStack.getMaxStackSize) { decrStackSize(1, 1) antimatter -= 125 newStack.stackSize += 1 setInventorySlotContents(2, newStack) } } } else { //Output to slot 2 and decrease volume of antimatter antimatter -= 125 decrStackSize(1, 1) setInventorySlotContents(2, new ItemStack(QuantumContent.itemAntimatter)) } } } } private def CalculateParticleDensity { val itemToAccelerate: ItemStack = this.getStackInSlot(0) if (itemToAccelerate != null) { antiMatterDensityMultiplyer = Settings.ACCELERATOR_ANITMATTER_DENSITY_MULTIPLIER val potentialBlock: Block = Block.getBlockFromItem(itemToAccelerate.getItem) if (potentialBlock != null) { antiMatterDensityMultiplyer = BlockUtility.getBlockHardness(potentialBlock).asInstanceOf[Int] * Settings.ACCELERATOR_ANITMATTER_DENSITY_MULTIPLIER if (antiMatterDensityMultiplyer <= 0) { antiMatterDensityMultiplyer = Settings.ACCELERATOR_ANITMATTER_DENSITY_MULTIPLIER } if (antiMatterDensityMultiplyer > 1000) { antiMatterDensityMultiplyer = 1000 * Settings.ACCELERATOR_ANITMATTER_DENSITY_MULTIPLIER } } } } override def getDescPacket: PacketTile = { return new PacketTile(x.toInt, y.toInt, z.toInt, Array[Any](DESC_PACKET_ID, velocity, totalEnergyConsumed, antimatter, energy.value)) } ///////////////////////////////////////// /// Packet Handling /// //////////////////////////////////////// /** get velocity for the particle and @return it as a float */ def getParticleVel(): Float = { if (entityParticle != null) return entityParticle.getParticleVelocity.asInstanceOf[Float] else return 0 } override def activate(player: EntityPlayer, side: Int, hit: Vector3): Boolean = { player.openGui(Electrodynamics, 0, world, x.toInt, y.toInt, z.toInt) return true } ///////////////////////////////////////// /// Save handling /// //////////////////////////////////////// override def read(buf: ByteBuf, id: Int, packetType: PacketType) { //Client only packets if (world.isRemote) { if (id == DESC_PACKET_ID) { this.velocity = buf.readFloat() this.totalEnergyConsumed = buf.readDouble() this.antimatter = buf.readInt() this.energy.value = buf.readDouble() } } } override def readFromNBT(par1NBTTagCompound: NBTTagCompound) { super.readFromNBT(par1NBTTagCompound) totalEnergyConsumed = par1NBTTagCompound.getDouble("energyUsed") antimatter = par1NBTTagCompound.getInteger("antimatter") } ///////////////////////////////////////// /// Inventory Overrides /// //////////////////////////////////////// override def writeToNBT(par1NBTTagCompound: NBTTagCompound) { super.writeToNBT(par1NBTTagCompound) par1NBTTagCompound.setDouble("energyUsed", totalEnergyConsumed) par1NBTTagCompound.setInteger("antimatter", antimatter) } override def canInsertItem(slotID: Int, itemStack: ItemStack, j: Int): Boolean = { return isItemValidForSlot(slotID, itemStack) && slotID != 2 && slotID != 3 } override def isItemValidForSlot(i: Int, itemStack: ItemStack): Boolean = { i match { case 0 => return true case 1 => return QuantumContent.isItemStackEmptyCell(itemStack) case 2 => return itemStack.getItem.isInstanceOf[ItemAntimatter] case 3 => return itemStack.getItem != null && itemStack.getItem.getUnlocalizedName.contains("DarkMatter") } return false } ///////////////////////////////////////// /// Field Getters & Setters /// //////////////////////////////////////// override def canExtractItem(slotID: Int, itemstack: ItemStack, j: Int): Boolean = { return slotID == 2 || slotID == 3 } override def isRunning: Boolean = { return true } @SideOnly(Side.CLIENT) override def getIcon(side: Int, meta: Int): IIcon = { if (side == getDirection.getOpposite.ordinal()) { return QuantumContent.blockElectromagnet.getIcon(side, meta) } return getIcon } override def getDirection: ForgeDirection = { return ForgeDirection.getOrientation(getBlockMetadata) } override def setDirection(direction: ForgeDirection) { world.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, direction.ordinal, 3) } }