package net.tropicraft.entity.underdasea; import java.util.ArrayList; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.passive.EntityWaterMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.world.World; public abstract class EntityTropicraftWaterMob extends EntityWaterMob { protected WaterMobType type; public Entity targetEntity; protected float climbFactor; protected float horFactor; protected int hyperness; protected int fickleness; public boolean isSurfacing; public boolean reachedTarget; public float important1; public float randomMotionSpeed; public float important2; protected float randomMotionVecX; protected float randomMotionVecY; protected float randomMotionVecZ; public int targetHeight; public int surfaceTick; public int targetHeightTick = 120; //TODO: Implement for fishing public boolean isCatchable; public int outOfWaterTick = 0; public double fishingMaxLookDist = 10D; public int fishingImmediateDispatchOdds = 10; public int fishingInterestOdds = 10; public int fishingBreakLineOdds = 500; public float fishingApproachSpeed = 1.4f; public float fishingEscapeSpeed = 2.4f; public static boolean fishingDebug = false; public List<String> fishingLog = new ArrayList<String>(); public EntityTropicraftWaterMob(World world) { super(world); important1 = 0.0F; randomMotionSpeed = 0.0F; important2 = 0.0F; important2 = (1.0F / (rand.nextFloat() + 1.0F)) * 0.2F; randomMotionVecX = 0.0F; randomMotionVecY = 0.0F; randomMotionVecZ = 0.0F; reachedTarget = true; targetHeight = 62; isSurfacing = false; surfaceTick = 0; hyperness = 30; fickleness = 150; horFactor = .1F; climbFactor = .1F; this.experienceValue = 5; this.type = WaterMobType.OCEAN_DWELLER; } public EntityTropicraftWaterMob(World par1World, WaterMobType type) { this(par1World); this.type = type; } protected abstract int attackStrength(); @Override public void onLivingUpdate() { super.onLivingUpdate(); if (worldObj.isRemote) return; // Orient creature important1 += important2; if(prevRotationPitch == 0.0F && prevRotationYaw == 0.0f) { float f = MathHelper.sqrt_double(motionX * motionX + motionZ * motionZ); prevRenderYawOffset = renderYawOffset = (float)((Math.atan2(motionX, motionZ) * 180D) / 3.1415927410125732D); prevRotationPitch = rotationPitch = (float)((Math.atan2(motionY, f) * 180D) / 3.1415927410125732D); } float f3 = MathHelper.sqrt_double(motionX * motionX + motionZ * motionZ); for(rotationPitch = (float)((Math.atan2(motionY, f3) * 180D) / 3.1415927410125732D); rotationPitch - prevRotationPitch < -180F; prevRotationPitch -= 360F) { } for(; rotationPitch - prevRotationPitch >= 180F; prevRotationPitch += 360F) { } rotationPitch = prevRotationPitch + (rotationPitch - prevRotationPitch) * 0.2F; if(important1 > 6.283185F) { important1 -= 6.283185F; if(rand.nextInt(10) == 0) { important2 = (1.0F / (rand.nextFloat() + 1.0F)) * 0.2F; } } // Move towards the surface if(surfaceTick != 0){ surfaceTick--; } if(!isSurfacing) { // Wander if(important1 < 3.141593F) { float f = important1 / 3.141593F; if((double)f > 0.75D) { randomMotionSpeed = 1.0F; } } else { randomMotionSpeed = randomMotionSpeed * 0.95F; } if(!worldObj.isRemote && targetEntity == null) { motionX = randomMotionVecX * randomMotionSpeed; motionY = randomMotionVecY * randomMotionSpeed; motionZ = randomMotionVecZ * randomMotionSpeed; } if(targetEntity == null){ renderYawOffset += ((-(float)Math.atan2(motionX, motionZ) * 180F) / 3.141593F - renderYawOffset) * 0.1F; rotationYaw = renderYawOffset; } } if(isInWater()) { } else { // Rise to surface if(!worldObj.isRemote) { motionX = 0.0D; motionY *= 0.98000001907348633D; motionZ = 0.0D; } // Done surfacing if(surfaceTick == 0){ isSurfacing = false; } //if (isInWater()) { this.setAir(20 * 20); //} if(!isInWater() && deathTime == 0) { //motionY += .50; /*this.attackEntityFrom(DamageSource.drown, 1); int d = 1; int e = 1; if(rand.nextInt(2) == 0){ d = -1; } if(rand.nextInt(2) == 0){ e = -1; } motionZ = rand.nextFloat()*.20F *d; motionX = rand.nextFloat()*.20F*e;*/ } Block blockUnder = worldObj.getBlock(MathHelper.floor_double(posX), MathHelper.floor_double(posY - 1), MathHelper.floor_double(posZ)); Block blockAt = worldObj.getBlock(MathHelper.floor_double(posX), MathHelper.floor_double(posY), MathHelper.floor_double(posZ)); if (!blockUnder.getMaterial().isSolid()) { if(blockAt == Blocks.air){ motionY -= 0.080000000000000002D; } } else { motionY += 0.2D; this.moveEntity(motionX, motionY, motionZ); } } } @Override public boolean isAIEnabled() { return false; } @Override protected void updateEntityActionState() { ++this.entityAge; // this.despawnEntity(); if(targetEntity != null) { if(targetEntity.isDead || !targetEntity.isInWater() || this.getDistanceToEntity(targetEntity) > 10) { targetEntity = null; } else if(inWater) { if(targetEntity.posY > this.type.shallowDepth || !targetEntity.isInWater()) { targetEntity = null; } if(attackTime == 0 && targetEntity != null) { attackEntity(targetEntity); } if(attackTime > 0) { motionZ = Math.cos((renderYawOffset) / 57.26) * horFactor; motionX = Math.sin((renderYawOffset) / 57.26) * horFactor; motionY = 0; } } } if(targetEntity == null) { targetEntity = this.getAttackTarget(); if(rand.nextInt(hyperness) == 0 || !inWater || randomMotionVecX == 0.0F && randomMotionVecY == 0.0F && randomMotionVecZ == 0.0F) { float f = rand.nextFloat() * 3.141593F * 2.0F; randomMotionVecX = MathHelper.cos(f) * horFactor; randomMotionVecZ = MathHelper.sin(f) * horFactor; } if(!isSurfacing && isInWater()) { if(!reachedTarget) { targetHeightTick --; } if(targetHeightTick == 0) { targetHeightTick = 120; reachedTarget = true; } if(posY <= targetHeight + .15 && posY >= targetHeight - .15 || reachedTarget == true) { reachedTarget = true; targetHeightTick = 120; randomMotionVecY = 0; if(rand.nextInt(fickleness) == 0) { reachedTarget = getTargetHeight(); } } else if(posY > targetHeight && !reachedTarget) { randomMotionVecY = -climbFactor; } else if(posY < targetHeight && !reachedTarget) { randomMotionVecY = climbFactor; } } } } protected int getDistanceToBase(int i, int height) { if (worldObj.getBlock(MathHelper.floor_double(posX), height - i, MathHelper.floor_double(posZ)).getMaterial().isLiquid()) { //System.out.println("I = " + i); return getDistanceToBase(i + 1, height); } else { return i; } } /** * Recursively counts the number of water blocks between this mob and the surface * @param i * @return */ protected int getDistanceToSurface(int i){ if(worldObj.getBlock(MathHelper.floor_double(posX), (int)posY + i, MathHelper.floor_double(posZ)).getMaterial().isLiquid()) { return getDistanceToSurface(i + 1); } else { return i; } } /** * Get the height this water mob is trying to get to * @return */ protected boolean getTargetHeight() { if(isWet() && !isSurfacing ) { if(posY < this.type.shallowDepth + 1) { int depth = (int)(getDistanceToBase(0, 62)); if(depth < 1) { targetHeight = (int)posY; return false; } else if(depth < 63 - this.type.shallowDepth) { targetHeight = 63 - rand.nextInt(depth + 1); if(targetHeight == 63){ targetHeight--; } return false; } else { depth -= 63 - this.type.shallowDepth; if(depth > this.type.deepDepth) { depth = this.type.deepDepth; } targetHeight = this.type.shallowDepth - rand.nextInt(depth + 1); return false; } } else { //System.out.println("Finding Distance to Surface"); int height = getDistanceToSurface(0); height += (int)posY; //System.out.println("Height = " + height + "PosY = " + posY); int depth = getDistanceToBase(0, height - 1); //System.out.println("Depth = " + depth); if(depth < 1) { targetHeight = (int)posY; return false; } else{ int i1 = (int)(rand.nextInt(depth)); if(i1 == 0) { i1 = 1; } targetHeight = height - i1; //System.out.println("TargetHeight is " + targetHeight); return false; } } } return true; } public void setAttackHeading(double d, double d1, double d2, float f, float f1) { float f2 = MathHelper.sqrt_double(d * d + d1 * d1 + d2 * d2); d /= f2; d1 /= f2; d2 /= f2; d *= f; d1 *= f; d2 *= f; motionX = d; motionY = d1; motionZ = d2; } /** * Faces an entity, then moves towards it to attack it * @param entity */ protected void attackEntity(Entity entity) { double d = entity.posX - posX; double d1 = entity.posZ - posZ; faceEntity(targetEntity, 360F, 360F); double d2 = entity.posY - posY; float f1 = MathHelper.sqrt_double(d * d + d1 * d1) * 0.2F; setAttackHeading(d, d2, d1, horFactor, 12F); } /** * 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; } /** * Checks if this entity is inside water (if inWater field is true as a result of handleWaterMovement() returning * true) */ @Override public boolean isInWater() { return super.isInWater();//this.worldObj.handleMaterialAcceleration(this.boundingBox.expand(0.0D, -0.6000000238418579D, 0.0D), Material.water, this); } /** * Checks if the entity's current position is a valid location to spawn this entity. */ @Override public boolean getCanSpawnHere() { return this.posY > 45.0D && this.posY < 63.0D && super.getCanSpawnHere(); } @Override protected void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(10.0D); // this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.20000000298023224D); } @Override public void applyEntityCollision(Entity entity){ super.applyEntityCollision(entity); if(targetEntity != null && entity.equals(targetEntity)){ if(attackStrength() != 0){ targetEntity.attackEntityFrom(DamageSource.causeMobDamage(this), attackStrength()); attackTime = 60; } } } public WaterMobType getType() { return this.type; } @Override public int getTalkInterval() { return 120; } @Override protected boolean canDespawn() { return false; } @Override protected int getExperiencePoints(EntityPlayer entityplayer) { return 1 + worldObj.rand.nextInt(3); } @Override public void moveEntityWithHeading(float f, float f1) { moveEntity(motionX, motionY, motionZ); } /** * Returns the sound this mob makes while it's alive. */ @Override protected String getLivingSound() { return null; } /** * Returns the sound this mob makes when it is hurt. */ @Override protected String getHurtSound() { return null; } /** * Returns the sound this mob makes on death. */ @Override protected String getDeathSound() { return null; } /** * Returns the volume for the sounds this mob makes. */ @Override protected float getSoundVolume() { return 0.4F; } public static enum WaterMobType { //TODO CHANGE THIS TO BE THE WATER HEIGHT LEVEL IN THE TROPICS! SURFACE_TROPICS(90, 88), SURFACE_OVERWORLD(63, 62), OCEAN_DWELLER(62, 32); /** The highest this water mob can go in the water (eg, the highest y-value) */ final int shallowDepth; /** The deepest this water mob can go in the water (eg, the smallest y-value) */ final int deepDepth; private WaterMobType(int shallowDepth, int deepDepth) { this.shallowDepth = shallowDepth; this.deepDepth = deepDepth; } public int getShallowDepth() { return this.shallowDepth; } public int getDeepDepth() { return this.deepDepth; } } @Override public void entityInit(){ this.dataWatcher.addObject(26, Integer.valueOf(-1)); super.entityInit(); } public int getHookID(){ return this.dataWatcher.getWatchableObjectInt(26); } public void setHookID(int i){ this.dataWatcher.updateObject(26, Integer.valueOf(i)); } public boolean fishingIsInterested = false; public void onFishingUpdate(){ // If we're hooked, check the validity of it if(this.getHookID() != -1){ List<Entity> l = worldObj.loadedEntityList; for(Entity e : l){ if(e.getEntityId() == getHookID()){ if(e.isDead){ // invalid, so set un-hooked //System.out.println("Gross"); setHookID(-1); } if(rand.nextInt(this.fishingBreakLineOdds) == 0){ if(!worldObj.isRemote){ //fishDebug("I managed to get your hook, see ya ;D"); //e.setDead(); } } } } } /* List<Entity> l = worldObj.loadedEntityList; for(Entity entity : l){ // we're up against the player's fishing rod if(entity instanceof EntityHook && !worldObj.isRemote){ EntityHook hook = (EntityHook)entity; if(hook.isDead){ continue; } if(hook.bobber == null){ // this.isSurfacing = true; // fish collision with bobber if(hook.boundingBox.expand(1f, 1f, 1f).intersectsWith(this.boundingBox) && rand.nextInt(this.fishingImmediateDispatchOdds) == 0){ hook.bobber = this; fishDebug("I'm hooked!"); // hook fish to the bobber, also set the hook id for reference this.posX = hook.posX; this.posY = hook.posY; this.posZ = hook.posZ; this.setHookID(hook.getEntityId()); continue; }else{ if(this.getDistanceToEntity(hook) < fishingMaxLookDist && this.canEntityBeSeen(hook) && rand.nextInt(this.fishingInterestOdds) == 0) { if(!isInWater()){ fishingIsInterested = false; return; } fishingIsInterested = true; fishDebug("Okay player, I want your hook!"); this.reachedTarget = false; this.faceEntity(hook, 100f, 100f); motionX = -((fishingApproachSpeed / 10) * Math.sin(Math.toRadians(rotationYaw))); motionZ = ((fishingApproachSpeed / 10) * Math.cos(Math.toRadians(rotationYaw))); // if(this.getDistanceToEntity(hook) < 4D) motionY = (hook.posY > this.posY + this.height ? 0.2f : -0.2F); //this.isSurfacing = true; }else{ fishingIsInterested = false; } } } } // we're up against a koa's fishing rod if(entity instanceof EntityTropicalFishHook && !worldObj.isRemote){ EntityTropicalFishHook hook = (EntityTropicalFishHook)entity; if(hook.isDead){ continue; } if(hook.bobber == null){ // fish collision with bobber if(rand.nextInt(this.fishingImmediateDispatchOdds) == 0){ fishDebug("I escaped the Koa's clutches!"); return; } if(hook.boundingBox.expand(2d, 2d, 2d).intersectsWith(this.boundingBox)){ hook.bobber = this; // hook fish to the bobber, also set the hook id for reference fishDebug("Hooked by a Koa!"); this.setHookID(hook.getEntityId()); continue; }else{ if(this.getDistanceToEntity(hook) < fishingMaxLookDist && this.canEntityBeSeen(hook) && rand.nextInt(this.fishingInterestOdds) == 0) { if(!isInWater()){ return; } fishDebug("I see a Koa hook worth going for!"); this.reachedTarget = false; this.faceEntity(hook, 100f, 100f); motionX = -((fishingApproachSpeed / 10) * Math.sin(Math.toRadians(rotationYaw))); motionZ = ((fishingApproachSpeed / 10) * Math.cos(Math.toRadians(rotationYaw))); motionY = hook.posY > this.posY + this.height ? 0.2f : -0.2F; this.isSurfacing = true; } } } } } // Resist once grabbed if(this.getHookID() != -1){ l = worldObj.loadedEntityList; for(Entity e : l){ if(e instanceof EntityHook){ EntityHook hook = (EntityHook) e; if(e.getEntityId() == getHookID() && hook.bobber != this){ fishDebug("Taking this player's hook for a swim \\o/!"); if(this.isInWater()){ //motionX += -((fishingEscapeSpeed) * Math.sin(Math.toRadians(rotationYaw))); //motionZ += ((fishingEscapeSpeed) * Math.cos(Math.toRadians(rotationYaw))); } double y = hook.getVecToPlayer().yCoord; if(y > 0){ // hook.angler.faceEntity(this, 1f, 1f); } //if(!this.isCollidedVertically) //motionY = -0.05F; } } if(e instanceof EntityTropicalFishHook){ EntityTropicalFishHook hook = (EntityTropicalFishHook) e; if(e.getEntityId() == getHookID() && hook.bobber != null && hook.angler != null){ this.faceEntity(hook.angler, 100f, 100f); faceEntity(hook.angler, this, 100f, 100f); fishDebug("D: KOA'S ARE GONNA KILL AND EAT ME!!!"); motionX = -((fishingEscapeSpeed / 10) * Math.sin(Math.toRadians(rotationYaw))); motionZ = ((fishingEscapeSpeed / 10) * Math.cos(Math.toRadians(rotationYaw))); motionY = (hook.angler.posY+(hook.angler.height/2)) > this.posY + this.height ? 0.2f : -0.2F; hook.posX = this.posX; hook.posY = this.posY; hook.posZ = this.posZ; //hook.motionY = 0; if(this.getDistanceToEntity(hook.angler) < 3D){ fishDebug("This is it for me, farewell..."); hook.angler.swingItem(); hook.angler.attackEntityAsMob(this); } } } } }*/ } public void fishDebug(String s){ try{ if(fishingDebug && !worldObj.isRemote){ String out = "<"+this.getEntityString().split("\\.")[1]+this.getEntityId()+">: "+s; if(fishingLog.contains(out)){ //System.out.println(out); return; } System.out.println(out); //net.minecraft.server.MinecraftServer.getServer().getConfigurationManager().sendChatMsg(ChatMessageComponent.createFromTranslationKey(out)); fishingLog.add(out); } }catch(Exception e){ } } public void faceEntity(Entity par1Entity, float par2, float par3) { double d0 = par1Entity.posX - this.posX; double d1 = par1Entity.posZ - this.posZ; double d2; if (par1Entity instanceof EntityLiving) { EntityLiving entityliving = (EntityLiving)par1Entity; d2 = entityliving.posY + (double)entityliving.getEyeHeight() - (this.posY + (double)this.getEyeHeight()); } else { d2 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) / 2.0D - (this.posY + (double)this.getEyeHeight()); } double d3 = (double)MathHelper.sqrt_double(d0 * d0 + d1 * d1); float f2 = (float)(Math.atan2(d1, d0) * 180.0D / Math.PI) - 90.0F; float f3 = (float)(-(Math.atan2(d2, d3) * 180.0D / Math.PI)); this.rotationPitch = this.updateRotation(this.rotationPitch, f3, par3); this.renderYawOffset = this.updateRotation(this.renderYawOffset, f2, par2); this.rotationYaw = this.renderYawOffset; } public void faceEntity(EntityLivingBase entSource, Entity par1Entity, float par2, float par3) { double d0 = par1Entity.posX - entSource.posX; double d1 = par1Entity.posZ - entSource.posZ; double d2; if (par1Entity instanceof EntityLivingBase) { EntityLivingBase entitylivingbase = (EntityLivingBase)par1Entity; d2 = entitylivingbase.posY + (double)entitylivingbase.getEyeHeight() - (entSource.posY + (double)entSource.getEyeHeight()); } else { d2 = (par1Entity.boundingBox.minY + par1Entity.boundingBox.maxY) / 2.0D - (entSource.posY + (double)entSource.getEyeHeight()); } double d3 = (double)MathHelper.sqrt_double(d0 * d0 + d1 * d1); float f2 = (float)(Math.atan2(d1, d0) * 180.0D / Math.PI) - 90.0F; float f3 = (float)(-(Math.atan2(d2, d3) * 180.0D / Math.PI)); entSource.rotationPitch = updateRotation(entSource.rotationPitch, f3, par3); entSource.rotationYaw = updateRotation(entSource.rotationYaw, f2, par2); } public float updateRotation(float p_70663_1_, float p_70663_2_, float p_70663_3_) { float f3 = MathHelper.wrapAngleTo180_float(p_70663_2_ - p_70663_1_); if (f3 > p_70663_3_) { f3 = p_70663_3_; } if (f3 < -p_70663_3_) { f3 = -p_70663_3_; } return p_70663_1_ + f3; } }