package minefantasy.mf2.entity; import java.util.Iterator; import java.util.List; import java.util.Random; import minefantasy.mf2.MineFantasyII; import minefantasy.mf2.item.gadget.EnumCasingType; import minefantasy.mf2.item.gadget.EnumExplosiveType; import minefantasy.mf2.item.gadget.EnumFuseType; import minefantasy.mf2.item.gadget.EnumPowderType; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.ai.EntityAIAttackOnCollide; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.monster.IMob; import net.minecraft.entity.passive.EntityChicken; import net.minecraft.entity.passive.EntityVillager; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.pathfinding.PathEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import minefantasy.mf2.mechanics.CombatMechanics; public class EntityBomb extends Entity { /** How long the fuse is */ public int fuse; private EntityLivingBase thrower; public EntityBomb(World world) { super(world); this.fuse = getFuseTime(); this.preventEntitySpawning = true; this.setSize(0.5F, 0.5F); this.yOffset = this.height / 2.0F; } public EntityBomb(World world, EntityLivingBase thrower) { this(world); this.thrower = thrower; this.setLocationAndAngles(thrower.posX, thrower.posY + thrower.getEyeHeight(), thrower.posZ, thrower.rotationYaw, thrower.rotationPitch); this.posX -= MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F; this.posY -= 0.10000000149011612D; this.posZ -= MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F; this.setPosition(this.posX, this.posY, this.posZ); float force = this.getThrownForce() + (CombatMechanics.getStrengthEnhancement(thrower)/4); float f = 0.4F; this.motionX = -MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI) * f; this.motionZ = MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI) * f; this.motionY = -MathHelper.sin((this.rotationPitch + this.getThrownOffset()) / 180.0F * (float)Math.PI) * f; this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, force, 1.0F); this.prevPosX = posX; this.prevPosY = posY; this.prevPosZ = posZ; } private int getFuseTime() { return (this.fuse = getFuseType().time) + (isSticky() ? 20 : 0); } public void setThrowableHeading(double x, double y, double z, float offset, float force) { float f2 = MathHelper.sqrt_double(x * x + y * y + z * z); x /= f2; y /= f2; z /= f2; x += this.rand.nextGaussian() * 0.007499999832361937D * force; y += this.rand.nextGaussian() * 0.007499999832361937D * force; z += this.rand.nextGaussian() * 0.007499999832361937D * force; x *= offset; y *= offset; z *= offset; this.motionX = x; this.motionY = y; this.motionZ = z; float f3 = MathHelper.sqrt_double(x * x + z * z); this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(x, z) * 180.0D / Math.PI); this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(y, f3) * 180.0D / Math.PI); } protected float getThrownOffset() { return 0.0F; } protected float getThrownForce() { return 1.5F; } @Override protected void entityInit() { dataWatcher.addObject(typeId, (byte)0); dataWatcher.addObject(typeId+1, (byte)0); dataWatcher.addObject(typeId+2, (byte)0); dataWatcher.addObject(typeId+3, (byte)0); } /** * returns if this entity triggers Block.onEntityWalking on the blocks they walk on. used for spiders and wolves to * prevent them from trampling crops */ @Override protected boolean canTriggerWalking() { return false; } /** * Returns true if other Entities should be prevented from moving through this Entity. */ @Override public boolean canBeCollidedWith() { return true; } /** * Called to update the entity's position/logic. */ @Override public void onUpdate() { this.prevPosX = this.posX; this.prevPosY = this.posY; this.prevPosZ = this.posZ; this.motionY -= (0.03999999910593033D * getGravityModifier()); this.moveEntity(this.motionX, this.motionY, this.motionZ); this.motionX *= 0.9800000190734863D; this.motionY *= 0.9800000190734863D; this.motionZ *= 0.9800000190734863D; if (this.onGround) { double d = 0.75D; this.motionX *= d; this.motionZ *= d; this.motionY *= -0.99D; } List collide = worldObj.getEntitiesWithinAABBExcludingEntity(this, boundingBox); if (!collide.isEmpty() && !(thrower != null && collide.contains(thrower))) { if(isSticky()) { Object object = collide.get(0); if(object instanceof Entity && object != this) { if(this.ridingEntity == null) { this.mountEntity((Entity) object); this.fuse = getFuseTime(); } } } this.motionX = motionZ = 0; } if (this.fuse-- <= 0) { this.setDead(); if (!this.worldObj.isRemote) { this.explode(); } } else { this.worldObj.spawnParticle("smoke", this.posX, this.posY + 0.125D, this.posZ, 0.0D, 0.0D, 0.0D); this.worldObj.spawnParticle("flame", this.posX, this.posY + 0.125D, this.posZ, 0.0D, 0.0D, 0.0D); } if(!worldObj.isRemote && this.ridingEntity != null && ridingEntity instanceof EntityLivingBase) { if(!(ridingEntity instanceof EntityChicken)) { CombatMechanics.panic((EntityLivingBase)ridingEntity, 1.0F, 30); } } if(isStuckInBlock()) { motionX = motionY = motionZ = 0; } } @Override public void mountEntity(Entity object) { super.mountEntity(object); if(object instanceof EntityChicken) { EntityChicken chook = (EntityChicken)object; Entity target = worldObj.findNearestEntityWithinAABB(IMob.class, chook.boundingBox.expand(64, 8, 64),chook); if(target != null) { if(target instanceof EntityLivingBase) { chook.setCustomNameTag("Suicide Chook!"); fuse = getFuseTime()*2; chook.getNavigator().clearPathEntity(); chook.setAttackTarget((EntityLivingBase)target); chook.targetTasks.addTask(1, new EntityAIAttackOnCollide(chook, IMob.class, 1.25D, true)); chook.setAIMoveSpeed(0.5F); } } } } private boolean isStuckInBlock() { return false;//isSticky() && isAABBInSolid(boundingBox.expand(0.5D, 0.5D, 0.5D)); } private boolean isSticky() { return getEntityData().hasKey("stickyBomb"); } private double getGravityModifier() { return isStuckInBlock() ? 0F : getCase().weightModifier; } private void explode2() { float power = 3.5F; this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, power, false); } /** * (abstract) Protected helper method to write subclass entity data to NBT. */ @Override protected void writeEntityToNBT(NBTTagCompound nbt) { nbt.setByte("Fuse", (byte)this.fuse); } /** * (abstract) Protected helper method to read subclass entity data from NBT. */ @Override protected void readEntityFromNBT(NBTTagCompound nbt) { this.fuse = nbt.getByte("Fuse"); } @Override @SideOnly(Side.CLIENT) public float getShadowSize() { return 0.25F; } /** * returns null or the entityliving it was placed or ignited by */ public EntityLivingBase getTntPlacedBy() { return this.thrower; } @Override public void applyEntityCollision(Entity entity) { if(!(thrower != null && thrower == entity)) { this.motionX = 0; this.motionZ = 0; } } public void explode() { worldObj.playSoundAtEntity(this, "random.explode", 0.3F, 10F - 5F); worldObj.createExplosion(this, posX, posY, posZ, 0, false); if (!this.worldObj.isRemote) { double area = getRangeOfBlast()*2D; AxisAlignedBB var3 = this.boundingBox.expand(area, area/2, area); List var4 = this.worldObj.getEntitiesWithinAABB(EntityLivingBase.class, var3); if (var4 != null && !var4.isEmpty()) { Iterator splashDamage = var4.iterator(); while (splashDamage.hasNext()) { Entity entityHit = (Entity)splashDamage.next(); double distanceToEntity = this.getDistanceToEntity(entityHit); double radius = getRangeOfBlast(); if (distanceToEntity < radius) { float dam = getDamage(); if(getCasing() != 2 && distanceToEntity > radius/2) { double sc = distanceToEntity-(radius/2); if(sc < 0)sc = 0; if(sc > (radius/2))sc = (radius/2); dam *= (sc / (radius/2)); } if(!(entityHit instanceof EntityItem)) { DamageSource source = causeBombDamage(this, thrower != null ? thrower:this); source.setExplosion(); if(getFilling() == 2) { source.setFireDamage(); } if(ridingEntity != null && entityHit == ridingEntity) { dam *= 1.5F; } if(entityHit.attackEntityFrom(source, dam)) { applyEffects(entityHit); } } } } } this.setDead(); } int t = getFilling(); if(t > 0) { for(int a = 0; a < 16; a++) { float range = 0.6F; EntityShrapnel shrapnel = new EntityShrapnel(worldObj, posX, posY+0.5D, posZ, (rand.nextDouble()-0.5)*range, (rand.nextDouble()-0.5F)*range, (rand.nextDouble()-0.5)*range); if(t == 2) { shrapnel.setFire(10); } worldObj.spawnEntityInWorld(shrapnel); } } } private void applyEffects(Entity hit) { if(getFilling() == 2) { hit.setFire(5); } if(hit instanceof EntityLivingBase) { EntityLivingBase live = (EntityLivingBase)hit; } } private double getRangeOfBlast() { return getBlast().range * getCase().rangeModifier * getPowderType().rangeModifier; } private int getDamage() { return (int)(getBlast().damage* getCase().damageModifier * getPowderType().damageModifier); } public static DamageSource causeBombDamage(Entity bomb, Entity user) { return (new EntityDamageSourceBomb(bomb, user)).setProjectile(); } public boolean canEntityBeSeen(Entity entity) { return this.worldObj.rayTraceBlocks(Vec3.createVectorHelper(this.posX, this.posY + this.getEyeHeight(), this.posZ), Vec3.createVectorHelper(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ)) == null; } private final int typeId = 2; public byte getFilling() { return dataWatcher.getWatchableObjectByte(typeId); } public byte getCasing() { return dataWatcher.getWatchableObjectByte(typeId+1); } public byte getFuse() { return dataWatcher.getWatchableObjectByte(typeId+2); } public byte getPowder() { return dataWatcher.getWatchableObjectByte(typeId+3); } public EntityBomb setType(byte fill, byte casing, byte fuse, byte powder) { dataWatcher.updateObject(typeId, fill); dataWatcher.updateObject(typeId+1, casing); dataWatcher.updateObject(typeId+2, fuse); dataWatcher.updateObject(typeId+3, powder); this.fuse = getFuseType().time; return this; } private EnumExplosiveType getBlast() { return EnumExplosiveType.getType(getFilling()); } private EnumCasingType getCase() { return EnumCasingType.getType(getCasing()); } private EnumFuseType getFuseType() { return EnumFuseType.getType(getFuse()); } private EnumPowderType getPowderType() { return EnumPowderType.getType(getPowder()); } public boolean isAABBInSolid(AxisAlignedBB field) { int i = MathHelper.floor_double(field.minX); int j = MathHelper.floor_double(field.maxX + 1.0D); int k = MathHelper.floor_double(field.minY); int l = MathHelper.floor_double(field.maxY + 1.0D); int i1 = MathHelper.floor_double(field.minZ); int j1 = MathHelper.floor_double(field.maxZ + 1.0D); for (int k1 = i; k1 < j; ++k1) { for (int l1 = k; l1 < l; ++l1) { for (int i2 = i1; i2 < j1; ++i2) { Block block = worldObj.getBlock(k1, l1, i2); if (block.getMaterial().isSolid()) { int j2 = worldObj.getBlockMetadata(k1, l1, i2); double d0 = (double)(l1 + 1); if (j2 < 8) { d0 = (double)(l1 + 1) - (double)j2 / 8.0D; } if (d0 >= field.minY) { return true; } } } } } return false; } }