package minefantasy.mf2.entity; import java.util.Iterator; import java.util.List; import minefantasy.mf2.MineFantasyII; import minefantasy.mf2.api.archery.IArrowMF; import minefantasy.mf2.api.archery.IArrowRetrieve; import minefantasy.mf2.api.weapon.IDamageType; import minefantasy.mf2.config.ConfigExperiment; import minefantasy.mf2.config.ConfigWeapon; import minefantasy.mf2.item.archery.ArrowType; 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 minefantasy.mf2.util.MFLogUtil; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IProjectile; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.monster.EntityEnderman; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.play.server.S2BPacketChangeGameState; import net.minecraft.util.AxisAlignedBB; 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 cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class EntityArrowMF extends EntityArrow implements IProjectile, IDamageType, IArrowRetrieve { private boolean playedSound = false; private int xTile = -1; private int yTile = -1; private int zTile = -1; private Block inBlock; private int inData; private boolean inGround; /** 1 if the player can pick up the arrow */ public int canBePickedUp; /** Seems to be some sort of timer for animating an arrow. */ public int arrowShake; /** The owner of this arrow. */ public Entity shootingEntity; private int ticksInGround; private int ticksInAir; private double damage = 2.0D; /** The amount of knockback an arrow applies when it hits a mob. */ private int knockbackStrength; public float velocityModifier = 1.0F; public ArrowType arrowtype = ArrowType.NORMAL; public float firepower = 1F; public EntityArrowMF(World world) { super(world); this.renderDistanceWeight = 10.0D; this.setSize(0.5F, 0.5F); } public EntityArrowMF(World world, double x, double y, double z) { super(world); this.renderDistanceWeight = 10.0D; this.setSize(0.5F, 0.5F); this.setPosition(x, y, z); this.yOffset = 0.0F; } /** * This is for shooting an arrow from a shooting entity to a target(Like skeletons and such) */ public EntityArrowMF(World world, EntityLivingBase shooter, EntityLivingBase target, float accuracy, float power) { super(world); this.renderDistanceWeight = 10.0D; this.shootingEntity = shooter; this.firepower = power; if (shooter instanceof EntityPlayer) { this.canBePickedUp = 1; } this.posY = shooter.posY + shooter.getEyeHeight() - 0.10000000149011612D; double d0 = target.posX - shooter.posX; double d1 = target.boundingBox.minY + target.height / 3.0F - this.posY; double d2 = target.posZ - shooter.posZ; double d3 = MathHelper.sqrt_double(d0 * d0 + d2 * d2); if (d3 >= 1.0E-7D) { float f2 = (float) (Math.atan2(d2, d0) * 180.0D / Math.PI) - 90.0F; float f3 = (float) (-(Math.atan2(d1, d3) * 180.0D / Math.PI)); double d4 = d0 / d3; double d5 = d2 / d3; this.setLocationAndAngles(shooter.posX + d4, this.posY, shooter.posZ + d5, f2, f3); this.yOffset = 0.0F; float f4 = (float) d3 * 0.2F; this.setThrowableHeading(d0, d1 + f4, d2, accuracy, power); } } /** * This method is for firing an arrow from an entity (Mostly player shooting) */ public EntityArrowMF(World world, EntityLivingBase shooter, float power) { this(world, shooter, 1.0F, power); } public EntityArrowMF(World world, EntityLivingBase shooter, float spread, float power) { super(world); this.firepower = power/2F; this.renderDistanceWeight = 10.0D; this.shootingEntity = shooter; if (shooter instanceof EntityPlayer) { this.canBePickedUp = 1; } this.setSize(0.5F, 0.5F); this.setLocationAndAngles( shooter.posX, shooter.posY + shooter.getEyeHeight(), shooter.posZ, shooter.rotationYaw, shooter.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); this.yOffset = 0.0F; 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, power * 1.5F, spread); } public EntityArrowMF setDeisgn(ArrowType type) { this.arrowtype = type; return this; } /** * Implement this with the constructor */ public EntityArrowMF setArrow(ItemStack arrow) { ItemStack arrowStack = arrow.copy(); arrowStack.stackSize = 1; setArrowStack(arrowStack); return this; } public EntityArrowMF setArrowTex(String tex) { updateTex(tex); return this; } private final int texture_dw = 18; private float power = 0F; @Override protected void entityInit() { this.dataWatcher.addObject(16, Byte.valueOf((byte) 0));//Critical this.dataWatcher.addObject(texture_dw, "steel_arrow"); } /** * Similar to setArrowHeading, it's point the throwable entity to a x, y, z * direction. */ @Override public void setThrowableHeading(double x, double y, double z, float angle, float power) { float f2 = MathHelper.sqrt_double(x * x + y * y + z * z); x /= f2; y /= f2; z /= f2; x += this.rand.nextGaussian() * (this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * power; y += this.rand.nextGaussian() * (this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * power; z += this.rand.nextGaussian() * (this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * power; x *= angle; y *= angle; z *= angle; 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); this.ticksInGround = 0; } /** * Sets the position and rotation. Only difference from the other one is no * bounding on the rotation. Args: posX, posY, posZ, yaw, pitch */ @Override @SideOnly(Side.CLIENT) public void setPositionAndRotation2(double x, double y, double z, float yaw, float pitch, int i) { this.setPosition(x, y, z); this.setRotation(yaw, pitch); } /** * Sets the position and rotation. Only difference from the other one is no * bounding on the rotation. Args: posX, posY, posZ, yaw, pitch */ public void setPositionAndRotation(double x, double y, double z, float yaw, float pitch, int i) { this.setPosition(x, y, z); this.setRotation(yaw, pitch); } /** * Sets the velocity to the args. Args: x, y, z */ @Override @SideOnly(Side.CLIENT) public void setVelocity(double xv, double yv, double zv) { this.motionX = xv; this.motionY = yv; this.motionZ = zv; if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F) { float f = MathHelper.sqrt_double(xv * xv + zv * zv); this.prevRotationYaw = this.rotationYaw = (float) (Math.atan2(xv, zv) * 180.0D / Math.PI); this.prevRotationPitch = this.rotationPitch = (float) (Math.atan2( yv, f) * 180.0D / Math.PI); this.prevRotationPitch = this.rotationPitch; this.prevRotationYaw = this.rotationYaw; this.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch); this.ticksInGround = 0; } } /** * Called to update the entity's position/logic. */ @Override public void onUpdate() { super.onEntityUpdate(); if(ConfigExperiment.dynamicArrows && worldObj.isRemote) { return; } if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F) { float f = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ); this.prevRotationYaw = this.rotationYaw = (float) (Math.atan2( this.motionX, this.motionZ) * 180.0D / Math.PI); this.prevRotationPitch = this.rotationPitch = (float) (Math.atan2( this.motionY, f) * 180.0D / Math.PI); } Block block = this.worldObj.getBlock(this.xTile, this.yTile, this.zTile); if (block.getMaterial() != Material.air) { block.setBlockBoundsBasedOnState(this.worldObj, this.xTile, this.yTile, this.zTile); AxisAlignedBB axisalignedbb = block .getCollisionBoundingBoxFromPool(this.worldObj, this.xTile, this.yTile, this.zTile); if (axisalignedbb != null && axisalignedbb.isVecInside(Vec3.createVectorHelper(this.posX, this.posY, this.posZ))) { this.inGround = true; } } if (this.arrowShake > 0) { --this.arrowShake; } if (this.inGround) { int j = this.worldObj.getBlockMetadata(this.xTile, this.yTile, this.zTile); if (block == this.inBlock && j == this.inData) { ++this.ticksInGround; if (this.ticksInGround == 1200) { this.setDead(); } } else { this.inGround = false; this.motionX *= this.rand.nextFloat() * 0.2F; this.motionY *= this.rand.nextFloat() * 0.2F; this.motionZ *= this.rand.nextFloat() * 0.2F; this.ticksInGround = 0; this.ticksInAir = 0; } } else { ++this.ticksInAir; Vec3 vec31 = Vec3.createVectorHelper(this.posX, this.posY, this.posZ); Vec3 vec3 = Vec3.createVectorHelper(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ); MovingObjectPosition movingobjectposition = this.worldObj.func_147447_a(vec31, vec3, false, true, false); vec31 = Vec3.createVectorHelper(this.posX, this.posY, this.posZ); vec3 = Vec3.createVectorHelper(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ); if (movingobjectposition != null) { vec3 = Vec3.createVectorHelper(movingobjectposition.hitVec.xCoord, movingobjectposition.hitVec.yCoord, movingobjectposition.hitVec.zCoord); } Entity entity = null; List list = this.worldObj.getEntitiesWithinAABBExcludingEntity( this, this.boundingBox.addCoord(this.motionX, this.motionY, this.motionZ).expand(1.0D, 1.0D, 1.0D)); double d0 = 0.0D; int i; float f1; for (i = 0; i < list.size(); ++i) { Entity entity1 = (Entity) list.get(i); if (entity1.canBeCollidedWith() && (entity1 != this.shootingEntity || this.ticksInAir >= 5)) { f1 = 0.3F; AxisAlignedBB axisalignedbb1 = entity1.boundingBox.expand( f1, f1, f1); MovingObjectPosition movingobjectposition1 = axisalignedbb1 .calculateIntercept(vec31, vec3); if (movingobjectposition1 != null) { double d1 = vec31 .distanceTo(movingobjectposition1.hitVec); if (d1 < d0 || d0 == 0.0D) { entity = entity1; d0 = d1; } } } } if (entity != null) { movingobjectposition = new MovingObjectPosition(entity); } if (movingobjectposition != null && movingobjectposition.entityHit != null && movingobjectposition.entityHit instanceof EntityPlayer) { EntityPlayer entityplayer = (EntityPlayer) movingobjectposition.entityHit; if (entityplayer.capabilities.disableDamage || this.shootingEntity instanceof EntityPlayer && !((EntityPlayer) this.shootingEntity) .canAttackPlayer(entityplayer)) { movingobjectposition = null; } } float f2; float f4; if (movingobjectposition != null) { if(isExplosive()) { explode(); } if (movingobjectposition.entityHit != null) { f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ) / velocityModifier; // int k = MathHelper.ceiling_double_int((double)f2 * (this.getHitDamage()/3F)); float dam = Math.max(0.1F, this.getHitDamage() * firepower);//(getDamageModifier()*power) / 10F * (float)k; if(!worldObj.isRemote) MFLogUtil.logDebug("Base MF Arrow Damage = " + dam + "force = " + (int)(firepower*100F)); if (this.getIsCritical()) { dam *= (rand.nextFloat()*0.5F)+1.0F; } DamageSource damagesource = null; if (this.shootingEntity == null) { damagesource = DamageSource .causeArrowDamage(this, this); } else { damagesource = DamageSource.causeArrowDamage(this, this.shootingEntity); } if (this.isBurning() && !(movingobjectposition.entityHit instanceof EntityEnderman)) { movingobjectposition.entityHit.setFire(5); } if(isExplosive()) { dam = this.getExplosionDamage(); damagesource.setExplosion(); if(this.getFilling() == 2) { damagesource.setFireDamage(); } } if (movingobjectposition.entityHit.attackEntityFrom(damagesource, dam)) { onHitEntity(movingobjectposition.entityHit, dam); if (movingobjectposition.entityHit instanceof EntityLivingBase) { EntityLivingBase entitylivingbase = (EntityLivingBase) movingobjectposition.entityHit; if (!this.worldObj.isRemote) { entitylivingbase .setArrowCountInEntity(entitylivingbase.getArrowCountInEntity() + 1); } if (this.knockbackStrength > 0) { f4 = MathHelper.sqrt_double(this.motionX* this.motionX + this.motionZ* this.motionZ); if (f4 > 0.0F) { movingobjectposition.entityHit.addVelocity(this.motionX* this.knockbackStrength* 0.6000000238418579D/ f4,0.1D,this.motionZ* this.knockbackStrength* 0.6000000238418579D/ f4); } } if (this.shootingEntity != null && this.shootingEntity instanceof EntityLivingBase) { EnchantmentHelper.func_151384_a(entitylivingbase, this.shootingEntity); EnchantmentHelper.func_151385_b((EntityLivingBase) this.shootingEntity,entitylivingbase); } if (this.shootingEntity != null&& movingobjectposition.entityHit != this.shootingEntity&& movingobjectposition.entityHit instanceof EntityPlayer && this.shootingEntity instanceof EntityPlayerMP) { ((EntityPlayerMP) this.shootingEntity).playerNetServerHandler .sendPacket(new S2BPacketChangeGameState( 6, 0.0F)); } } playHitSound(); if (!(movingobjectposition.entityHit instanceof EntityEnderman)) { this.setDead(); } } else { this.motionX *= -0.10000000149011612D; this.motionY *= -0.10000000149011612D; this.motionZ *= -0.10000000149011612D; this.rotationYaw += 180.0F; this.prevRotationYaw += 180.0F; this.ticksInAir = 0; } } else { this.xTile = movingobjectposition.blockX; this.yTile = movingobjectposition.blockY; this.zTile = movingobjectposition.blockZ; this.inBlock = block; this.inData = this.worldObj.getBlockMetadata( this.xTile, this.yTile, this.zTile); this.motionX = ((float) (movingobjectposition.hitVec.xCoord - this.posX)); this.motionY = ((float) (movingobjectposition.hitVec.yCoord - this.posY)); this.motionZ = ((float) (movingobjectposition.hitVec.zCoord - this.posZ)); f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ); this.posX -= this.motionX / f2 * 0.05000000074505806D; this.posY -= this.motionY / f2 * 0.05000000074505806D; this.posZ -= this.motionZ / f2 * 0.05000000074505806D; playHitSound(); this.inGround = true; this.arrowShake = 7; this.setIsCritical(false); if (this.inBlock.getMaterial() != Material.air) { this.inBlock.onEntityCollidedWithBlock( this.worldObj, this.xTile, this.yTile, this.zTile, this); } if(ConfigWeapon.breakArrowsGround && didArrowBreak()) { breakArrow(); } } if(getEntityData().hasKey("hasBroken_MFArrow")) { worldObj.playSoundAtEntity(this, "random.break", 1.0F, 1.0F); setDead(); } } if (this.getIsCritical()) { for (i = 0; i < 4; ++i) { this.worldObj.spawnParticle("crit", this.posX + this.motionX * i / 4.0D, this.posY + this.motionY * i / 4.0D, this.posZ + this.motionZ * i / 4.0D, -this.motionX, -this.motionY + 0.2D, -this.motionZ); } } this.posX += this.motionX; this.posY += this.motionY; this.posZ += this.motionZ; 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); 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 f3 = 0.99F; f1 = 0.05F; if (this.isInWater()) { for (int l = 0; l < 4; ++l) { f4 = 0.25F; this.worldObj.spawnParticle("bubble", this.posX - this.motionX * f4, this.posY - this.motionY * f4, this.posZ - this.motionZ * f4, this.motionX, this.motionY, this.motionZ); } f3 = 0.8F; } if (this.isWet()) { this.extinguish(); } this.motionX *= f3; this.motionY *= f3; this.motionZ *= f3; this.motionY -= f1*getGravityModifier(); this.setPosition(this.posX, this.posY, this.posZ); this.func_145775_I(); } } private boolean isExplosive() { return getEntityData().hasKey("Explosive"); } private void playHitSound() { if(worldObj.isRemote || playedSound)return; float pitch = 1.0F / (this.rand.nextFloat() * 0.2F + 0.9F); if(this.arrowtype != null && this.arrowtype == ArrowType.BROADHEAD) { pitch *= 0.75F; } this.playSound("minefantasy2:weapon.arrowHit", 0.5F, pitch); playedSound = true; } private void onHitEntity(Entity entityHit, float dam) { ItemStack arrow = getArrowStack(); if(arrow != null && arrow.getItem() instanceof IArrowMF) { ((IArrowMF)arrow.getItem()).onHitEntity(this, shootingEntity, entityHit, dam); } } /** * (abstract) Protected helper method to write subclass entity data to NBT. */ @Override public void writeEntityToNBT(NBTTagCompound nbt) { nbt.setFloat("firepower", firepower); nbt.setBoolean("PlayedSound", playedSound); nbt.setFloat("pierceChance", velocityModifier); nbt.setShort("xTile", (short) this.xTile); nbt.setShort("yTile", (short) this.yTile); nbt.setShort("zTile", (short) this.zTile); nbt.setShort("life", (short) this.ticksInGround); nbt.setByte("inTile", (byte) Block.getIdFromBlock(this.inBlock)); nbt.setByte("inData", (byte) this.inData); nbt.setByte("shake", (byte) this.arrowShake); nbt.setByte("inGround", (byte) (this.inGround ? 1 : 0)); nbt.setByte("pickup", (byte) this.canBePickedUp); nbt.setDouble("damage", this.damage); nbt.setString("arrowTexture", this.getCustomTex()); nbt.setString("arrowtype", arrowtype.name); nbt.setFloat("FirePower", power); } /** * (abstract) Protected helper method to read subclass entity data from NBT. */ @Override public void readEntityFromNBT(NBTTagCompound nbt) { firepower = nbt.getFloat("firepower"); playedSound = nbt.getBoolean("PlayedSound"); velocityModifier = nbt.getFloat("pierceChance"); this.xTile = nbt.getShort("xTile"); this.yTile = nbt.getShort("yTile"); this.zTile = nbt.getShort("zTile"); this.ticksInGround = nbt.getShort("life"); this.inBlock = Block.getBlockById(nbt .getByte("inTile") & 255); this.inData = nbt.getByte("inData") & 255; this.arrowShake = nbt.getByte("shake") & 255; this.inGround = nbt.getByte("inGround") == 1; if (nbt.hasKey("damage", 99)) { this.damage = nbt.getDouble("damage"); } if (nbt.hasKey("pickup", 99)) { this.canBePickedUp = nbt.getByte("pickup"); } else if (nbt.hasKey("player", 99)) { this.canBePickedUp = nbt.getBoolean("player") ? 1 : 0; } if(nbt.hasKey("arrowTexture")) { updateTex(nbt.getString("arrowTexture")); } if(nbt.hasKey("arrowtype")) { ArrowType arrow = ArrowType.arrowMap.get(nbt.getString("arrowtype")); if(arrow != null) { arrowtype = arrow; } } power = nbt.getFloat("FirePower"); } /** * Called by a player entity when they collide with an entity */ @Override public void onCollideWithPlayer(EntityPlayer player) { if (!this.worldObj.isRemote && this.inGround && this.arrowShake <= 0) { boolean canPickUp = this.canBePickedUp == 1 || this.canBePickedUp == 2 && player.capabilities.isCreativeMode; if (this.canBePickedUp == 1 && !player.inventory.addItemStackToInventory(getPickedUpItem())) { canPickUp = false; } if (canPickUp) { this.playSound( "random.pop", 0.2F, ((this.rand.nextFloat() - this.rand.nextFloat()) * 0.7F + 1.0F) * 2.0F); player.onItemPickup(this, 1); this.setDead(); } } } /** * 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; } @Override @SideOnly(Side.CLIENT) public float getShadowSize() { return 0.0F; } @Override public void setDamage(double dam) { this.damage = dam; } @Override public double getDamage() { return this.damage; } /** * Sets the amount of knockback the arrow applies when it hits a mob. */ @Override public void setKnockbackStrength(int str) { this.knockbackStrength = str; } /** * If returns false, the item will not inflict any damage against entities. */ @Override public boolean canAttackWithItem() { return false; } /** * The old critical method called on full charge, I use my own */ @Override public void setIsCritical(boolean flag) { } /** * [New Method] Whether the arrow has a stream of critical hit particles flying behind * it. Called by chance */ public void setCritical(boolean flag) { byte b0 = this.dataWatcher.getWatchableObjectByte(16); if (flag) { this.dataWatcher.updateObject(16, Byte.valueOf((byte) (b0 | 1))); } else { this.dataWatcher.updateObject(16, Byte.valueOf((byte) (b0 & -2))); } } /** * Whether the arrow has a stream of critical hit particles flying behind * it. */ @Override public boolean getIsCritical() { byte b0 = this.dataWatcher.getWatchableObjectByte(16); return (b0 & 1) != 0; } public float getHitDamage() { float dam = 2.0F; ItemStack arrowStack = getArrowStack(); if(arrowStack != null) { if(arrowStack.getItem() instanceof IArrowMF) { dam = ((IArrowMF)arrowStack.getItem()).getDamageModifier(arrowStack); } } if(getEntityData().hasKey("MF_Bow_Damage")) { MFLogUtil.logDebug("Arrow DMG: " + dam + " x Bow DMG: " + getEntityData().getFloat("MF_Bow_Damage")); dam *= getEntityData().getFloat("MF_Bow_Damage"); } return dam; } public float getGravityModifier() { ItemStack arrowStack = getArrowStack(); if(arrowStack != null) { if(arrowStack.getItem() instanceof IArrowMF) { return ((IArrowMF)arrowStack.getItem()).getGravityModifier(arrowStack); } } return 1.0F; } public float getBreakChance() { ItemStack arrowStack = getArrowStack(); if(arrowStack != null) { if(arrowStack.getItem() instanceof IArrowMF) { return ((IArrowMF)arrowStack.getItem()).getBreakChance(this, arrowStack); } } return 1.0F; } @SideOnly(Side.CLIENT) public String getTexture() { return "textures/projectile/"+getCustomTex(); } public ItemStack getPickedUpItem() { return getArrowStack(); } /** * Saves the arrow to the NBT * @param arrow */ private void setArrowStack(ItemStack arrow) { NBTTagCompound arrowNBT = new NBTTagCompound(); arrow.writeToNBT(arrowNBT); getEntityData().setTag("MF_ArrowItem", arrowNBT); } private ItemStack getArrowStack() { if(getEntityData().hasKey("MF_ArrowItem")) { NBTTagCompound heldArrow = getEntityData().getCompoundTag("MF_ArrowItem"); return ItemStack.loadItemStackFromNBT(heldArrow); } return new ItemStack(Items.arrow); } private void updateTex(String tex) { dataWatcher.updateObject(texture_dw, tex); } private String getCustomTex() { try { return dataWatcher.getWatchableObjectString(texture_dw); }catch(Exception e) { MFLogUtil.logWarn("Arrow Failed To Load Texture"); return "steel_arrow"; } } @Override public boolean canBePickedUp() { if(didArrowBreak()) { breakArrow(); return false; } return canBePickedUp == 1; } private void breakArrow() { getEntityData().setBoolean("hasBroken_MFArrow", true); } private boolean didArrowBreak() { if(isExplosive()) { return false; } float c = rand.nextFloat(); float br = getBreakChance() * ConfigWeapon.arrowBreakMod; return c < br; } @Override public ItemStack getDroppedItem() { return getArrowStack(); } @Override public float[] getDamageRatio(Object... implement) { if(isExplosive()) { return new float[]{0,1, 0}; } if(arrowtype != null) { return arrowtype.ratio; } return new float[]{0,0, 1}; } public void modifyVelocity(float velocity) { this.velocityModifier = velocity; motionX*=velocity; motionY*=velocity; motionZ*=velocity; } @Override public float getPenetrationLevel(Object implement) { return arrowtype == ArrowType.BROADHEAD ? -0.5F : 0F; } public void setPower(float f) { power = f; } public EntityArrowMF setBombStats(int powder, int filling) { getEntityData().setInteger("powder", powder); getEntityData().setInteger("filling", filling); getEntityData().setBoolean("Explosive", true); return this; } 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 = getExplosionDamage(); if(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, shootingEntity != null ? shootingEntity:this); source.setExplosion(); if(getFilling() == 2) { source.setFireDamage(); } entityHit.attackEntityFrom(source, dam); } } } } this.setDead(); } int filling = getFilling(); if(filling > 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.5)*range, (rand.nextDouble()-0.5)*range); if(filling == 2) { shrapnel.setFire(10); } worldObj.spawnEntityInWorld(shrapnel); } } } private int getFilling() { return getEntityData().getInteger("filling"); } private int getPowder() { return getEntityData().getInteger("powder"); } private EnumExplosiveType getBlast() { return EnumExplosiveType.getType((byte)getFilling()); } private EnumPowderType getPowderType() { return EnumPowderType.getType((byte)getPowder()); } private double getRangeOfBlast() { return getBlast().range * getPowderType().rangeModifier*0.5F; } private int getExplosionDamage() { return (int)(getBlast().damage* getPowderType().damageModifier*0.5F); } public static DamageSource causeBombDamage(Entity bomb, Entity user) { return (new EntityDamageSourceBomb(bomb, user)).setProjectile(); } }