212 lines
7.4 KiB
Java

package com.hbm.entity.projectile;
import com.hbm.items.weapon.sedna.BulletConfig;
import com.hbm.util.BobMathUtil;
import com.hbm.util.EntityDamageUtil;
import com.hbm.util.TrackerUtil;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.util.ForgeDirection;
public class EntityBulletBaseMK4 extends EntityThrowableInterp {
public BulletConfig config;
//used for rendering tracers
public double velocity;
public double prevVelocity;
public float damage;
public int ricochets = 0;
public EntityBulletBaseMK4(World world) {
super(world);
this.renderDistanceWeight = 10.0D;
this.setSize(0.5F, 0.5F);
}
public EntityBulletBaseMK4(EntityLivingBase entity, BulletConfig config, float baseDamage, float gunSpread, double sideOffset, double heightOffset, double frontOffset) {
this(entity.worldObj);
this.thrower = entity;
this.setBulletConfig(config);
this.damage = baseDamage * this.config.damageMult;
this.setLocationAndAngles(thrower.posX, thrower.posY + thrower.getEyeHeight(), thrower.posZ, thrower.rotationYaw, thrower.rotationPitch);
Vec3 offset = Vec3.createVectorHelper(sideOffset, heightOffset, frontOffset);
offset.rotateAroundX(-this.rotationPitch / 180F * (float) Math.PI);
offset.rotateAroundY(-this.rotationYaw / 180F * (float) Math.PI);
this.posX += offset.xCoord;
this.posY += offset.yCoord;
this.posZ += offset.zCoord;
this.setPosition(this.posX, this.posY, this.posZ);
this.motionX = -MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI);
this.motionZ = MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI);
this.motionY = (-MathHelper.sin(this.rotationPitch / 180.0F * (float) Math.PI));
this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, 1.0F, this.config.spread + gunSpread);
}
@Override
protected void entityInit() {
super.entityInit();
this.dataWatcher.addObject(3, Integer.valueOf(0));
}
public void setBulletConfig(BulletConfig config) {
this.config = config;
this.dataWatcher.updateObject(3, config.id);
}
public BulletConfig getBulletConfig() {
int id = this.dataWatcher.getWatchableObjectInt(3);
if(id < 0 || id > BulletConfig.configs.size()) return null;
return BulletConfig.configs.get(id);
}
@Override
public void onUpdate() {
if(config == null) config = this.getBulletConfig();
if(config == null){
this.setDead();
return;
}
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
super.onUpdate();
double dX = this.posX - this.prevPosX;
double dY = this.posY - this.prevPosY;
double dZ = this.posZ - this.prevPosZ;
this.prevVelocity = this.velocity;
this.velocity = Math.sqrt(dX * dX + dY * dY + dZ * dZ);
if(!this.onGround && velocity > 0) {
float hyp = MathHelper.sqrt_double(dX * dX + dZ * dZ);
this.rotationYaw = (float) (Math.atan2(dX, dZ) * 180.0D / Math.PI);
for(this.rotationPitch = (float) (Math.atan2(dY, (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;
}
if(!worldObj.isRemote && this.ticksExisted > config.expires) this.setDead();
if(this.config.onUpdate != null) this.config.onUpdate.accept(this);
}
@Override
public void setDead() {
super.setDead();
//send a teleport on collision so that the bullets are forced to move even if their lifetime is only 1 tick, letting them render
if(worldObj instanceof WorldServer) TrackerUtil.sendTeleport((WorldServer) worldObj, this);
}
@Override
protected void onImpact(MovingObjectPosition mop) {
if(!worldObj.isRemote) {
if(this.config.onImpact != null) this.config.onImpact.accept(this, mop);
if(this.isDead) return;
if(mop.typeOfHit == mop.typeOfHit.BLOCK) {
ForgeDirection dir = ForgeDirection.getOrientation(mop.sideHit);
Vec3 face = Vec3.createVectorHelper(dir.offsetX, dir.offsetY, dir.offsetZ);
Vec3 vel = Vec3.createVectorHelper(motionX, motionY, motionZ).normalize();
double angle = Math.abs(BobMathUtil.getCrossAngle(vel, face) - 90);
if(angle <= config.ricochetAngle) {
this.ricochets++;
if(this.ricochets > this.config.maxRicochetCount) {
this.setPosition(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord);
this.setDead();
}
switch(mop.sideHit) {
case 0: case 1: motionY *= -1; break;
case 2: case 3: motionZ *= -1; break;
case 4: case 5: motionX *= -1; break;
}
worldObj.playSoundAtEntity(this, "hbm:weapon.ricochet", 0.25F, 1.0F);
this.setPosition(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord);
//send a teleport so the ricochet is more accurate instead of the interp smoothing fucking everything up
if(worldObj instanceof WorldServer) TrackerUtil.sendTeleport((WorldServer) worldObj, this);
return;
} else {
this.setPosition(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord);
this.setDead();
}
}
if(mop.typeOfHit == mop.typeOfHit.ENTITY) {
Entity entity = mop.entityHit;
if(entity instanceof EntityLivingBase && ((EntityLivingBase) entity).getHealth() <= 0) {
return;
}
DamageSource damageCalc = this.config.getDamage(this, getThrower(), false);
if(!(entity instanceof EntityLivingBase)) {
EntityDamageUtil.attackEntityFromIgnoreIFrame(entity, damageCalc, this.damage);
return;
}
EntityLivingBase living = (EntityLivingBase) entity;
float prevHealth = living.getHealth();
if(this.config.armorPiercingPercent == 0) {
EntityDamageUtil.attackEntityFromIgnoreIFrame(entity, damageCalc, this.damage);
} else {
DamageSource damagePiercing = this.config.getDamage(this, getThrower(), true);
EntityDamageUtil.attackArmorPiercing(living, damageCalc, damagePiercing, this.damage, this.config.armorPiercingPercent);
}
float newHealth = living.getHealth();
if(this.config.damageFalloffByPen) this.damage -= Math.max(prevHealth - newHealth, 0);
if(!this.doesPenetrate() || this.damage < 0) {
this.setPosition(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord);
this.setDead();
}
}
}
}
@Override protected double headingForceMult() { return 1D; }
@Override public double getGravityVelocity() { return this.config.gravity; }
@Override protected double motionMult() { return this.config.velocity; }
@Override protected float getAirDrag() { return 1F; }
@Override protected float getWaterDrag() { return 1F; }
@Override public boolean doesImpactEntities() { return this.config.impactsEntities; }
@Override public boolean doesPenetrate() { return this.config.doesPenetrate; }
@Override public boolean isSpectral() { return this.config.isSpectral; }
@Override public int selfDamageDelay() { return this.config.selfDamageDelay; }
}