package com.flansmod.common; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import com.flansmod.common.guns.EntityDamageSourceGun; import com.flansmod.common.guns.GrenadeType; import com.flansmod.common.teams.TeamsManager; import com.flansmod.common.types.InfoType; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import net.minecraft.block.Block; 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.item.EntityTNTPrimed; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.network.play.server.S27PacketExplosion; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.DamageSource; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.Explosion; import net.minecraft.world.World; public class FlansModExplosion extends Explosion { /** The type of Flan's Mod weapon that caused this explosion */ private InfoType type; private double x, y, z; private float radius; private World world; private Entity explosive; private EntityPlayer detonator; private List affectedBlockPositions; private final Vec3 position; /** whether or not the explosion sets fire to blocks around it */ private final boolean isFlaming; /** whether or not this explosion spawns smoke particles */ private final boolean isSmoking; private final Random explosionRNG; private final Map playerMap; private boolean breaksBlocks; public FlansModExplosion(World world, Entity entity, EntityPlayer detonator, InfoType type, double x, double y, double z, float radius, boolean flaming, boolean smoking, boolean breaksBlocks) { super(world, entity, x, y, z, radius, flaming, smoking); this.explosionRNG = new Random(); this.affectedBlockPositions = Lists.newArrayList(); this.playerMap = Maps.newHashMap(); this.type = type; this.x = x; this.y = y; this.z = z; this.radius = radius; this.world = world; this.explosive = entity; this.detonator = detonator; this.affectedBlockPositions = Lists.newArrayList(); this.isFlaming = flaming; this.isSmoking = true; this.breaksBlocks = breaksBlocks && TeamsManager.explosions; this.position = new Vec3(x, y, z); if (!net.minecraftforge.event.ForgeEventFactory.onExplosionStart(world, this)) { this.doExplosionA(); this.doExplosionB(true); for(Object obj : world.playerEntities) FlansMod.getPacketHandler().sendTo(new S27PacketExplosion(x, y, z, radius, getAffectedBlockPositions(), (Vec3)getPlayerKnockbackMap().get((EntityPlayer)obj)), (EntityPlayerMP)obj); } } /** First part of the explosion. Damage blocks and entities */ @Override public void doExplosionA() { HashSet hashset = Sets.newHashSet(); boolean flag = true; int j; int k; if(breaksBlocks) { for (int i = 0; i < 16; ++i) { for (j = 0; j < 16; ++j) { for (k = 0; k < 16; ++k) { if (i == 0 || i == 15 || j == 0 || j == 15 || k == 0 || k == 15) { double d0 = (double)((float)i / 15.0F * 2.0F - 1.0F); double d1 = (double)((float)j / 15.0F * 2.0F - 1.0F); double d2 = (double)((float)k / 15.0F * 2.0F - 1.0F); double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2); d0 /= d3; d1 /= d3; d2 /= d3; float f = radius * (0.7F + world.rand.nextFloat() * 0.6F); double d4 = x; double d6 = y; double d8 = z; for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) { BlockPos blockpos = new BlockPos(d4, d6, d8); IBlockState iblockstate = world.getBlockState(blockpos); if (iblockstate.getBlock().getMaterial() != Material.air) { float f2 = explosive != null ? explosive.getExplosionResistance(this, world, blockpos, iblockstate) : iblockstate.getBlock().getExplosionResistance(world, blockpos, (Entity)null, this); f -= (f2 + 0.3F) * 0.3F; } if (f > 0.0F && (explosive == null || explosive.verifyExplosion(this, world, blockpos, iblockstate, f))) { hashset.add(blockpos); } d4 += d0 * 0.30000001192092896D; d6 += d1 * 0.30000001192092896D; d8 += d2 * 0.30000001192092896D; } } } } } } this.affectedBlockPositions.addAll(hashset); float f3 = this.radius * 2.0F; j = MathHelper.floor_double(this.x - (double)f3 - 1.0D); k = MathHelper.floor_double(this.x + (double)f3 + 1.0D); int j1 = MathHelper.floor_double(this.y - (double)f3 - 1.0D); int l = MathHelper.floor_double(this.y + (double)f3 + 1.0D); int k1 = MathHelper.floor_double(this.z - (double)f3 - 1.0D); int i1 = MathHelper.floor_double(this.z + (double)f3 + 1.0D); List list = this.world.getEntitiesWithinAABBExcludingEntity(explosive, new AxisAlignedBB((double)j, (double)j1, (double)k1, (double)k, (double)l, (double)i1)); net.minecraftforge.event.ForgeEventFactory.onExplosionDetonate(this.world, this, list, f3); Vec3 vec3 = new Vec3(x, y, z); for (int l1 = 0; l1 < list.size(); ++l1) { Entity entity = (Entity)list.get(l1); if (!entity.isImmuneToExplosions()) { double d12 = entity.getDistance(x, y, z) / (double)f3; if (d12 <= 1.0D) { double d5 = entity.posX - x; double d7 = entity.posY + (double)entity.getEyeHeight() - y; double d9 = entity.posZ - z; double d13 = (double)MathHelper.sqrt_double(d5 * d5 + d7 * d7 + d9 * d9); if (d13 != 0.0D) { d5 /= d13; d7 /= d13; d9 /= d13; double d14 = (double)this.world.getBlockDensity(vec3, entity.getEntityBoundingBox()); double d10 = (1.0D - d12) * d14; entity.attackEntityFrom(new EntityDamageSourceGun(type.shortName, explosive, detonator, type, false), (float)((int)((d10 * d10 + d10) / 2.0D * 8.0D * (double)f3 + 1.0D))); double d11 = EnchantmentProtection.func_92092_a(entity, d10); entity.motionX += d5 * d11; entity.motionY += d7 * d11; entity.motionZ += d9 * d11; if (entity instanceof EntityPlayer) { this.playerMap.put((EntityPlayer)entity, new Vec3(d5 * d10, d7 * d10, d9 * d10)); } } } } } } /** Second part of the explosion (sound, particles, drop spawn) */ public void doExplosionB(boolean p_77279_1_) { this.world.playSoundEffect(this.x, this.y, this.z, "random.explode", 4.0F, (1.0F + (this.world.rand.nextFloat() - this.world.rand.nextFloat()) * 0.2F) * 0.7F); if (this.isSmoking) { this.world.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D, new int[0]); } else { this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D, new int[0]); } Iterator iterator; BlockPos blockpos; if (isSmoking) { iterator = this.affectedBlockPositions.iterator(); while (iterator.hasNext()) { blockpos = (BlockPos)iterator.next(); Block block = this.world.getBlockState(blockpos).getBlock(); if (p_77279_1_) { double d0 = (double)((float)blockpos.getX() + this.world.rand.nextFloat()); double d1 = (double)((float)blockpos.getY() + this.world.rand.nextFloat()); double d2 = (double)((float)blockpos.getZ() + this.world.rand.nextFloat()); double d3 = d0 - this.x; double d4 = d1 - this.y; double d5 = d2 - this.z; double d6 = (double)MathHelper.sqrt_double(d3 * d3 + d4 * d4 + d5 * d5); d3 /= d6; d4 /= d6; d5 /= d6; double d7 = 0.5D / (d6 / (double)this.radius + 0.1D); d7 *= (double)(this.world.rand.nextFloat() * this.world.rand.nextFloat() + 0.3F); d3 *= d7; d4 *= d7; d5 *= d7; this.world.spawnParticle(EnumParticleTypes.EXPLOSION_NORMAL, (d0 + this.x * 1.0D) / 2.0D, (d1 + this.y * 1.0D) / 2.0D, (d2 + this.z * 1.0D) / 2.0D, d3, d4, d5, new int[0]); this.world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, d0, d1, d2, d3, d4, d5, new int[0]); } if (block.getMaterial() != Material.air) { if (block.canDropFromExplosion(this)) { block.dropBlockAsItemWithChance(this.world, blockpos, this.world.getBlockState(blockpos), 1.0F / this.radius, 0); } block.onBlockExploded(this.world, blockpos, this); } } } if (this.isFlaming) { iterator = this.affectedBlockPositions.iterator(); while (iterator.hasNext()) { blockpos = (BlockPos)iterator.next(); if (this.world.getBlockState(blockpos).getBlock().getMaterial() == Material.air && this.world.getBlockState(blockpos.down()).getBlock().isFullBlock() && this.explosionRNG.nextInt(3) == 0) { this.world.setBlockState(blockpos, Blocks.fire.getDefaultState()); } } } } @Override public Map getPlayerKnockbackMap() { return this.playerMap; } /** * Returns either the entity that placed the explosive block, the entity that caused the explosion or null. */ @Override public EntityLivingBase getExplosivePlacedBy() { return detonator; } @Override public void func_180342_d() { this.affectedBlockPositions.clear(); } @Override public List getAffectedBlockPositions() { return this.affectedBlockPositions; } @Override public Vec3 getPosition(){ return this.position; } }