electrodynamics/src/main/scala/edx/quantum/laser/Laser.scala
2015-01-25 17:03:39 +08:00

208 lines
7.6 KiB
Scala

package edx.quantum.laser
import java.awt.Color
import cpw.mods.fml.relauncher.ReflectionHelper
import edx.core.Electrodynamics
import net.minecraft.block.material.Material
import net.minecraft.block.{Block, BlockStainedGlass, BlockStainedGlassPane, BlockTNT}
import net.minecraft.init.Blocks
import net.minecraft.item.ItemDye
import net.minecraft.tileentity.TileEntityFurnace
import net.minecraft.util.{DamageSource, MovingObjectPosition}
import net.minecraft.world.World
import resonant.lib.transform.vector.Vector3
import scala.collection.mutable
/**
* Handles laser interaction
* @author Calclavia
*/
object Laser
{
val maxDistance = 100
val minEnergy = 100d
val maxEnergy = 20000d
val minEnergyToMine = 10000d
val maxEnergyToMine = 500000d
val minBurnEnergy = minEnergyToMine
val currentBlockEnergy = mutable.HashMap[Vector3, Double]()
val accumilatedBlockEnergy = mutable.HashMap[Vector3, Double]()
var lastUpdateTime = 0L
def spawn(world: World, start: Vector3, direction: Vector3, energy: Double)
{
spawn(world, start, start, direction, energy)
}
def spawn(world: World, start: Vector3, renderStart: Vector3, direction: Vector3, energy: Double)
{
spawn(world, start, renderStart, direction, new Vector3(1, 1, 1), energy)
}
def spawn(world: World, start: Vector3, renderStart: Vector3, direction: Vector3, color: Vector3, energy: Double)
{
if (energy > minEnergy)
{
val maxPos = start + (direction * maxDistance)
val hit = start.rayTrace(world, maxPos)
if (hit != null)
{
if (hit.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK)
{
val hitVec = new Vector3(hit.hitVec)
val hitBlockPos = new Vector3(hit.blockX, hit.blockY, hit.blockZ)
/**
* Handle Mirror Reflection
*/
val hitTile = world.getTileEntity(hit.blockX, hit.blockY, hit.blockZ)
val hitBlock = world.getBlock(hit.blockX, hit.blockY, hit.blockZ)
val hitMetadata = world.getBlockMetadata(hit.blockX, hit.blockY, hit.blockZ)
if (hitTile.isInstanceOf[ILaserHandler])
{
if (!hitTile.asInstanceOf[ILaserHandler].onLaserHit(renderStart, direction, hit, color, energy))
{
Electrodynamics.proxy.renderLaser(world, renderStart, hitVec, color, energy)
}
}
else if (hitBlock.getMaterial == Material.glass)
{
Electrodynamics.proxy.renderLaser(world, renderStart, hitVec, color, energy)
var newColor = color
if (hitBlock.isInstanceOf[BlockStainedGlass] || hitBlock.isInstanceOf[BlockStainedGlassPane])
{
val dyeColor = new Color(ItemDye.field_150922_c(blockToDye(hitMetadata)))
newColor = new Vector3(dyeColor.getRed, dyeColor.getGreen, dyeColor.getBlue).normalize
}
spawn(world, hitVec + direction * 0.9, hitVec, direction, ((newColor + color) / 2).normalize, energy / 1.05)
}
else
{
/**
* Attempt to burn block
*/
if (!world.isRemote)
{
val hardness = hitBlock.getBlockHardness(world, hitBlockPos.x.toInt, hitBlockPos.y.toInt, hitBlockPos.z.toInt)
if (hardness != -1)
{
if (lastUpdateTime != world.getWorldTime)
{
currentBlockEnergy.clear
lastUpdateTime = world.getWorldTime
}
val energyOnBlock = (if (currentBlockEnergy.contains(hitBlockPos)) currentBlockEnergy(hitBlockPos) else 0) + energy
currentBlockEnergy.put(hitBlockPos, energyOnBlock)
if (hitTile.isInstanceOf[TileEntityFurnace])
{
/**
* Cook in furnace
*/
val furnace = hitTile.asInstanceOf[TileEntityFurnace]
try
{
if (ReflectionHelper.findMethod(classOf[TileEntityFurnace], furnace, Array("canSmelt", "func_145948_k")).invoke(furnace).asInstanceOf[Boolean])
{
furnace.furnaceBurnTime = Math.max(2, furnace.furnaceBurnTime)
furnace.furnaceCookTime = Math.min(199, furnace.furnaceCookTime + (15 * (energy / maxEnergy)).toInt)
}
}
catch
{
case e: Exception => e.printStackTrace()
}
}
else
{
if (energyOnBlock > minEnergyToMine)
{
/**
* The laser can mine the hitBlock!
*/
val accumulatedEnergy = (if (accumilatedBlockEnergy.contains(hitBlockPos)) accumilatedBlockEnergy(hitBlockPos) else 0) + energy
accumilatedBlockEnergy.put(hitBlockPos, accumulatedEnergy)
val energyRequiredToMineBlock = hardness * maxEnergyToMine
world.destroyBlockInWorldPartially(Block.blockRegistry.getIDForObject(hitBlock), hitBlockPos.x.toInt, hitBlockPos.y.toInt, hitBlockPos.z.toInt, (accumulatedEnergy / energyRequiredToMineBlock * 10).toInt)
if (accumulatedEnergy > energyRequiredToMineBlock)
{
hitBlock.dropBlockAsItem(world, hitBlockPos.x.toInt, hitBlockPos.y.toInt, hitBlockPos.z.toInt, world.getBlockMetadata(hitBlockPos.x.toInt, hitBlockPos.y.toInt, hitBlockPos.z.toInt), 0)
world.setBlockToAir(hitBlockPos.x.toInt, hitBlockPos.y.toInt, hitBlockPos.z.toInt)
accumilatedBlockEnergy.remove(hitBlockPos)
}
}
else
{
//accumilatedBlockEnergy.remove(hitBlockPos)
}
/**
* Catch Fire
*/
if (energyOnBlock > minBurnEnergy && hitBlock.getMaterial.getCanBurn)
{
if (hitBlock.isInstanceOf[BlockTNT])
{
hitBlock.asInstanceOf[BlockTNT].func_150114_a(world, hitBlockPos.x.toInt, hitBlockPos.y.toInt, hitBlockPos.z.toInt, 1, null)
}
world.setBlock(hitBlockPos.x.toInt, hitBlockPos.y.toInt, hitBlockPos.z.toInt, Blocks.fire)
}
}
}
}
/**
* Render laser hit
*/
Electrodynamics.proxy.renderLaser(world, renderStart, hitVec, color, energy)
/**
* Render scorch and particles
*/
Electrodynamics.proxy.renderScorch(world, hitVec - (direction * 0.02), hit.sideHit)
Electrodynamics.proxy.renderBlockParticle(world, hitVec, hitBlock, hit.sideHit)
}
}
else if (hit.typeOfHit == MovingObjectPosition.MovingObjectType.ENTITY)
{
if (energy > minBurnEnergy)
{
val fireTime = (10 * (energy / maxEnergy)).toInt
if (fireTime > 0)
{
hit.entityHit.setFire(fireTime)
hit.entityHit.attackEntityFrom(DamageSource.onFire, (20 * (energy / maxEnergy)).toInt)
}
}
Electrodynamics.proxy.renderLaser(world, renderStart, new Vector3(hit.hitVec), color, energy)
}
return
}
Electrodynamics.proxy.renderLaser(world, renderStart, maxPos, color, energy)
}
}
def blockToDye(blockMeta: Int): Int =
{
return ~blockMeta & 15
}
}