/**
Copyright (C) <2017> <coolAlias>
This file is part of coolAlias' Zelda Sword Skills Minecraft Mod; as such,
you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package zeldaswordskills.entity.projectile;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityThrowable;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import zeldaswordskills.api.damage.DamageUtils;
import zeldaswordskills.entity.player.ZSSPlayerSkills;
import zeldaswordskills.ref.Sounds;
import zeldaswordskills.skills.SkillBase;
import zeldaswordskills.skills.sword.SwordBeam;
import zeldaswordskills.util.WorldUtils;
/**
*
* Sword beam shot from Link's sword when at full health. Inflicts a portion of
* the original sword's base damage to the first entity struck, less 20% for each
* additional target thus struck.
*
* If using the Master Sword, the beam will shoot through enemies, hitting all
* entities in its direct path.
*
*/
public class EntitySwordBeam extends EntityThrowable implements IEntityAdditionalSpawnData
{
/** Damage that will be inflicted on impact */
private float damage = 4.0F;
/** Skill level of user; affects range */
private int level = 1;
/** Base number of ticks this entity can exist */
private int lifespan = 12;
/** Whether this is the master sword version, which can strike multiple targets */
private boolean isMaster = false;
public EntitySwordBeam(World world) {
super(world);
}
public EntitySwordBeam(World world, EntityLivingBase entity) {
super(world, entity);
}
public EntitySwordBeam(World world, double x, double y, double z) {
super(world, x, y, z);
}
@Override
public void entityInit() {
setSize(0.5F, 0.5F);
}
/**
* Each level increases the distance the beam will travel
*/
public EntitySwordBeam setLevel(int level) {
this.level = level;
this.lifespan += level;
return this;
}
/**
* Sets amount of damage that will be caused onImpact
*/
public EntitySwordBeam setDamage(float amount) {
this.damage = amount;
return this;
}
/**
* Sets whether this beam is capable of striking multiple targets
*/
public EntitySwordBeam setMasterSword(boolean isMaster) {
this.isMaster = isMaster;
return this;
}
@Override
protected float getVelocity() {
return 1.0F + (level * 0.15F);
}
@Override
public float getGravityVelocity() {
return 0.0F;
}
@Override
public float getBrightness(float partialTick) {
return 1.0F;
}
@Override
@SideOnly(Side.CLIENT)
public int getBrightnessForRender(float partialTick) {
return 0xf000f0;
}
@Override
public void onUpdate() {
super.onUpdate();
if (inGround || ticksExisted > lifespan) {
setDead();
}
for (int i = 0; i < 2; ++i) {
worldObj.spawnParticle((i % 2 == 1 ? EnumParticleTypes.CRIT_MAGIC : EnumParticleTypes.CRIT), posX, posY, posZ, motionX + rand.nextGaussian(), 0.01D, motionZ + rand.nextGaussian());
worldObj.spawnParticle((i % 2 == 1 ? EnumParticleTypes.CRIT_MAGIC : EnumParticleTypes.CRIT), posX, posY, posZ, -motionX + rand.nextGaussian(), 0.01D, -motionZ + rand.nextGaussian());
}
}
@Override
protected void onImpact(MovingObjectPosition mop) {
if (!worldObj.isRemote) {
EntityPlayer player = (getThrower() instanceof EntityPlayer ? (EntityPlayer) getThrower() : null);
SwordBeam skill = (player != null ? (SwordBeam) ZSSPlayerSkills.get(player).getPlayerSkill(SkillBase.swordBeam) : null);
if (mop.typeOfHit == MovingObjectType.ENTITY) {
Entity entity = mop.entityHit;
if (player != null) {
if (skill != null) {
skill.onImpact(player, false);
}
if (entity.attackEntityFrom(DamageUtils.causeIndirectComboDamage(this, player).setProjectile(), damage)) {
WorldUtils.playSoundAtEntity(entity, Sounds.DAMAGE_SUCCESSFUL_HIT, 0.4F, 0.5F);
}
damage *= 0.8F;
}
if (!isMaster) {
setDead();
}
} else {
Block block = worldObj.getBlockState(mop.getBlockPos()).getBlock();
if (block.getMaterial() != Material.air) {
block.onEntityCollidedWithBlock(worldObj, mop.getBlockPos(), this);
}
if (block.getMaterial().blocksMovement()) {
if (player != null && skill != null) {
skill.onImpact(player, true);
}
setDead();
}
}
}
}
@Override
public void writeSpawnData(ByteBuf buffer) {
String throwerName = "";
if (getThrower() != null) {
throwerName = getThrower().getName();
}
ByteBufUtils.writeUTF8String(buffer, throwerName);
}
@Override
public void readSpawnData(ByteBuf buffer) {
String throwerName = ByteBufUtils.readUTF8String(buffer);
if (getThrower() == null && throwerName != null && throwerName.length() > 0) {
// EntityThrowable#thrower is private with no setter -.-
ReflectionHelper.setPrivateValue(EntityThrowable.class, this, worldObj.getPlayerEntityByName(throwerName), "field_70192_c", "thrower");
}
}
@Override
public void writeEntityToNBT(NBTTagCompound compound) {
super.writeEntityToNBT(compound);
compound.setBoolean("isMaster", isMaster);
compound.setFloat("damage", damage);
compound.setInteger("level", level);
compound.setInteger("lifespan", lifespan);
}
@Override
public void readEntityFromNBT(NBTTagCompound compound) {
super.readEntityFromNBT(compound);
isMaster = (compound.getBoolean("isMaster"));
damage = compound.getFloat("damage");
level = compound.getInteger("level");
lifespan = compound.getInteger("lifespan");
}
}