/*******************************************************************************
* AbyssalCraft
* Copyright (c) 2012 - 2017 Shinoow.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-3.0.txt
*
* Contributors:
* Shinoow - implementation
******************************************************************************/
package com.shinoow.abyssalcraft.common.world;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.enchantment.EnchantmentProtection;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;
import com.google.common.collect.Sets;
import com.shinoow.abyssalcraft.api.block.ACBlocks;
import com.shinoow.abyssalcraft.common.entity.EntityODBPrimed;
import com.shinoow.abyssalcraft.common.entity.EntityODBcPrimed;
public class ACExplosion extends Explosion
{
/** whether or not the explosion converts nearby blocks to liquid antimatter */
public boolean isAntimatter;
/** whether or not this explosion spawns smoke particles */
public boolean isSmoking = true;
private int chunkSize;
private Random explosionRNG = new Random();
private World worldObj;
public double explosionX;
public double explosionY;
public double explosionZ;
public Entity exploder;
public float explosionSize;
/** A list of BlockPos of blocks affected by this explosion */
public List<BlockPos> affectedBlockPositions = new ArrayList<BlockPos>();
private Map<EntityPlayer, Vec3d> field_77288_k = new HashMap<EntityPlayer, Vec3d>();
public ACExplosion(World par1World, Entity par2Entity, double par3, double par5, double par7, float par9, int par11, boolean par12, boolean par14)
{
super(par1World, par2Entity, par3, par5, par7, par9, par12, par14);
worldObj = par1World;
exploder = par2Entity;
explosionSize = par9;
explosionX = par3;
explosionY = par5;
explosionZ = par7;
chunkSize = par11;
isAntimatter = par12;
isSmoking = par14;
}
/**
* Does the first part of the explosion (destroy blocks)
*/
@Override
public void doExplosionA()
{
Set<BlockPos> set = Sets.<BlockPos>newHashSet();
for (int j = 0; j < chunkSize; ++j)
for (int k = 0; k < chunkSize; ++k)
for (int l = 0; l < chunkSize; ++l)
if (j == 0 || j == chunkSize - 1 || k == 0 || k == chunkSize - 1 || l == 0 || l == chunkSize - 1)
{
double d0 = (float)j / (chunkSize - 1) * 2.0F - 1.0F;
double d1 = (float)k / (chunkSize - 1) * 2.0F - 1.0F;
double d2 = (float)l / (chunkSize - 1) * 2.0F - 1.0F;
double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
d0 /= d3;
d1 /= d3;
d2 /= d3;
float f = explosionSize * (0.7F + worldObj.rand.nextFloat() * 0.6F);
double d4 = explosionX;
double d6 = explosionY;
double d8 = explosionZ;
for (; f > 0.0F; f -= 0.22500001F)
{
BlockPos blockpos = new BlockPos(d4, d6, d8);
IBlockState iblockstate = worldObj.getBlockState(blockpos);
if (iblockstate.getMaterial() != Material.AIR)
{
float f2 = exploder != null ? exploder.getExplosionResistance(this, worldObj, blockpos, iblockstate) : iblockstate.getBlock().getExplosionResistance(worldObj, blockpos, (Entity)null, this);
f -= (f2 + 0.3F) * 0.3F;
}
if (f > 0.0F && (exploder == null || exploder.verifyExplosion(this, worldObj, blockpos, iblockstate, f)))
set.add(blockpos);
d4 += d0 * 0.30000001192092896D;
d6 += d1 * 0.30000001192092896D;
d8 += d2 * 0.30000001192092896D;
}
}
affectedBlockPositions.addAll(set);
float f3 = explosionSize * 2.0F;
int k1 = MathHelper.floor(explosionX - f3 - 1.0D);
int l1 = MathHelper.floor(explosionX + f3 + 1.0D);
int i2 = MathHelper.floor(explosionY - f3 - 1.0D);
int i1 = MathHelper.floor(explosionY + f3 + 1.0D);
int j2 = MathHelper.floor(explosionZ - f3 - 1.0D);
int j1 = MathHelper.floor(explosionZ + f3 + 1.0D);
List<Entity> list = worldObj.getEntitiesWithinAABBExcludingEntity(exploder, new AxisAlignedBB(k1, i2, j2, l1, i1, j1));
net.minecraftforge.event.ForgeEventFactory.onExplosionDetonate(worldObj, this, list, f3);
Vec3d vec3d = new Vec3d(explosionX, explosionY, explosionZ);
for (int k2 = 0; k2 < list.size(); ++k2)
{
Entity entity = list.get(k2);
if (!entity.isImmuneToExplosions())
{
double d12 = entity.getDistance(explosionX, explosionY, explosionZ) / f3;
if (d12 <= 1.0D)
{
double d5 = entity.posX - explosionX;
double d7 = entity.posY + entity.getEyeHeight() - explosionY;
double d9 = entity.posZ - explosionZ;
double d13 = MathHelper.sqrt(d5 * d5 + d7 * d7 + d9 * d9);
if (d13 != 0.0D)
{
d5 /= d13;
d7 /= d13;
d9 /= d13;
double d14 = worldObj.getBlockDensity(vec3d, entity.getEntityBoundingBox());
double d10 = (1.0D - d12) * d14;
entity.attackEntityFrom(DamageSource.causeExplosionDamage(this), (int)((d10 * d10 + d10) / 2.0D * 7.0D * f3 + 1.0D));
double d11 = 1.0D;
if (entity instanceof EntityLivingBase)
d11 = EnchantmentProtection.getBlastDamageReduction((EntityLivingBase)entity, d10);
entity.motionX += d5 * d11;
entity.motionY += d7 * d11;
entity.motionZ += d9 * d11;
if (entity instanceof EntityPlayer)
{
EntityPlayer entityplayer = (EntityPlayer)entity;
if (!entityplayer.isSpectator() && (!entityplayer.isCreative() || !entityplayer.capabilities.isFlying))
field_77288_k.put(entityplayer, new Vec3d(d5 * d10, d7 * d10, d9 * d10));
}
}
}
}
}
}
/**
* Does the second part of the explosion (sound, particles, drop spawn)
*/
@Override
public void doExplosionB(boolean par1)
{
worldObj.playSound(null, explosionX, explosionY, explosionZ, SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.BLOCKS, 4.0F, (1.0F + (worldObj.rand.nextFloat() - worldObj.rand.nextFloat()) * 0.2F) * 0.7F);
if (explosionSize >= 2.0F && isSmoking)
worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, explosionX, explosionY, explosionZ, 1.0D, 0.0D, 0.0D);
else
worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, explosionX, explosionY, explosionZ, 1.0D, 0.0D, 0.0D);
if (isSmoking)
for(BlockPos pos : affectedBlockPositions)
{
IBlockState block = worldObj.getBlockState(pos);
if (par1)
{
double d0 = pos.getX() + worldObj.rand.nextFloat();
double d1 = pos.getY() + worldObj.rand.nextFloat();
double d2 = pos.getZ() + worldObj.rand.nextFloat();
double d3 = d0 - explosionX;
double d4 = d1 - explosionY;
double d5 = d2 - explosionZ;
double d6 = MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
d3 /= d6;
d4 /= d6;
d5 /= d6;
double d7 = 0.5D / (d6 / explosionSize + 0.1D);
d7 *= worldObj.rand.nextFloat() * worldObj.rand.nextFloat() + 0.3F;
d3 *= d7;
d4 *= d7;
d5 *= d7;
worldObj.spawnParticle(EnumParticleTypes.EXPLOSION_NORMAL, (d0 + explosionX * 1.0D) / 2.0D, (d1 + explosionY * 1.0D) / 2.0D, (d2 + explosionZ * 1.0D) / 2.0D, d3, d4, d5);
worldObj.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, d0, d1, d2, d3, d4, d5);
}
if (block.getMaterial() != Material.AIR)
block.getBlock().onBlockExploded(worldObj, pos, this);
}
if (isAntimatter)
for(BlockPos pos1 : affectedBlockPositions)
{
IBlockState block = worldObj.getBlockState(pos1);
IBlockState block1 = worldObj.getBlockState(pos1.down());
if (block.getMaterial() == Material.AIR && block1.isFullBlock() && explosionRNG.nextInt(3) == 0)
worldObj.setBlockState(pos1, ACBlocks.liquid_antimatter.getDefaultState());
}
}
@Override
public Map<EntityPlayer, Vec3d> getPlayerKnockbackMap()
{
return field_77288_k;
}
/**
* Returns either the entity that placed the explosive block, the entity that caused the explosion or null.
*/
@Override
public EntityLivingBase getExplosivePlacedBy()
{
return exploder == null ? null : exploder instanceof EntityODBPrimed ? ((EntityODBPrimed)exploder).getODBPlacedBy() : exploder instanceof EntityODBcPrimed ? ((EntityODBcPrimed)exploder).getODBCPlacedBy() : exploder instanceof EntityLivingBase ? (EntityLivingBase)exploder : null;
}
}