package com.arkcraft.module.creature.common.entity; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.ai.EntityAIBase; import net.minecraft.entity.passive.EntityTameable; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.inventory.IInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemFood; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.ChatComponentText; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import com.arkcraft.lib.LogHelper; import com.arkcraft.module.core.ARKCraft; import com.arkcraft.module.core.GlobalAdditions.GUI; import com.arkcraft.module.creature.common.container.inventory.InventoryDino; import com.arkcraft.module.creature.common.container.inventory.InventorySaddle; import com.arkcraft.module.creature.common.container.inventory.InventoryTaming; import com.arkcraft.module.items.ARKCraftItems; /** * @author wildbill22 */ public abstract class EntityTameableDinosaur extends EntityTameable { // Stuff that needs to be saved to NBT: public InventoryDino invTamedDino; public InventoryTaming invTaming; public InventorySaddle invSaddle; protected boolean isSaddled = false; protected boolean isTaming = false; // Other non-NBT variables: protected boolean isRideable = false; protected boolean isTameable = false; protected int tamingSeconds = 0; protected EntityAIBase attackPlayerTarget; public SaddleType saddleType; private int DINO_SADDLED_WATCHER = 22; public boolean isSaddled() { isSaddled = (this.dataWatcher.getWatchableObjectByte(DINO_SADDLED_WATCHER) & 1) != 0; return isSaddled; } public void setSaddled(boolean saddled) { if (!this.isChild() && this.isTamed()) { isSaddled = saddled; byte b0 = (byte) (saddled ? 1 : 0); this.dataWatcher.updateObject(DINO_SADDLED_WATCHER, Byte.valueOf(b0)); } } public Item getSaddleType() { return this.saddleType.getSaddleItem(); } public void setSaddleType(int type) { switch (type) { case 0: this.saddleType = SaddleType.NONE; break; case 1: this.saddleType = SaddleType.SMALL; break; case 2: this.saddleType = SaddleType.MEDIUM; break; case 3: this.saddleType = SaddleType.LARGE; break; } } public EntityTameableDinosaur(World worldIn) { super(worldIn); } protected EntityTameableDinosaur(World worldIn, SaddleType saddleType) { super(worldIn); this.getDataWatcher().addObject(DINO_SADDLED_WATCHER, Byte.valueOf((byte) 0)); this.isTameable = true; this.tamingSeconds = 120; // Set this before the InventoryTaming (this // is the default if not set) this.invTamedDino = new InventoryDino("Items", true, saddleType.getInventorySize()); this.invTaming = new InventoryTaming(this); this.saddleType = saddleType; this.invSaddle = new InventorySaddle(); } // Use this constructor if you want to create a dino that is not tameable protected EntityTameableDinosaur(World worldIn, SaddleType saddleType, boolean isTameable, int tamingSeconds) { super(worldIn); this.getDataWatcher().addObject(DINO_SADDLED_WATCHER, Byte.valueOf((byte) 0)); this.isTameable = isTameable; this.saddleType = saddleType; if (isTameable) { this.tamingSeconds = tamingSeconds; // This must be before the // InventoryTaming this.invTamedDino = new InventoryDino("Items", true, saddleType.getInventorySize()); this.invTaming = new InventoryTaming(this); this.invSaddle = new InventorySaddle(); } // Stuff for when tamed this.tasks.addTask(1, this.aiSit); } /** * Clears previous AI Tasks, so the ones defined above will actually * perform. */ protected void clearAITasks() { tasks.taskEntries.clear(); targetTasks.taskEntries.clear(); } /** * Sets the active target the Task system uses for tracking */ public void setAttackTarget(EntityLivingBase target) { super.setAttackTarget(target); if (target == null) { this.setAngry(false); } else if (!this.isTamed()) { this.setAngry(true); } } // //////////////////////////////////// // Properties that all dinos must have // * This must check that the item is an instanceof ItemFood */ public abstract boolean isFavoriteFood(ItemStack itemstack); // //////////////////////////// /** * Determines whether this wolf is angry or not. */ public boolean isAngry() { return (this.dataWatcher.getWatchableObjectByte(16) & 2) != 0; } /** * Sets whether this wolf is angry or not. */ public void setAngry(boolean angry) { byte b0 = this.dataWatcher.getWatchableObjectByte(16); if (angry) { this.dataWatcher.updateObject(16, Byte.valueOf((byte) (b0 | 2))); } else { this.dataWatcher.updateObject(16, Byte.valueOf((byte) (b0 & -3))); } } /** * Drop 0-2 items of this living's type */ @Override protected void dropFewItems(boolean p_70628_1_, int p_70628_2_) { int j = this.rand.nextInt(3) + this.rand.nextInt(1 + p_70628_2_); for (int k = 0; k < j; ++k) { this.dropItem(Items.feather, 1); // TODO: Dodo feather instead } if (this.isBurning()) { this.dropItem(ARKCraftItems.meat_cooked, 1); } else { this.dropItem(ARKCraftItems.meat_raw, 1); } if (this.isSaddled()) { this.dropItem(ARKCraftItems.saddle_large, 1); } if (this.isTamed()) { this.dropItemsInChest(this, this.invTamedDino); } } // TODO: Make these drop in a random circle around where the entity dies private void dropItemsInChest(Entity entity, IInventory inventory) { if (inventory != null && !this.worldObj.isRemote) { for (int i = 0; i < inventory.getSizeInventory(); ++i) { ItemStack itemstack = inventory.getStackInSlot(i); if (itemstack != null) { this.entityDropItem(itemstack, 0.0F); } } } } /** * (abstract) Protected helper method to write subclass entity data to NBT. */ @Override public void writeEntityToNBT(NBTTagCompound nbt) { super.writeEntityToNBT(nbt); if (isTameable) { nbt.setBoolean("isSaddled", isSaddled); nbt.setBoolean("isTaming", isTaming); } if (this.isTamed()) { this.invTamedDino.saveInventoryToNBT(nbt); } else { this.invTaming.saveInventoryToNBT(nbt); } } /** * (abstract) Protected helper method to read subclass entity data from NBT. */ @Override public void readEntityFromNBT(NBTTagCompound nbt) { super.readEntityFromNBT(nbt); if (isTameable) { if (nbt.hasKey("isSaddled")) { this.setSaddled(nbt.getBoolean("isSaddled")); } if (nbt.hasKey("isTaming")) { this.setIsTaming(nbt.getBoolean("isTaming")); } if (this.isTamed()) { final byte NBT_TYPE_COMPOUND = 10; NBTTagList dataForAllSlots = nbt.getTagList("Items", NBT_TYPE_COMPOUND); this.invTamedDino.loadInventoryFromNBT(dataForAllSlots); } else { this.invTaming.loadInventoryFromNBT(nbt); } } } public void setTamed(EntityPlayer player, boolean tamed) { if (player != null && tamed) { player.addChatMessage(new ChatComponentText( "EntityTameableDinosaur: You have tamed the dino!")); this.setAttackTarget((EntityLivingBase) null); // this.aiSit.setSitting(true); this.setHealth(25.0F); this.setOwnerId(player.getUniqueID().toString()); this.playTameEffect(true); this.worldObj.setEntityState(this, (byte) 7); if (attackPlayerTarget != null) { this.targetTasks.removeTask(attackPlayerTarget); } } super.setTamed(tamed); } /* * Plays the hearts / smoke depending on status. If progress is 100, we * always are successful. */ protected void playTameEffect(boolean p_70908_1_) { super.playTameEffect(p_70908_1_); } public boolean isTameable() { return this.isTameable; } public boolean isTaming() { return this.isTaming; } public void setIsTaming(boolean isTaming) { this.isTaming = isTaming; } /** * Used only when tranquilizing a Dino */ public void increaseTorpor(int i) { if (this.isTameable()) { int currTorpor = this.invTaming.getTorporTime(); if (this.invTaming.setTorporTime((short) (currTorpor + i))) { setIsTaming(true); LogHelper.info("EntityTameableDinosaur: Just set taming to true!"); } LogHelper.info("EntityTameableDinosaur: Set torpor to " + this.invTaming .getTorporTime()); } } public int getTorpor() { if (!this.isTamed() && this.isTameable()) { return this.invTaming.getTorporTime(); } else { return 0; } } /** * Called when the entity is attacked. (Needed to attack other mobs) */ @Override public boolean attackEntityFrom(DamageSource damageSource, float damage) { if (this.isEntityInvulnerable(damageSource)) { return false; } else { Entity entity = damageSource.getEntity(); if (entity != null) { // Reduce damage if from player if ((entity instanceof EntityPlayer) && this.isTamed()) { damage = Math.min(damage, 1.0F); } } return super.attackEntityFrom(damageSource, damage); } } /** * Called when attacking an entity */ @Override public boolean attackEntityAsMob(Entity entity) { super.attackEntityAsMob(entity); double attackDamage = this.getEntityAttribute(SharedMonsterAttributes.attackDamage) .getBaseValue(); LogHelper.info("DinoTamable: Attacking with " + attackDamage + " attackDamage."); return entity.attackEntityFrom(DamageSource.causeMobDamage(this), (float) attackDamage); } /** * Determines if an entity can despawn, used on idle far away entities */ @Override protected boolean canDespawn() { return false; } /** * Called when a player interacts with a mob. e.g. gets milk from a cow, * gets into the saddle on a pig. */ @Override public boolean interact(EntityPlayer player) { if (!this.worldObj.isRemote) { LogHelper.info("The player right clicked a Dino."); } ItemStack itemstack = player.inventory.getCurrentItem(); if (isTamed()) { if (this.isOwner(player)) { if (!this.worldObj.isRemote) { player.addChatMessage(new ChatComponentText("This dino is tamed.")); } if (player.isSneaking()) { if (isTamed()) { player.openGui(ARKCraft.instance, GUI.TAMED_DINO.getID(), this.worldObj, (int) Math.floor(this.posX), (int) this.posY, (int) Math.floor(this.posZ)); this.aiSit.setSitting(this.isSitting()); LogHelper.info("Dino is sitting"); this.isJumping = false; this.navigator.clearPathEntity(); return true; } } // not sneaking else if (itemstack != null) { // Heal the Dino with its favorite food if (itemstack != null && isFavoriteFood(itemstack)) { ItemFood itemfood = (ItemFood) itemstack.getItem(); if (!player.capabilities.isCreativeMode) { --itemstack.stackSize; } this.heal((float) itemfood.getHealAmount(itemstack)); if (itemstack.stackSize <= 0) { player.inventory.setInventorySlotContents(player.inventory.currentItem, (ItemStack) null); } if (!this.worldObj.isRemote) { player.addChatMessage(new ChatComponentText( "This dino's health is: " + this.getHealth() + " Max is: " + this .getEntityAttribute(SharedMonsterAttributes.maxHealth) .getBaseValue())); } return true; } else { this.setSitting(!this.isSitting()); } } else { if (isSaddled()) { LogHelper.info("Dino is saddled."); this.setSitting(false); if (!this.worldObj.isRemote) { player.mountEntity(this); } return true; } else { LogHelper.info("Dino is not saddled."); } // this.setSitting(!this.isSitting()); } } else { // end of owner's dino player.addChatMessage(new ChatComponentText( "EntityTameableDinosaur: This dino is tamed, but not yours.")); } } // end of is tamed // Tame the dino with its favorite food else if (isTameable() && itemstack != null && isFavoriteFood(itemstack)) { if (!player.capabilities.isCreativeMode) { --itemstack.stackSize; } if (itemstack.stackSize <= 0) { player.inventory.setInventorySlotContents(player.inventory.currentItem, (ItemStack) null); } if (!this.worldObj.isRemote) { if (this.rand.nextInt(2) == 0) { this.setTamed(player, true); } else { player.addChatMessage(new ChatComponentText( "EntityTameableDinosaur: Taming the dino failed, try again!")); this.playTameEffect(false); this.worldObj.setEntityState(this, (byte) 6); } } return true; } // Tame the dino with the GUI else if (isTaming()) { if (!this.worldObj.isRemote) { player.openGui(ARKCraft.instance, GUI.TAMING_GUI.getID(), this.worldObj, (int) Math.floor(this.posX), (int) this.posY, (int) Math.floor(this.posZ)); LogHelper .info("EntityTameableDinosaur: Opening GUI on Dino at: " + this.posX + "," + this.posY + "," + this.posZ + " (" + (int) Math .floor(this.posX) + "," + (int) this.posY + "," + (int) Math .floor(this.posZ) + ")"); return true; } // player.addChatMessage(new // ChatComponentText("EntityTameableDinosaur: Use a Raw Porkchop to tame the dino.")); } return false; // return super.interact(player); } // private boolean itemIsSaddle(ItemStack itemstack) { // if (itemstack.getItem() == ARKCraftItems.saddle_small || // itemstack.getItem() == ARKCraftItems.saddle_medium || // itemstack.getItem() == ARKCraftItems.saddle_large) // return true; // else // return false; // } public boolean isUseableByPlayer(EntityPlayer player) { final double X_CENTRE_OFFSET = 0.5; final double Y_CENTRE_OFFSET = 0.5; final double Z_CENTRE_OFFSET = 0.5; final double MAXIMUM_DISTANCE_SQ = 8.0 * 8.0; return player.getDistanceSq(this.posX + X_CENTRE_OFFSET, this.posY + Y_CENTRE_OFFSET, this.posZ + Z_CENTRE_OFFSET) < MAXIMUM_DISTANCE_SQ; } public void markDirty() { if (isTameable) { invTamedDino.markDirty(); ; invTaming.markDirty(); } } public int getTamingSeconds() { return this.tamingSeconds; } @Override public void onLivingUpdate() { if (getTorpor() == 0) { super.onLivingUpdate(); } // Paralyze else { this.isJumping = false; this.moveStrafing = 0.0F; this.moveForward = 0.0F; this.randomYawVelocity = 0.0F; this.invTaming.update(); } } /** * The age value may be negative or positive or zero. If it's negative, it * get's incremented on each tick, if it's positive, it get's decremented * each tick. Don't confuse this with EntityLiving.getAge. With a negative * value the Entity is considered a child. */ @Override public int getGrowingAge() { // Added the null check for the dossier if (this.worldObj != null) { return this.worldObj.isRemote ? this.dataWatcher.getWatchableObjectByte(12) : this.field_175504_a; } else { return this.field_175504_a; } } // //////////////////////////// Stuff so you can ride the dino // ///////////////////////////////////////// /** * Returns the Y offset from the entity's position for any entity riding * this one. Override this as needed. */ @Override public double getMountedYOffset() { return (double) this.height * 0.75D; } /** * Dead and sleeping entities cannot move This keeps dino from moving on its * own when you ride it (I think) */ protected boolean isMovementBlocked() { return (this.riddenByEntity != null && this.isSaddled()) || (this.getHealth() <= 0.0F); } /** * Handle any special cases, such as rearing */ public void updateRiderPosition() { super.updateRiderPosition(); } /** * Moves the entity based on the specified heading. Args: strafe, forward * This is needed for rider to move dino! TODO: Add ability to jump if * desired */ public void moveEntityWithHeading(float strafe, float forward) { if (this.riddenByEntity != null && this.riddenByEntity instanceof EntityPlayer && this .isSaddled()) { this.prevRotationYaw = this.rotationYaw = this.riddenByEntity.rotationYaw; this.rotationPitch = this.riddenByEntity.rotationPitch * 0.5F; this.setRotation(this.rotationYaw, this.rotationPitch); this.rotationYawHead = this.renderYawOffset = this.rotationYaw; strafe = ((EntityLivingBase) this.riddenByEntity).moveStrafing * 0.5F; forward = ((EntityLivingBase) this.riddenByEntity).moveForward; if (forward <= 0.0F) { forward *= 0.25F; // this.gallopTime = 0; } // if (this.onGround && this.jumpPower == 0.0F && this.isRearing() // && !this.field_110294_bI) // { // strafe = 0.0F; // forward = 0.0F; // } // if (this.jumpPower > 0.0F && !this.isHorseJumping() && // this.onGround) // { // this.motionY = this.getHorseJumpStrength() * // (double)this.jumpPower; // // if (this.isPotionActive(Potion.jump)) // { // this.motionY += // (double)((float)(this.getActivePotionEffect(Potion.jump).getAmplifier() // + 1) * 0.1F); // } // // this.setHorseJumping(true); // this.isAirBorne = true; // // if (forward > 0.0F) // { // float f2 = MathHelper.sin(this.rotationYaw * (float)Math.PI / // 180.0F); // float f3 = MathHelper.cos(this.rotationYaw * (float)Math.PI / // 180.0F); // this.motionX += (double)(-0.4F * f2 * this.jumpPower); // this.motionZ += (double)(0.4F * f3 * this.jumpPower); // this.playSound("mob.horse.jump", 0.4F, 1.0F); // } // // this.jumpPower = 0.0F; // net.minecraftforge.common.ForgeHooks.onLivingJump(this); // } this.stepHeight = 1.0F; this.jumpMovementFactor = this.getAIMoveSpeed() * 0.1F; if (!this.worldObj.isRemote) { this.setAIMoveSpeed((float) this.getEntityAttribute( SharedMonsterAttributes.movementSpeed).getAttributeValue()); super.moveEntityWithHeading(strafe, forward); } // if (this.onGround) // { // this.jumpPower = 0.0F; // this.setHorseJumping(false); // } this.prevLimbSwingAmount = this.limbSwingAmount; double d1 = this.posX - this.prevPosX; double d0 = this.posZ - this.prevPosZ; float f4 = MathHelper.sqrt_double(d1 * d1 + d0 * d0) * 4.0F; if (f4 > 1.0F) { f4 = 1.0F; } this.limbSwingAmount += (f4 - this.limbSwingAmount) * 0.4F; this.limbSwing += this.limbSwingAmount; } else { this.stepHeight = 0.5F; this.jumpMovementFactor = 0.02F; super.moveEntityWithHeading(strafe, forward); } } }