378 lines
12 KiB
Java

package com.hbm.entity.projectile;
import java.util.List;
import com.hbm.util.TrackerUtil;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
/**
* Near-identical copy of EntityThrowable but deobfuscated & untangled
* @author hbm
*
*/
public abstract class EntityThrowableNT extends Entity implements IProjectile {
private int stuckBlockX = -1;
private int stuckBlockY = -1;
private int stuckBlockZ = -1;
private Block stuckBlock;
protected boolean inGround;
public int throwableShake;
protected EntityLivingBase thrower;
private String throwerName;
public int ticksInGround;
private int ticksInAir;
public EntityThrowableNT(World world) {
super(world);
this.setSize(0.25F, 0.25F);
}
@Override
protected void entityInit() {
this.dataWatcher.addObject(2, Byte.valueOf((byte)0));
}
public void setStuckIn(int side) {
this.dataWatcher.updateObject(2, (byte) side);
}
public int getStuckIn() {
return this.dataWatcher.getWatchableObjectByte(2);
}
@Override
@SideOnly(Side.CLIENT)
public boolean isInRangeToRenderDist(double dist) {
double perimeter = this.boundingBox.getAverageEdgeLength() * 4.0D;
perimeter *= 64.0D;
return dist < perimeter * perimeter;
}
public EntityThrowableNT(World world, EntityLivingBase thrower) {
super(world);
this.thrower = thrower;
this.setSize(0.25F, 0.25F);
this.setLocationAndAngles(thrower.posX, thrower.posY + (double) thrower.getEyeHeight(), thrower.posZ, thrower.rotationYaw, thrower.rotationPitch);
this.posX -= (double) (MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI) * 0.16F);
this.posY -= 0.1D;
this.posZ -= (double) (MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI) * 0.16F);
this.setPosition(this.posX, this.posY, this.posZ);
this.yOffset = 0.0F;
float velocity = 0.4F;
this.motionX = (double) (-MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI) * velocity);
this.motionZ = (double) (MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI) * velocity);
this.motionY = (double) (-MathHelper.sin((this.rotationPitch + this.throwAngle()) / 180.0F * (float) Math.PI) * velocity);
this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, this.throwForce(), 1.0F);
}
public EntityThrowableNT(World world, double x, double y, double z) {
super(world);
this.ticksInGround = 0;
this.setSize(0.25F, 0.25F);
this.setPosition(x, y, z);
this.yOffset = 0.0F;
}
protected float throwForce() {
return 1.5F;
}
protected double headingForceMult() {
return 0.0075D;
}
protected float throwAngle() {
return 0.0F;
}
protected double motionMult() {
return 1.0D;
}
@Override
public void setThrowableHeading(double motionX, double motionY, double motionZ, float velocity, float inaccuracy) {
float throwLen = MathHelper.sqrt_double(motionX * motionX + motionY * motionY + motionZ * motionZ);
motionX /= (double) throwLen;
motionY /= (double) throwLen;
motionZ /= (double) throwLen;
motionX += this.rand.nextGaussian() * headingForceMult() * (double) inaccuracy;
motionY += this.rand.nextGaussian() * headingForceMult() * (double) inaccuracy;
motionZ += this.rand.nextGaussian() * headingForceMult() * (double) inaccuracy;
motionX *= (double) velocity;
motionY *= (double) velocity;
motionZ *= (double) velocity;
this.motionX = motionX;
this.motionY = motionY;
this.motionZ = motionZ;
float hyp = MathHelper.sqrt_double(motionX * motionX + motionZ * motionZ);
this.prevRotationYaw = this.rotationYaw = (float) (Math.atan2(motionX, motionZ) * 180.0D / Math.PI);
this.prevRotationPitch = this.rotationPitch = (float) (Math.atan2(motionY, (double) hyp) * 180.0D / Math.PI);
this.ticksInGround = 0;
}
@Override
@SideOnly(Side.CLIENT)
public void setVelocity(double x, double y, double z) {
this.motionX = x;
this.motionY = y;
this.motionZ = z;
if(this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F) {
float hyp = 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, (double) hyp) * 180.0D / Math.PI);
}
}
@Override
public void onUpdate() {
this.lastTickPosX = this.posX;
this.lastTickPosY = this.posY;
this.lastTickPosZ = this.posZ;
super.onUpdate();
if(this.throwableShake > 0) {
--this.throwableShake;
}
if(this.inGround) {
if(this.worldObj.getBlock(this.stuckBlockX, this.stuckBlockY, this.stuckBlockZ) == this.stuckBlock) {
++this.ticksInGround;
if(this.groundDespawn() > 0 && this.ticksInGround == this.groundDespawn()) {
this.setDead();
}
return;
} else {
this.inGround = false;
this.motionX *= (double) (this.rand.nextFloat() * 0.2F);
this.motionY *= (double) (this.rand.nextFloat() * 0.2F);
this.motionZ *= (double) (this.rand.nextFloat() * 0.2F);
this.ticksInGround = 0;
this.ticksInAir = 0;
}
} else {
++this.ticksInAir;
Vec3 pos = Vec3.createVectorHelper(this.posX, this.posY, this.posZ);
Vec3 nextPos = Vec3.createVectorHelper(this.posX + this.motionX * motionMult(), this.posY + this.motionY * motionMult(), this.posZ + this.motionZ * motionMult());
MovingObjectPosition mop = null;
if(!this.isSpectral()) mop = this.worldObj.func_147447_a(pos, nextPos, false, true, false);
pos = Vec3.createVectorHelper(this.posX, this.posY, this.posZ);
nextPos = Vec3.createVectorHelper(this.posX + this.motionX * motionMult(), this.posY + this.motionY * motionMult(), this.posZ + this.motionZ * motionMult());
if(mop != null) {
nextPos = Vec3.createVectorHelper(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord);
}
if(!this.worldObj.isRemote) {
Entity hitEntity = null;
List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.addCoord(this.motionX * motionMult(), this.motionY * motionMult(), this.motionZ * motionMult()).expand(1.0D, 1.0D, 1.0D));
double nearest = 0.0D;
EntityLivingBase thrower = this.getThrower();
MovingObjectPosition nonPenImpact = null;
for(int j = 0; j < list.size(); ++j) {
Entity entity = (Entity) list.get(j);
if(entity.canBeCollidedWith() && (entity != thrower || this.ticksInAir >= this.selfDamageDelay())) {
double hitbox = 0.3F;
AxisAlignedBB aabb = entity.boundingBox.expand(hitbox, hitbox, hitbox);
MovingObjectPosition hitMop = aabb.calculateIntercept(pos, nextPos);
if(hitMop != null) {
// if penetration is enabled, run impact for all intersecting entities
if(this.doesPenetrate()) {
this.onImpact(new MovingObjectPosition(entity, hitMop.hitVec));
} else {
double dist = pos.distanceTo(hitMop.hitVec);
if(dist < nearest || nearest == 0.0D) {
hitEntity = entity;
nearest = dist;
nonPenImpact = hitMop;
}
}
}
}
}
// if not, only run it for the closest MOP
if(!this.doesPenetrate() && hitEntity != null) {
mop = new MovingObjectPosition(hitEntity, nonPenImpact.hitVec);
}
}
if(mop != null) {
if(mop.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK && this.worldObj.getBlock(mop.blockX, mop.blockY, mop.blockZ) == Blocks.portal) {
this.setInPortal();
} else {
this.onImpact(mop);
}
}
if(!this.onGround) {
float hyp = 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, (double) hyp) * 180.0D / Math.PI); 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;
}
this.rotationPitch = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * 0.2F;
this.rotationYaw = this.prevRotationYaw + (this.rotationYaw - this.prevRotationYaw) * 0.2F;
}
float drag = this.getAirDrag();
double gravity = this.getGravityVelocity();
this.posX += this.motionX * motionMult();
this.posY += this.motionY * motionMult();
this.posZ += this.motionZ * motionMult();
if(this.isInWater()) {
for(int i = 0; i < 4; ++i) {
float f = 0.25F;
this.worldObj.spawnParticle("bubble", this.posX - this.motionX * (double) f, this.posY - this.motionY * (double) f, this.posZ - this.motionZ * (double) f, this.motionX, this.motionY, this.motionZ);
}
drag = this.getWaterDrag();
}
this.motionX *= (double) drag;
this.motionY *= (double) drag;
this.motionZ *= (double) drag;
this.motionY -= gravity;
this.setPosition(this.posX, this.posY, this.posZ);
}
}
public boolean doesPenetrate() {
return false;
}
public boolean isSpectral() {
return false;
}
public int selfDamageDelay() {
return 5;
}
public void getStuck(int x, int y, int z, int side) {
this.stuckBlockX = x;
this.stuckBlockY = y;
this.stuckBlockZ = z;
this.stuckBlock = worldObj.getBlock(x, y, z);
this.inGround = true;
this.motionX = 0;
this.motionY = 0;
this.motionZ = 0;
this.setStuckIn(side);
TrackerUtil.sendTeleport(worldObj, this);
}
public double getGravityVelocity() {
return 0.03D;
}
protected abstract void onImpact(MovingObjectPosition mop);
@Override
public void writeEntityToNBT(NBTTagCompound nbt) {
nbt.setShort("xTile", (short) this.stuckBlockX);
nbt.setShort("yTile", (short) this.stuckBlockY);
nbt.setShort("zTile", (short) this.stuckBlockZ);
nbt.setByte("inTile", (byte) Block.getIdFromBlock(this.stuckBlock));
nbt.setByte("shake", (byte) this.throwableShake);
nbt.setByte("inGround", (byte) (this.inGround ? 1 : 0));
if((this.throwerName == null || this.throwerName.length() == 0) && this.thrower != null && this.thrower instanceof EntityPlayer) {
this.throwerName = this.thrower.getCommandSenderName();
}
nbt.setString("ownerName", this.throwerName == null ? "" : this.throwerName);
}
@Override
public void readEntityFromNBT(NBTTagCompound nbt) {
this.stuckBlockX = nbt.getShort("xTile");
this.stuckBlockY = nbt.getShort("yTile");
this.stuckBlockZ = nbt.getShort("zTile");
this.stuckBlock = Block.getBlockById(nbt.getByte("inTile") & 255);
this.throwableShake = nbt.getByte("shake") & 255;
this.inGround = nbt.getByte("inGround") == 1;
this.throwerName = nbt.getString("ownerName");
if(this.throwerName != null && this.throwerName.length() == 0) {
this.throwerName = null;
}
}
@Override
@SideOnly(Side.CLIENT)
public float getShadowSize() {
return 0.0F;
}
public void setThrower(EntityLivingBase thrower) {
this.thrower = thrower;
}
public EntityLivingBase getThrower() {
if(this.thrower == null && this.throwerName != null && this.throwerName.length() > 0) {
this.thrower = this.worldObj.getPlayerEntityByName(this.throwerName);
}
return this.thrower;
}
/* ================================== Additional Getters =====================================*/
protected float getAirDrag() {
return 0.99F;
}
protected float getWaterDrag() {
return 0.8F;
}
protected int groundDespawn() {
return 1200;
}
}