454 lines
14 KiB
Scala
454 lines
14 KiB
Scala
package edx.quantum.reactor
|
|
|
|
import java.util
|
|
import java.util.List
|
|
|
|
import cpw.mods.fml.relauncher.{Side, SideOnly}
|
|
import edx.core.{Electrodynamics, Reference}
|
|
import edx.quantum.QuantumContent
|
|
import net.minecraft.block.Block
|
|
import net.minecraft.block.material.Material
|
|
import net.minecraft.entity.EntityLiving
|
|
import net.minecraft.entity.player.EntityPlayer
|
|
import net.minecraft.init.Blocks
|
|
import net.minecraft.item.ItemStack
|
|
import net.minecraft.nbt.NBTTagCompound
|
|
import net.minecraft.tileentity.TileEntity
|
|
import net.minecraft.util.{AxisAlignedBB, ResourceLocation}
|
|
import net.minecraft.world.World
|
|
import net.minecraftforge.client.model.AdvancedModelLoader
|
|
import net.minecraftforge.common.util.ForgeDirection
|
|
import org.lwjgl.opengl.GL11
|
|
import resonantengine.api.edx.machine.{IReactor, IReactorComponent}
|
|
import resonantengine.lib.grid.thermal.{GridThermal, ThermalPhysics}
|
|
import resonantengine.lib.potion.PoisonRadiation
|
|
import resonantengine.lib.render.RenderUtility
|
|
import resonantengine.lib.render.model.ModelCube
|
|
import resonantengine.lib.transform.vector.Vector3
|
|
import resonantengine.lib.utility.inventory.InventoryUtility
|
|
import resonantengine.prefab.block.mixed.TileInventory
|
|
import resonantengine.prefab.block.multiblock.{IMultiBlockStructure, MultiBlockHandler}
|
|
import resonantengine.prefab.network.{TPacketReceiver, TPacketSender}
|
|
|
|
import scala.collection.convert.wrapAll._
|
|
|
|
/** The primary reactor component cell used to build reactors with.
|
|
*
|
|
* @author Calclavia */
|
|
object TileReactorCell
|
|
{
|
|
final val radius = 2
|
|
final val meltingPoint = 3000
|
|
final val specificHeatCapacity = 1000
|
|
final val mass = ThermalPhysics.getMass(1000, 7)
|
|
|
|
final val modelTop = AdvancedModelLoader.loadModel(new ResourceLocation(Reference.domain, Reference.modelPath + "reactorCellTop.tcn"))
|
|
final val modelMiddle = AdvancedModelLoader.loadModel(new ResourceLocation(Reference.domain, Reference.modelPath + "reactorCellMiddle.tcn"))
|
|
final val modelBottom = AdvancedModelLoader.loadModel(new ResourceLocation(Reference.domain, Reference.modelPath + "reactorCellBottom.tcn"))
|
|
final val textureTop = new ResourceLocation(Reference.domain, Reference.modelPath + "reactorCellTop.png")
|
|
final val textureMiddle = new ResourceLocation(Reference.domain, Reference.modelPath + "reactorCellMiddle.png")
|
|
final val textureBottom = new ResourceLocation(Reference.domain, Reference.modelPath + "reactorCellBottom.png")
|
|
final val textureFuel = new ResourceLocation(Reference.domain, Reference.modelPath + "fissileMaterial.png")
|
|
}
|
|
|
|
class TileReactorCell extends TileInventory(Material.iron) with IMultiBlockStructure[TileReactorCell] with IReactor with TPacketSender with TPacketReceiver
|
|
{
|
|
/** Multiblock Methods. */
|
|
private val multiBlock = new MultiBlockHandler[TileReactorCell](this)
|
|
private var internalEnergy = 0d
|
|
|
|
textureName = "machine"
|
|
isOpaqueCube = false
|
|
normalRender = false
|
|
|
|
override def getSizeInventory = 1
|
|
|
|
override def onWorldJoin()
|
|
{
|
|
updatePositionStatus()
|
|
}
|
|
|
|
/** Multiblock Methods */
|
|
def updatePositionStatus()
|
|
{
|
|
val mainTile = getLowest
|
|
mainTile.getMultiBlock.deconstruct()
|
|
mainTile.getMultiBlock.construct()
|
|
|
|
val top = (toVectorWorld + new Vector3(0, 1, 0)).getTileEntity(worldObj).isInstanceOf[TileReactorCell]
|
|
val bottom = (toVectorWorld + new Vector3(0, -1, 0)).getTileEntity(worldObj).isInstanceOf[TileReactorCell]
|
|
|
|
if (top && bottom)
|
|
{
|
|
setMeta(1)
|
|
}
|
|
else if (top)
|
|
{
|
|
setMeta(0)
|
|
}
|
|
else
|
|
{
|
|
setMeta(2)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return Gets the lowest reactor cell in this "tower"
|
|
*/
|
|
def getLowest: TileReactorCell =
|
|
{
|
|
var lowest: TileReactorCell = this
|
|
val checkPosition: Vector3 = toVectorWorld
|
|
while (true)
|
|
{
|
|
val t: TileEntity = checkPosition.getTileEntity(this.worldObj)
|
|
if (t.isInstanceOf[TileReactorCell])
|
|
{
|
|
lowest = t.asInstanceOf[TileReactorCell]
|
|
}
|
|
else
|
|
{
|
|
return lowest
|
|
}
|
|
checkPosition.y -= 1
|
|
}
|
|
return lowest
|
|
}
|
|
|
|
override def onNeighborChanged(block: Block)
|
|
{
|
|
updatePositionStatus()
|
|
}
|
|
|
|
override def update()
|
|
{
|
|
super.update()
|
|
|
|
/**
|
|
* Move the fuel rod down into the main reactor.
|
|
*/
|
|
if (!getMultiBlock.isPrimary)
|
|
{
|
|
if (getStackInSlot(0) != null)
|
|
{
|
|
if (getMultiBlock.get.getStackInSlot(0) == null)
|
|
{
|
|
getMultiBlock.get.setInventorySlotContents(0, getStackInSlot(0))
|
|
setInventorySlotContents(0, null)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!getWorld.isRemote)
|
|
{
|
|
/*
|
|
if (getMultiBlock().isPrimary() && tank.getFluid != null && tank.getFluid.fluidID == QuantumContent.FLUID_PLASMA.getID)
|
|
{
|
|
val drain: FluidStack = tank.drain(FluidContainerRegistry.BUCKET_VOLUME, false)
|
|
if (drain != null && drain.amount >= FluidContainerRegistry.BUCKET_VOLUME)
|
|
{
|
|
val spawnDir: ForgeDirection = ForgeDirection.getOrientation(worldObj.rand.nextInt(3) + 2)
|
|
val spawnPos: Vector3 = position + spawnDir + spawnDir
|
|
spawnPos.add(0, Math.max(worldObj.rand.nextInt(getHeight) - 1, 0), 0)
|
|
if (worldObj.isAirBlock(spawnPos.xi, spawnPos.yi, spawnPos.zi))
|
|
{
|
|
MinecraftForge.EVENT_BUS.post(new PlasmaEvent.SpawnPlasmaEvent(worldObj, spawnPos.xi, spawnPos.yi, spawnPos.zi, TilePlasma.plasmaMaxTemperature))
|
|
tank.drain(FluidContainerRegistry.BUCKET_VOLUME, true)
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{*/
|
|
|
|
/**
|
|
* Fission reaction
|
|
*/
|
|
val fuelRod = getMultiBlock.get.getStackInSlot(0)
|
|
|
|
if (fuelRod != null)
|
|
{
|
|
if (fuelRod.getItem.isInstanceOf[IReactorComponent])
|
|
{
|
|
fuelRod.getItem.asInstanceOf[IReactorComponent].onReact(fuelRod, this)
|
|
|
|
if (!worldObj.isRemote)
|
|
{
|
|
if (fuelRod.getItemDamage >= fuelRod.getMaxDamage)
|
|
{
|
|
getMultiBlock.get.setInventorySlotContents(0, null)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Radiation
|
|
*/
|
|
//TODO: Raycast radiation code
|
|
if (ticks % 20 == 0)
|
|
{
|
|
if (worldObj.rand.nextFloat > 0.65)
|
|
{
|
|
val entities = worldObj.getEntitiesWithinAABB(classOf[EntityLiving], AxisAlignedBB.getBoundingBox(xCoord - TileReactorCell.radius * 2, yCoord - TileReactorCell.radius * 2, zCoord - TileReactorCell.radius * 2, xCoord + TileReactorCell.radius * 2, yCoord + TileReactorCell.radius * 2, zCoord + TileReactorCell.radius * 2)).asInstanceOf[List[EntityLiving]]
|
|
for (entity <- entities)
|
|
{
|
|
PoisonRadiation.INSTANCE.poisonEntity(toVectorWorld, entity)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Heats up the surroundings. Control rods absorbs neutrons, reducing the heat produced.
|
|
*/
|
|
val controlRodCount = ForgeDirection.VALID_DIRECTIONS.map(toVectorWorld + _).count(_.getBlock == QuantumContent.blockControlRod)
|
|
GridThermal.addHeat(toVectorWorld, internalEnergy / ((controlRodCount + 1) * 0.3))
|
|
val temperature = GridThermal.getTemperature(toVectorWorld)
|
|
|
|
internalEnergy = 0
|
|
|
|
/**
|
|
* Play sound effects
|
|
*/
|
|
if (temperature >= 373)
|
|
{
|
|
if (world.rand.nextInt(80) == 0)
|
|
{
|
|
world.playSoundEffect(xCoord + 0.5F, yCoord + 0.5F, zCoord + 0.5F, "Fluid.lava", 0.5F, 2.1F + (worldObj.rand.nextFloat - worldObj.rand.nextFloat) * 0.85F)
|
|
}
|
|
if (world.rand.nextInt(40) == 0)
|
|
{
|
|
world.playSoundEffect(xCoord + 0.5F, yCoord + 0.5F, zCoord + 0.5F, "Fluid.lavapop", 0.5F, 2.6F + (worldObj.rand.nextFloat - worldObj.rand.nextFloat) * 0.8F)
|
|
}
|
|
|
|
if (ticks % (20 * 5) == 0)
|
|
{
|
|
world.playSoundEffect(this.xCoord + 0.5F, this.yCoord + 0.5F, this.zCoord + 0.5F, Reference.prefix + "reactorcell", temperature / TileReactorCell.meltingPoint, 1.0F)
|
|
}
|
|
}
|
|
|
|
if (temperature > TileReactorCell.meltingPoint)
|
|
{
|
|
// meltDown()
|
|
}
|
|
}
|
|
else
|
|
{
|
|
val temperature = GridThermal.getTemperature(toVectorWorld)
|
|
|
|
if (world.rand.nextInt(5) == 0 && temperature >= 373)
|
|
{
|
|
world.spawnParticle("cloud", this.xCoord + worldObj.rand.nextInt(2), this.yCoord + 1.0F, this.zCoord + worldObj.rand.nextInt(2), 0, 0.1D, 0)
|
|
world.spawnParticle("bubble", this.xCoord + worldObj.rand.nextInt(5), this.yCoord, this.zCoord + worldObj.rand.nextInt(5), 0, 0, 0)
|
|
}
|
|
}
|
|
}
|
|
|
|
override def getWorld: World =
|
|
{
|
|
return worldObj
|
|
}
|
|
|
|
def onMultiBlockChanged()
|
|
{
|
|
}
|
|
|
|
override def getMultiBlockVectors: java.lang.Iterable[Vector3] =
|
|
{
|
|
val vectors: List[Vector3] = new util.ArrayList[Vector3]
|
|
val checkPosition: Vector3 = toVectorWorld
|
|
while (true)
|
|
{
|
|
val t: TileEntity = checkPosition.getTileEntity(this.worldObj)
|
|
if (t.isInstanceOf[TileReactorCell])
|
|
{
|
|
vectors.add(checkPosition - getPosition)
|
|
}
|
|
else
|
|
{
|
|
return vectors
|
|
}
|
|
checkPosition.y += 1
|
|
}
|
|
return vectors
|
|
}
|
|
|
|
def getPosition: Vector3 =
|
|
{
|
|
return toVectorWorld
|
|
}
|
|
|
|
override def readFromNBT(nbt: NBTTagCompound)
|
|
{
|
|
super.readFromNBT(nbt)
|
|
getMultiBlock.load(nbt)
|
|
}
|
|
|
|
override def writeToNBT(nbt: NBTTagCompound)
|
|
{
|
|
super.writeToNBT(nbt)
|
|
getMultiBlock.save(nbt)
|
|
}
|
|
|
|
override def getInventoryStackLimit: Int = 1
|
|
|
|
/** Returns true if automation can insert the given item in the given slot from the given side.
|
|
* Args: Slot, item, side */
|
|
override def canInsertItem(slot: Int, items: ItemStack, side: Int): Boolean =
|
|
{
|
|
return this.isItemValidForSlot(slot, items)
|
|
}
|
|
|
|
override def isItemValidForSlot(slotID: Int, itemStack: ItemStack): Boolean =
|
|
{
|
|
if (getMultiBlock.isPrimary && getMultiBlock.get.getStackInSlot(0) == null)
|
|
{
|
|
return itemStack.getItem.isInstanceOf[IReactorComponent]
|
|
}
|
|
return false
|
|
}
|
|
|
|
override def getMultiBlock: MultiBlockHandler[TileReactorCell] = multiBlock
|
|
|
|
override def isUseableByPlayer(par1EntityPlayer: EntityPlayer): Boolean =
|
|
{
|
|
return if (worldObj.getTileEntity(xCoord, yCoord, zCoord) ne this) false else par1EntityPlayer.getDistanceSq(xCoord + 0.5D, yCoord + 0.5D, zCoord + 0.5D) <= 64.0D
|
|
}
|
|
|
|
def getInvName: String =
|
|
{
|
|
return getBlockType.getLocalizedName
|
|
}
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
override def getRenderBoundingBox: AxisAlignedBB =
|
|
{
|
|
if (getMultiBlock.isPrimary && getMultiBlock.isConstructed)
|
|
{
|
|
return AxisAlignedBB.getBoundingBox(x - 5, y - 5, z - 5, x + 5, y + 5, z + 5);
|
|
}
|
|
return super.getRenderBoundingBox
|
|
}
|
|
|
|
override def heat(energy: Double)
|
|
{
|
|
internalEnergy = Math.max(internalEnergy + energy, 0)
|
|
}
|
|
|
|
override def renderDynamic(pos: Vector3, frame: Float, pass: Int)
|
|
{
|
|
GL11.glPushMatrix()
|
|
GL11.glTranslated(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5)
|
|
val meta = if (frame != 0) metadata else 2
|
|
|
|
val hasBelow = if (frame != 0) world.getTileEntity(x.toInt, y.toInt - 1, z.toInt).isInstanceOf[TileReactorCell] else false
|
|
|
|
if (meta == 0)
|
|
{
|
|
RenderUtility.bind(TileReactorCell.textureBottom)
|
|
TileReactorCell.modelBottom.renderAll()
|
|
}
|
|
else if (meta == 1)
|
|
{
|
|
RenderUtility.bind(TileReactorCell.textureMiddle)
|
|
GL11.glTranslatef(0, 0.075f, 0)
|
|
GL11.glScalef(1f, 1.15f, 1f)
|
|
TileReactorCell.modelMiddle.renderAll()
|
|
}
|
|
else
|
|
{
|
|
RenderUtility.bind(TileReactorCell.textureTop)
|
|
|
|
if (hasBelow)
|
|
{
|
|
GL11.glScalef(1f, 1.32f, 1f)
|
|
}
|
|
else
|
|
{
|
|
GL11.glTranslatef(0, 0.1f, 0)
|
|
GL11.glScalef(1f, 1.2f, 1f)
|
|
}
|
|
|
|
if (hasBelow)
|
|
{
|
|
TileReactorCell.modelTop.renderAllExcept("BottomPad", "BaseDepth", "BaseWidth", "Base")
|
|
}
|
|
else
|
|
{
|
|
TileReactorCell.modelTop.renderAll()
|
|
}
|
|
}
|
|
GL11.glPopMatrix()
|
|
|
|
if (getStackInSlot(0) != null)
|
|
{
|
|
val height = getHeight * ((getStackInSlot(0).getMaxDamage - getStackInSlot(0).getItemDamage).toFloat / getStackInSlot(0).getMaxDamage.toFloat)
|
|
GL11.glPushMatrix()
|
|
GL11.glTranslated(pos.x + 0.5, pos.y + 0.5 * height, pos.z + 0.5)
|
|
GL11.glScalef(0.4f, 0.9f * height, 0.4f)
|
|
RenderUtility.bind(TileReactorCell.textureFuel)
|
|
RenderUtility.disableLighting()
|
|
ModelCube.INSTNACE.render()
|
|
RenderUtility.enableLighting()
|
|
GL11.glPopMatrix()
|
|
}
|
|
}
|
|
|
|
def getHeight: Int =
|
|
{
|
|
var height: Int = 0
|
|
val checkPosition: Vector3 = toVectorWorld
|
|
var tile: TileEntity = this
|
|
while (tile.isInstanceOf[TileReactorCell])
|
|
{
|
|
checkPosition.y += 1
|
|
height += 1
|
|
tile = checkPosition.getTileEntity(worldObj)
|
|
}
|
|
return height
|
|
}
|
|
|
|
/** Called when the block is right clicked by the player */
|
|
override protected def use(player: EntityPlayer, side: Int, hit: Vector3): Boolean =
|
|
{
|
|
if (!world.isRemote)
|
|
{
|
|
val tile: TileReactorCell = getMultiBlock.get()
|
|
if (player.inventory.getCurrentItem != null)
|
|
{
|
|
if (tile.getStackInSlot(0) == null)
|
|
{
|
|
if (player.inventory.getCurrentItem.getItem.isInstanceOf[IReactorComponent])
|
|
{
|
|
val itemStack: ItemStack = player.inventory.getCurrentItem.copy
|
|
itemStack.stackSize = 1
|
|
tile.setInventorySlotContents(0, itemStack)
|
|
player.inventory.decrStackSize(player.inventory.currentItem, 1)
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
else if (player.isSneaking && tile.getStackInSlot(0) != null)
|
|
{
|
|
InventoryUtility.dropItemStack(world, new Vector3(player), tile.getStackInSlot(0), 0)
|
|
tile.setInventorySlotContents(0, null)
|
|
return true
|
|
}
|
|
else
|
|
{
|
|
player.openGui(Electrodynamics, 0, world, tile.xCoord, tile.yCoord, tile.zCoord)
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
private def meltDown()
|
|
{
|
|
if (!world.isRemote)
|
|
{
|
|
world.setBlock(this.xCoord, this.yCoord, this.zCoord, Blocks.lava)
|
|
world.createExplosion(null, x + 0.5, y + 0.5, z + 0.5, 3, false)
|
|
}
|
|
}
|
|
}
|