/**
Copyright (C) <2015> <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.passive;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.passive.EntityAmbientCreature;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.BlockPos;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import zeldaswordskills.ZSSAchievements;
import zeldaswordskills.entity.player.ZSSPlayerInfo;
import zeldaswordskills.item.ZSSItems;
import zeldaswordskills.ref.Sounds;
import zeldaswordskills.util.TargetUtils;
/**
*
* Classic Zelda fairy can be captured in bottles, heals on contact, and is immune to damage.
*
* They spawn naturally in swamps, but only at night, as well as in water dungeons.
*
*/
public class EntityFairy extends EntityAmbientCreature
{
/**
* randomly selected ChunkCoordinates in a 7x6x7 box around the bat (y offset -2 to 4) towards which it will fly.
* upon getting close a new target will be selected
*/
protected BlockPos currentFlightTarget;
/** Home coordinates where this fairy spawned; will not wander too far from here */
protected BlockPos home = null;
/** Fairies released from bottles into the wild set this to false so they cannot be recaptured */
protected boolean canBeBottled = true;
public EntityFairy(World world) {
super(world);
setSize(0.5F, 0.5F);
isImmuneToFire = true;
}
/**
* Sets the fairy's home coordinates after calling setPositionAndUpdate
*/
public void setFairyHome(BlockPos pos) {
setPositionAndUpdate(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D);
home = pos;
}
/**
* Determines whether this fairy can be recaptured.
* Call when released from a bottle after the fairy home, if any, has been set.
*/
public void onReleased() {
canBeBottled = (home != null);
}
@Override
public boolean isEntityInvulnerable(DamageSource source) {
return true;
}
@Override
public boolean attackEntityFrom(DamageSource source, float amount) {
return false;
}
@Override
public boolean canDespawn() {
return home == null;
}
@Override
public boolean canBePushed() {
return false;
}
@Override
protected boolean canTriggerWalking() {
return false;
}
@Override
public boolean doesEntityNotTriggerPressurePlate() {
return true;
}
@Override
public void fall(float distance, float damageMultiplier) {}
@Override
protected void updateFallState(double par1, boolean par3, Block block, BlockPos pos) {}
@Override
protected float getSoundVolume() {
return 0.1F;
}
@Override
protected String getLivingSound() {
return Sounds.FAIRY_LIVING;
}
@Override
protected void applyEntityAttributes() {
super.applyEntityAttributes();
getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(5.0D);
}
@Override
protected void collideWithEntity(Entity entity) {
if (entity instanceof EntityLivingBase) {
((EntityLivingBase) entity).heal(1.0F);
}
if (entity instanceof EntityPlayer) {
ZSSPlayerInfo.get((EntityPlayer) entity).restoreMagic(0.5F);
}
}
@Override
protected boolean interact(EntityPlayer player) {
ItemStack stack = player.getHeldItem();
if (canBeBottled && stack != null && stack.getItem() == Items.glass_bottle) {
if (!worldObj.isRemote) {
player.triggerAchievement(ZSSAchievements.fairyCatcher);
ItemStack fairyBottle = new ItemStack(ZSSItems.fairyBottle);
if (hasCustomName()) {
fairyBottle.setStackDisplayName(getCustomNameTag());
}
player.setCurrentItemOrArmor(0, fairyBottle);
if (stack.stackSize > 1) {
stack.splitStack(1);
if (!player.inventory.addItemStackToInventory(stack)) {
player.worldObj.spawnEntityInWorld(new EntityItem(player.worldObj, player.posX, player.posY, player.posZ, stack));
}
}
worldObj.playSoundAtEntity(player, Sounds.CORK, 1.0F, 1.0F / (rand.nextFloat() * 0.4F + 1.0F));
setDead();
}
return true;
} else {
return false;
}
}
@Override
public void onUpdate() {
super.onUpdate();
motionY *= 0.6000000238418579D;
if (!worldObj.isRemote && canDespawn()) {
if (worldObj.provider.getDimensionId() == -1 && ticksExisted > 60) {
// TODO terrible scream sound
setDead();
}
if (worldObj.isDaytime() && TargetUtils.canEntitySeeSky(worldObj, this)) {
setDead();
}
}
/* if (isDead) { // reset the current block's light value
worldObj.updateLightByType(EnumSkyBlock.Block, MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ));
} else {
illuminateBlocks(MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ));
} */
}
/**
* Illuminates nearby blocks
* Args: floor_double of current position x/y/z
*/
/*private void illuminateBlocks(int x, int y, int z) {
worldObj.updateLightByType(EnumSkyBlock.Block, MathHelper.floor_double(lastTickPosX), MathHelper.floor_double(lastTickPosY), MathHelper.floor_double(lastTickPosZ));
worldObj.setLightValue(EnumSkyBlock.Block, x, y, z, 15);
worldObj.markBlockRangeForRenderUpdate(x, y, z, 12, 12, 12);
//worldObj.markBlockForUpdate(x, y, z);
/*
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y +1, z);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y +1, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y +1, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y +1, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y +1, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y +1, z);
worldObj.updateLightByType(EnumSkyBlock.Block, x, y +1, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x, y +1, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x, y -1, z);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y -1, z);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y -1, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y -1, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y -1, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y -1, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y -1, z);
worldObj.updateLightByType(EnumSkyBlock.Block, x, y -1, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x, y -1, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y, z);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x +1, y, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y, z -1);
worldObj.updateLightByType(EnumSkyBlock.Block, x -1, y, z);
worldObj.updateLightByType(EnumSkyBlock.Block, x, y, z +1);
worldObj.updateLightByType(EnumSkyBlock.Block, x, y, z -1);
} */
@Override
public boolean getCanSpawnHere() {
// TODO or nearby water, such as underground lakes
return !worldObj.isDaytime() && TargetUtils.canEntitySeeSky(worldObj, this) && super.getCanSpawnHere();
}
@Override
protected void updateAITasks() {
super.updateAITasks();
if (currentFlightTarget != null && (!worldObj.isAirBlock(currentFlightTarget) || currentFlightTarget.getY() < 1)) {
currentFlightTarget = null;
}
if (home != null && (posY < home.getY() || getDistanceSqToCenter(home) > 16D)) {
currentFlightTarget = new BlockPos(home);
} else if (currentFlightTarget == null || rand.nextInt(30) == 0 || currentFlightTarget.distanceSqToCenter((int) posX, (int) posY, (int) posZ) < 4.0F) {
currentFlightTarget = new BlockPos((int) posX + rand.nextInt(7) - rand.nextInt(7), (int) posY + rand.nextInt(6) - 2, (int) posZ + rand.nextInt(7) - rand.nextInt(7));
}
double d0 = (double) currentFlightTarget.getX() + 0.5D - posX;
double d1 = (double) currentFlightTarget.getY() + 0.1D - posY;
double d2 = (double) currentFlightTarget.getZ() + 0.5D - posZ;
motionX += (Math.signum(d0) * 0.5D - motionX) * 0.10000000149011612D;
motionY += (Math.signum(d1) * 0.699999988079071D - motionY) * 0.10000000149011612D;
motionZ += (Math.signum(d2) * 0.5D - motionZ) * 0.10000000149011612D;
float f = (float)(Math.atan2(motionZ, motionX) * 180.0D / Math.PI) - 90.0F;
float f1 = MathHelper.wrapAngleTo180_float(f - rotationYaw);
moveForward = 0.5F;
rotationYaw += f1;
}
@Override
@SideOnly(Side.CLIENT)
public int getBrightnessForRender(float par1) {
int i = super.getBrightnessForRender(par1);
int j = (i & 255) + 120;
int k = (i >> 16) & 255;
if (j > 240) { j = 240; }
return j | k << 16;
}
@Override
public void writeEntityToNBT(NBTTagCompound compound) {
super.writeEntityToNBT(compound);
compound.setBoolean("canBeBottled", canBeBottled);
compound.setBoolean("hasHome", home != null);
if (home != null) {
compound.setLong("FairyHome", home.toLong());
}
}
@Override
public void readEntityFromNBT(NBTTagCompound compound) {
super.readEntityFromNBT(compound);
canBeBottled = compound.getBoolean("canBeBottled");
if (compound.getBoolean("hasHome")) {
home = BlockPos.fromLong(compound.getLong("FairyHome"));
}
}
}