/**
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.mobs;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.monster.EntitySpider;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.BlockPos;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;
import zeldaswordskills.api.block.IWhipBlock.WhipType;
import zeldaswordskills.api.entity.IEntityLootable;
import zeldaswordskills.entity.IEntityVariant;
import zeldaswordskills.entity.ai.EntityAIPerch;
import zeldaswordskills.entity.ai.EntityAISeekPerch;
import zeldaswordskills.entity.ai.IWallPerch;
import zeldaswordskills.item.ZSSItems;
import zeldaswordskills.ref.Config;
import zeldaswordskills.util.BiomeType;
/**
*
* Skulltulas initially wait in ambush high on trees, lowering down to attack enemies from above.
*
*/
public class EntitySkulltula extends EntitySpider implements IEntityLootable, IEntityVariant, IWallPerch
{
/**
* Returns array of default biomes in which this entity may spawn naturally
*/
public static String[] getDefaultBiomes() {
List<String> biomes = new ArrayList<String>();
biomes.addAll(Arrays.asList(BiomeType.FOREST.defaultBiomes));
biomes.addAll(Arrays.asList(BiomeType.JUNGLE.defaultBiomes));
biomes.addAll(Arrays.asList(BiomeType.TAIGA.defaultBiomes));
return biomes.toArray(new String[biomes.size()]);
}
/** Data watcher index for this entity's variant (type) */
private static final int TYPE_INDEX = 17;
/** Data watcher index tracking this entity's 'perched' status */
private static final int PERCHED_INDEX = 18;
public EntitySkulltula(World world) {
super(world);
Iterator<EntityAITaskEntry> iterator = tasks.taskEntries.iterator();
while (iterator.hasNext()) {
if (iterator.next().action instanceof EntityAIWander) {
iterator.remove();
break;
}
}
this.tasks.addTask(2, new EntityAIPerch(this));
this.tasks.addTask(5, new EntityAISeekPerch(this, 0.8D));
}
@Override
protected void entityInit() {
super.entityInit();
dataWatcher.addObject(TYPE_INDEX, (byte) 0);
dataWatcher.addObject(PERCHED_INDEX, (byte) 0);
}
/**
* 0 for regular, 1 for Gold
*/
@Override
public IEntityVariant setType(int type) {
dataWatcher.updateObject(TYPE_INDEX, (type > 0 ? (byte) 1 : (byte) 0));
return this;
}
/**
* Returns true if this is a Golden Skulltula
*/
public boolean isGolden() {
return (dataWatcher.getWatchableObjectByte(TYPE_INDEX) != 0);
}
@Override
public boolean isPerched() {
return (dataWatcher.getWatchableObjectByte(PERCHED_INDEX) != 0);
}
@Override
public boolean canPerch() {
BlockPos pos = new BlockPos(this);
for (EnumFacing facing : EnumFacing.HORIZONTALS) {
if (worldObj.isSideSolid(pos.offset(facing), facing.getOpposite())) {
return distanceToGround() > 2;
}
}
return false;
}
@Override
public void setPerched(boolean isPerched) {
dataWatcher.updateObject(PERCHED_INDEX, (isPerched ? (byte) 1 : (byte) 0));
}
private int distanceToGround() {
int i = 0;
BlockPos pos = new BlockPos(this).down();
while (!worldObj.isSideSolid(pos, EnumFacing.UP) && pos.getY() > 5) {
pos = pos.down();
++i;
}
return i;
}
@Override
public float getLootableChance(EntityPlayer player, WhipType whip) {
return 0.2F;
}
@Override
public ItemStack getEntityLoot(EntityPlayer player, WhipType whip) {
return new ItemStack(isGolden() ? ZSSItems.skulltulaToken : Items.emerald);
}
@Override
public boolean onLootStolen(EntityPlayer player, boolean wasItemStolen) {
return wasItemStolen || !isGolden();
}
@Override
public boolean isHurtOnTheft(EntityPlayer player, WhipType whip) {
return Config.getHurtOnSteal();
}
@Override
protected void dropFewItems(boolean recentlyHit, int lootingLevel) {
super.dropFewItems(recentlyHit, lootingLevel);
if (isGolden()) {
entityDropItem(new ItemStack(ZSSItems.skulltulaToken), 0.0F);
}
}
@Override
public int getMaxFallHeight() {
return 10;
}
@Override
public void fall(float distance, float damageMultiplier) {}
@Override
public int getTotalArmorValue() {
return super.getTotalArmorValue() + (isGolden() ? 6 : 4);
}
@Override
protected void damageEntity(DamageSource source, float amount) {
super.damageEntity(source, amount);
setPerched(false);
}
@Override
public void onLivingUpdate() {
super.onLivingUpdate();
if (worldObj.isRemote) {
return;
}
if (hurtResistantTime == 0 && (getAttackTarget() == null || getAITarget() == null)) {
if (isPerched() && getBrightness(1.0F) < 0.5F) {
motionY = (worldObj.isSideSolid(new BlockPos(this).up(), EnumFacing.DOWN) || distanceToGround() > 3 ? 0.0D : 0.1D);
EntityPlayer target = worldObj.getClosestPlayerToEntity(this, 8.0D);
if (target != null && !((EntityPlayer) target).capabilities.disableDamage) {
setAttackTarget(target);
setPerched(false);
}
}
} else {
setPerched(false);
}
}
@Override
public IEntityLivingData onInitialSpawn(DifficultyInstance difficulty, IEntityLivingData data) {
// Avoid calling super due to possibility of spawning skeleton (so instead, copy most of EntitySpider's code)
getEntityAttribute(SharedMonsterAttributes.followRange).applyModifier(new AttributeModifier("Random spawn bonus", rand.nextGaussian() * 0.05D, 1));
if (worldObj.rand.nextInt(100) == 0) {
setType(1); // Golden Skulltula
}
if (data == null) {
data = new EntitySpider.GroupData();
if (worldObj.getDifficulty() == EnumDifficulty.HARD && worldObj.rand.nextFloat() < 0.1F * difficulty.getClampedAdditionalDifficulty()) {
((EntitySpider.GroupData) data).func_111104_a(worldObj.rand);
}
}
if (data instanceof EntitySpider.GroupData) {
int i = ((EntitySpider.GroupData) data).potionEffectId;
if (i > 0 && Potion.potionTypes[i] != null) {
this.addPotionEffect(new PotionEffect(i, Integer.MAX_VALUE));
}
}
return data;
}
@Override
public float getBlockPathWeight(BlockPos pos) {
float f = 0.0F;
boolean has_face = false;
for (EnumFacing facing : EnumFacing.HORIZONTALS) {
if (worldObj.isSideSolid(pos.offset(facing), facing.getOpposite())) {
f += (has_face ? -0.1F : 0.1F);
has_face = true;
} else if (has_face) {
f += 0.1F;
}
}
if (!has_face) {
return super.getBlockPathWeight(pos);
}
for (int i = 1; i < 3; ++i) {
if (worldObj.isSideSolid(pos.down(i), EnumFacing.UP)) {
return f;
} else if (worldObj.getBlockState(pos.down(i)).getBlock().getMaterial().isLiquid()) {
return super.getBlockPathWeight(pos);
}
f += (0.1F * i);
}
return f;
}
@Override
public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
compound.setByte("SkulltulaType", dataWatcher.getWatchableObjectByte(TYPE_INDEX));
compound.setBoolean("IsPerched", isPerched());
}
@Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
dataWatcher.updateObject(TYPE_INDEX, compound.getByte("SkulltulaType"));
setPerched(compound.getBoolean("IsPerched"));
}
}