package com.hbm.entity.missile; import java.util.ArrayList; import java.util.List; import com.hbm.entity.logic.IChunkLoader; import com.hbm.entity.projectile.EntityThrowableInterp; import com.hbm.explosion.ExplosionLarge; import com.hbm.explosion.vanillant.ExplosionVNT; import com.hbm.explosion.vanillant.standard.BlockAllocatorStandard; import com.hbm.explosion.vanillant.standard.BlockMutatorFire; import com.hbm.explosion.vanillant.standard.BlockProcessorStandard; import com.hbm.explosion.vanillant.standard.EntityProcessorCross; import com.hbm.explosion.vanillant.standard.ExplosionEffectStandard; import com.hbm.explosion.vanillant.standard.PlayerProcessorStandard; import com.hbm.main.MainRegistry; import api.hbm.entity.IRadarDetectableNT; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.util.Vec3; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraftforge.common.ForgeChunkManager; import net.minecraftforge.common.ForgeChunkManager.Ticket; import net.minecraftforge.common.ForgeChunkManager.Type; public abstract class EntityMissileBaseNT extends EntityThrowableInterp implements IChunkLoader, IRadarDetectableNT { public int startX; public int startZ; public int targetX; public int targetZ; public double velocity; public double decelY; public double accelXZ; public boolean isCluster = false; private Ticket loaderTicket; public int health = 50; public EntityMissileBaseNT(World world) { super(world); this.ignoreFrustumCheck = true; startX = (int) posX; startZ = (int) posZ; targetX = (int) posX; targetZ = (int) posZ; } public EntityMissileBaseNT(World world, float x, float y, float z, int a, int b) { super(world); this.ignoreFrustumCheck = true; this.setLocationAndAngles(x, y, z, 0, 0); startX = (int) x; startZ = (int) z; targetX = a; targetZ = b; this.motionY = 2; Vec3 vector = Vec3.createVectorHelper(targetX - startX, 0, targetZ - startZ); accelXZ = decelY = 1 / vector.lengthVector(); decelY *= 2; velocity = 0; this.setSize(1.5F, 1.5F); } @Override public boolean canBeSeenBy(Object radar) { return true; } @Override public boolean paramsApplicable(RadarScanParams params) { if(!params.scanMissiles) return false; return true; } @Override public boolean suppliesRedstone(RadarScanParams params) { if(params.smartMode && this.motionY >= 0) return false; return true; } @Override protected void entityInit() { super.entityInit(); init(ForgeChunkManager.requestTicket(MainRegistry.instance, worldObj, Type.ENTITY)); } @Override protected double motionMult() { return velocity; } @Override public boolean doesImpactEntities() { return false; } @Override public void onUpdate() { super.onUpdate(); if(velocity < 4) velocity += 0.025; if(!worldObj.isRemote) { if(hasPropulsion()) { this.motionY -= decelY * velocity; Vec3 vector = Vec3.createVectorHelper(targetX - startX, 0, targetZ - startZ); vector = vector.normalize(); vector.xCoord *= accelXZ; vector.zCoord *= accelXZ; if(motionY > 0) { motionX += vector.xCoord * velocity; motionZ += vector.zCoord * velocity; } if(motionY < 0) { motionX -= vector.xCoord * velocity; motionZ -= vector.zCoord * velocity; } } else { motionX *= 0.99; motionZ *= 0.99; if(motionY > -1.5) motionY -= 0.05; } if(motionY < -velocity && this.isCluster) { cluster(); this.setDead(); return; } loadNeighboringChunks((int) Math.floor(posX / 16), (int) Math.floor(posZ / 16)); } else { this.spawnContrail(); } float f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ); this.rotationYaw = (float) (Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI); for(this.rotationPitch = (float) (Math.atan2(this.motionY, f2) * 180.0D / Math.PI) - 90; this.rotationPitch - this.prevRotationPitch < -180.0F; this.prevRotationPitch -= 360.0F); while(this.rotationPitch - this.prevRotationPitch >= 180.0F) this.prevRotationPitch += 360.0F; while(this.rotationYaw - this.prevRotationYaw < -180.0F) this.prevRotationYaw -= 360.0F; while(this.rotationYaw - this.prevRotationYaw >= 180.0F) this.prevRotationYaw += 360.0F; } public boolean hasPropulsion() { return true; } protected void spawnContrail() { Vec3 vec = Vec3.createVectorHelper(motionX, motionY, motionZ).normalize(); MainRegistry.proxy.particleControl(posX - vec.xCoord, posY - vec.yCoord, posZ - vec.zCoord, 2); } @Override public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); motionX = nbt.getDouble("moX"); motionY = nbt.getDouble("moY"); motionZ = nbt.getDouble("moZ"); posX = nbt.getDouble("poX"); posY = nbt.getDouble("poY"); posZ = nbt.getDouble("poZ"); decelY = nbt.getDouble("decel"); accelXZ = nbt.getDouble("accel"); targetX = nbt.getInteger("tX"); targetZ = nbt.getInteger("tZ"); startX = nbt.getInteger("sX"); startZ = nbt.getInteger("sZ"); velocity = nbt.getDouble("veloc"); } @Override public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); nbt.setDouble("moX", motionX); nbt.setDouble("moY", motionY); nbt.setDouble("moZ", motionZ); nbt.setDouble("poX", posX); nbt.setDouble("poY", posY); nbt.setDouble("poZ", posZ); nbt.setDouble("decel", decelY); nbt.setDouble("accel", accelXZ); nbt.setInteger("tX", targetX); nbt.setInteger("tZ", targetZ); nbt.setInteger("sX", startX); nbt.setInteger("sZ", startZ); nbt.setDouble("veloc", velocity); } public boolean canBeCollidedWith() { return true; } public boolean attackEntityFrom(DamageSource source, float amount) { if(this.isEntityInvulnerable()) { return false; } else { if(!this.isDead && !this.worldObj.isRemote) { health -= amount; if(this.health <= 0) { this.killMissile(); } } return true; } } protected void killMissile() { this.setDead(); ExplosionLarge.explode(worldObj, posX, posY, posZ, 5, true, false, true); ExplosionLarge.spawnShrapnelShower(worldObj, posX, posY, posZ, motionX, motionY, motionZ, 15, 0.075); ExplosionLarge.spawnMissileDebris(worldObj, posX, posY, posZ, motionX, motionY, motionZ, 0.25, getDebris(), getDebrisRareDrop()); } @Override @SideOnly(Side.CLIENT) public boolean isInRangeToRenderDist(double distance) { return true; } @Override protected void onImpact(MovingObjectPosition mop) { if(mop != null && mop.typeOfHit == mop.typeOfHit.BLOCK) { this.onImpact(); this.setDead(); } } public abstract void onImpact(); public abstract List getDebris(); public abstract ItemStack getDebrisRareDrop(); public void cluster() { } @Override public double getGravityVelocity() { return 0.0D; } @Override protected float getAirDrag() { return 1F; } @Override protected float getWaterDrag() { return 1F; } @Override public void init(Ticket ticket) { if(!worldObj.isRemote) { if(ticket != null) { if(loaderTicket == null) { loaderTicket = ticket; loaderTicket.bindEntity(this); loaderTicket.getModData(); } ForgeChunkManager.forceChunk(loaderTicket, new ChunkCoordIntPair(chunkCoordX, chunkCoordZ)); } } } List loadedChunks = new ArrayList(); public void loadNeighboringChunks(int newChunkX, int newChunkZ) { if(!worldObj.isRemote && loaderTicket != null) { clearChunkLoader(); loadedChunks.clear(); loadedChunks.add(new ChunkCoordIntPair(newChunkX, newChunkZ)); //loadedChunks.add(new ChunkCoordIntPair(newChunkX + (int) Math.floor((this.posX + this.motionX * this.motionMult()) / 16D), newChunkZ + (int) Math.floor((this.posZ + this.motionZ * this.motionMult()) / 16D))); for(ChunkCoordIntPair chunk : loadedChunks) { ForgeChunkManager.forceChunk(loaderTicket, chunk); } } } @Override public void setDead() { super.setDead(); this.clearChunkLoader(); } public void clearChunkLoader() { if(!worldObj.isRemote && loaderTicket != null) { for(ChunkCoordIntPair chunk : loadedChunks) { ForgeChunkManager.unforceChunk(loaderTicket, chunk); } } } public void explodeStandard(float strength, int resolution, boolean fire, boolean largeSmoke) { ExplosionVNT xnt = new ExplosionVNT(worldObj, posX, posY, posZ, strength); xnt.setBlockAllocator(new BlockAllocatorStandard(resolution)); xnt.setBlockProcessor(new BlockProcessorStandard().setNoDrop().withBlockEffect(fire ? new BlockMutatorFire() : null)); xnt.setEntityProcessor(new EntityProcessorCross(7.5D).withRangeMod(2)); xnt.setPlayerProcessor(new PlayerProcessorStandard()); xnt.setSFX(new ExplosionEffectStandard()); if(largeSmoke) ExplosionLarge.spawnParticles(worldObj, posX, posY, posZ, ExplosionLarge.cloudFunction((int) strength)); xnt.explode(); } }