mirror of
https://github.com/HbmMods/Hbm-s-Nuclear-Tech-GIT.git
synced 2026-03-11 20:25:36 +00:00
337 lines
12 KiB
Java
337 lines
12 KiB
Java
package com.hbm.entity.projectile;
|
|
|
|
import java.util.List;
|
|
|
|
import com.hbm.handler.threading.PacketThreading;
|
|
import com.hbm.items.weapon.sedna.BulletConfig;
|
|
import com.hbm.packet.toclient.AuxParticlePacketNT;
|
|
|
|
import cpw.mods.fml.common.network.NetworkRegistry.TargetPoint;
|
|
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
|
|
import cpw.mods.fml.relauncher.Side;
|
|
import cpw.mods.fml.relauncher.SideOnly;
|
|
import io.netty.buffer.ByteBuf;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.EntityLivingBase;
|
|
import net.minecraft.entity.monster.EntityMob;
|
|
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;
|
|
|
|
public class EntityBulletBeamBase extends Entity implements IEntityAdditionalSpawnData {
|
|
|
|
public EntityLivingBase thrower;
|
|
public BulletConfig config;
|
|
public float damage;
|
|
public double headingX;
|
|
public double headingY;
|
|
public double headingZ;
|
|
public double beamLength;
|
|
|
|
public EntityBulletBeamBase(World world) {
|
|
super(world);
|
|
this.ignoreFrustumCheck = true;
|
|
this.renderDistanceWeight = 10.0D;
|
|
this.setSize(0.5F, 0.5F);
|
|
this.isImmuneToFire = true;
|
|
}
|
|
|
|
public EntityLivingBase getThrower() { return this.thrower; }
|
|
|
|
public EntityBulletBeamBase(EntityLivingBase entity, BulletConfig config, float baseDamage) {
|
|
this(entity.worldObj);
|
|
|
|
this.thrower = entity;
|
|
this.setBulletConfig(config);
|
|
|
|
this.damage = baseDamage * this.config.damageMult;
|
|
}
|
|
|
|
public EntityBulletBeamBase(EntityLivingBase entity, BulletConfig config, float baseDamage, float angularInaccuracy, 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 + (float) rand.nextGaussian() * angularInaccuracy, thrower.rotationPitch + (float) rand.nextGaussian() * angularInaccuracy);
|
|
|
|
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.headingX = (double) (-MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
|
|
this.headingZ = (double) (MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
|
|
this.headingY = (double) (-MathHelper.sin((this.rotationPitch) / 180.0F * (float) Math.PI));
|
|
|
|
double range = 250D;
|
|
this.headingX *= range;
|
|
this.headingY *= range;
|
|
this.headingZ *= range;
|
|
|
|
performHitscan();
|
|
}
|
|
|
|
public void setRotationsFromVector(Vec3 delta) {
|
|
this.rotationPitch = (float) (-Math.asin(delta.yCoord / delta.lengthVector()) * 180D / Math.PI);
|
|
this.rotationYaw = (float) (-Math.atan2(delta.xCoord, delta.zCoord) * 180D / Math.PI);
|
|
|
|
this.headingX = (double) (-MathHelper.sin(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
|
|
this.headingZ = (double) (MathHelper.cos(this.rotationYaw / 180.0F * (float) Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float) Math.PI));
|
|
this.headingY = (double) (-MathHelper.sin((this.rotationPitch) / 180.0F * (float) Math.PI));
|
|
}
|
|
|
|
public void performHitscanExternal(double range) {
|
|
this.headingX *= range;
|
|
this.headingY *= range;
|
|
this.headingZ *= range;
|
|
performHitscan();
|
|
}
|
|
|
|
@Override
|
|
protected void 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;
|
|
}
|
|
|
|
if(config.onUpdate != null) config.onUpdate.accept(this);
|
|
|
|
super.onUpdate();
|
|
|
|
if(!worldObj.isRemote && this.ticksExisted > config.expires) this.setDead();
|
|
}
|
|
|
|
protected void performHitscan() {
|
|
|
|
Vec3 pos = Vec3.createVectorHelper(this.posX, this.posY, this.posZ);
|
|
Vec3 nextPos = Vec3.createVectorHelper(this.posX + this.headingX, this.posY + this.headingY, this.posZ + this.headingZ);
|
|
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.headingX, this.posY + this.headingY, this.posZ + this.headingZ);
|
|
|
|
if(mop != null) {
|
|
nextPos = Vec3.createVectorHelper(mop.hitVec.xCoord, mop.hitVec.yCoord, mop.hitVec.zCoord);
|
|
}
|
|
|
|
if(!this.worldObj.isRemote && this.doesImpactEntities()) {
|
|
|
|
Entity hitEntity = null;
|
|
List<Entity> list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.addCoord(this.headingX, this.headingY, this.headingZ).expand(1.0D, 1.0D, 1.0D));
|
|
double nearest = 0.0D;
|
|
MovingObjectPosition nonPenImpact = null;
|
|
MovingObjectPosition coinHit = null;
|
|
|
|
double closestCoin = 0;
|
|
EntityCoin hitCoin = null;
|
|
|
|
for(Entity entity : list) {
|
|
if(entity.isDead) continue;
|
|
if(entity instanceof EntityCoin) {
|
|
double hitbox = 0.3F;
|
|
AxisAlignedBB aabb = entity.boundingBox.expand(hitbox, hitbox, hitbox);
|
|
MovingObjectPosition hitMop = aabb.calculateIntercept(pos, nextPos);
|
|
if(hitMop != null) {
|
|
double dist = pos.distanceTo(hitMop.hitVec);
|
|
if(closestCoin == 0 || dist < closestCoin) {
|
|
closestCoin = dist;
|
|
hitCoin = (EntityCoin) entity;
|
|
coinHit = hitMop;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(int j = 0; j < list.size(); ++j) {
|
|
Entity entity = (Entity) list.get(j);
|
|
|
|
if(entity.canBeCollidedWith() && entity != thrower && entity.isEntityAlive()) {
|
|
double hitbox = 0.3F;
|
|
AxisAlignedBB aabb = entity.boundingBox.expand(hitbox, hitbox, hitbox);
|
|
MovingObjectPosition hitMop = aabb.calculateIntercept(pos, nextPos);
|
|
|
|
if(hitMop != null) {
|
|
|
|
double dist = pos.distanceTo(hitMop.hitVec);
|
|
|
|
// if penetration is enabled, run impact for all intersecting entities
|
|
if(this.doesPenetrate()) {
|
|
if(hitCoin == null || dist < closestCoin) {
|
|
this.onImpact(new MovingObjectPosition(entity, hitMop.hitVec));
|
|
}
|
|
} else {
|
|
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(hitCoin != null) {
|
|
Vec3 vec = Vec3.createVectorHelper(coinHit.hitVec.xCoord - posX, coinHit.hitVec.yCoord - posY, coinHit.hitVec.zCoord - posZ);
|
|
this.beamLength = vec.lengthVector();
|
|
|
|
double range = 50;
|
|
List<Entity> targets = worldObj.getEntitiesWithinAABB(Entity.class, AxisAlignedBB.getBoundingBox(coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord, coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord).expand(range, range, range));
|
|
Entity nearestCoin = null;
|
|
Entity nearestPlayer = null;
|
|
Entity nearestMob = null;
|
|
Entity nearestOther = null;
|
|
double coinDist = 0;
|
|
double playerDist = 0;
|
|
double mobDist = 0;
|
|
double otherDist = 0;
|
|
|
|
hitCoin.setDead();
|
|
|
|
// well i mean we could just uuse a single var for all variants and then overwrite stuff
|
|
// when we run into things with higher priority. however i can't be assed fuck off
|
|
for(Entity entity : targets) {
|
|
if(entity == this.getThrower()) continue;
|
|
if(entity.isDead) continue;
|
|
double dist = entity.getDistanceToEntity(hitCoin);
|
|
if(dist > range) continue;
|
|
|
|
if(entity instanceof EntityCoin) {
|
|
if(coinDist == 0 || dist < coinDist) {
|
|
coinDist = dist;
|
|
nearestCoin = entity;
|
|
}
|
|
} else if(entity instanceof EntityPlayer) {
|
|
if(playerDist == 0 || dist < playerDist) {
|
|
playerDist = dist;
|
|
nearestPlayer = entity;
|
|
}
|
|
} else if(entity instanceof EntityMob) {
|
|
if(mobDist == 0 || dist < mobDist) {
|
|
mobDist = dist;
|
|
nearestMob = entity;
|
|
}
|
|
} else if(entity instanceof EntityLivingBase) {
|
|
if(otherDist == 0 || dist < otherDist) {
|
|
otherDist = dist;
|
|
nearestOther = entity;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ternary of shame
|
|
Entity target = nearestCoin != null ? nearestCoin :
|
|
nearestPlayer != null ? nearestPlayer :
|
|
nearestMob != null ? nearestMob :
|
|
nearestOther != null ? nearestOther : null;
|
|
|
|
if(target != null) {
|
|
EntityBulletBeamBase newBeam = new EntityBulletBeamBase(hitCoin.getThrower() != null ? hitCoin.getThrower() : this.thrower, this.config, this.damage * 1.25F);
|
|
newBeam.setPosition(coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord);
|
|
Vec3 delta = Vec3.createVectorHelper(target.posX - newBeam.posX, (target.posY + target.height / 2D) - newBeam.posY, target.posZ - newBeam.posZ);
|
|
newBeam.setRotationsFromVector(delta);
|
|
newBeam.performHitscanExternal(delta.lengthVector());
|
|
worldObj.spawnEntityInWorld(newBeam);
|
|
} else {
|
|
EntityBulletBeamBase newBeam = new EntityBulletBeamBase(hitCoin.getThrower() != null ? hitCoin.getThrower() : this.thrower, this.config, this.damage * 1.25F);
|
|
newBeam.setPosition(coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord);
|
|
newBeam.setRotationsFromVector(Vec3.createVectorHelper(rand.nextGaussian() * 0.5, -1, rand.nextGaussian() * 0.5));
|
|
newBeam.performHitscanExternal(100);
|
|
worldObj.spawnEntityInWorld(newBeam);
|
|
}
|
|
|
|
NBTTagCompound data = new NBTTagCompound();
|
|
data.setString("type", "vanillaExt");
|
|
data.setString("mode", "largeexplode");
|
|
data.setFloat("size", 1.5F);
|
|
data.setByte("count", (byte)1);
|
|
PacketThreading.createAllAroundThreadedPacket(new AuxParticlePacketNT(data, coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord), new TargetPoint(worldObj.provider.dimensionId, coinHit.hitVec.xCoord, coinHit.hitVec.yCoord, coinHit.hitVec.zCoord, 100));
|
|
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
Vec3 vec = Vec3.createVectorHelper(mop.hitVec.xCoord - posX, mop.hitVec.yCoord - posY, mop.hitVec.zCoord - posZ);
|
|
this.beamLength = vec.lengthVector();
|
|
} else {
|
|
Vec3 vec = Vec3.createVectorHelper(nextPos.xCoord - posX, nextPos.yCoord - posY, nextPos.zCoord - posZ);
|
|
this.beamLength = vec.lengthVector();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
protected void onImpact(MovingObjectPosition mop) {
|
|
if(!worldObj.isRemote) {
|
|
if(this.config.onImpactBeam != null) this.config.onImpactBeam.accept(this, mop);
|
|
}
|
|
}
|
|
|
|
public boolean doesImpactEntities() { return this.config.impactsEntities; }
|
|
public boolean doesPenetrate() { return this.config.doesPenetrate; }
|
|
public boolean isSpectral() { return this.config.isSpectral; }
|
|
|
|
@Override @SideOnly(Side.CLIENT) public float getShadowSize() { return 0.0F; }
|
|
|
|
@Override protected void writeEntityToNBT(NBTTagCompound nbt) { }
|
|
@Override public boolean writeToNBTOptional(NBTTagCompound nbt) { return false; }
|
|
@Override public void readEntityFromNBT(NBTTagCompound nbt) { this.setDead(); }
|
|
|
|
@Override public void writeSpawnData(ByteBuf buf) {
|
|
buf.writeDouble(beamLength);
|
|
buf.writeFloat(rotationYaw);
|
|
buf.writeFloat(rotationPitch);
|
|
}
|
|
@Override public void readSpawnData(ByteBuf buf) {
|
|
this.beamLength = buf.readDouble();
|
|
this.rotationYaw = buf.readFloat();
|
|
this.rotationPitch = buf.readFloat();
|
|
}
|
|
|
|
@Override @SideOnly(Side.CLIENT) public boolean canRenderOnFire() { return false; }
|
|
}
|