package drzhark.mocreatures.entity.passive; import drzhark.mocreatures.MoCTools; import drzhark.mocreatures.MoCreatures; import drzhark.mocreatures.entity.MoCEntityAnimal; import drzhark.mocreatures.network.MoCServerPacketHandler; import net.minecraft.block.material.Material; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.pathfinding.PathEntity; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.util.DamageSource; import net.minecraft.util.MathHelper; import net.minecraft.world.World; // TODO // SOUNDS: snakeslither / snakeswim / snakesnap / snakerattle /snakedying // /snakehurt / snakehiss /snakeupset // change walking sounds to slither sounds (done code, pending sounds) // head follows player (Done) // climbing animation (done) // d/c jump (done) // remove shadow (done) // water floating yoffset (done) // randomness to the slithering movement(done) // adjust bounding size (done) // follows player that carries snake food (mouse/birds)(done) // change pathfinding behavior / facing behavior (avoid sudden changes facing // when resting) (done) // tongue in/out plus vibrating movment up/down at the end (done) // fangs (done) // biting (done) // attacking animation (done) // attacking behavior / poisoning (done) // rattlesnake (done) // rattle / moving tail (done) // cobra special parts (done) // snake textures (done) // specific biome spawning (done) // baby snakes - edad, growing sizes, stretching (done) // eggs (done) // small non aggressive snakes flee from player (done) // different sizes/behaviors, some aggressive, some passive, some shy (done) // you can pick tamed snakes (done) // synchronize bite (done) // hissing -warning prior to attacking! - avoid attack if player has mouse/bird // (done) // curled stance (perhaps not needed?) // avoid curling when dying (no need) // encrouching / eating prey? (for later) // spitting venom snake? (for later) // taming?? (done) // sounds // test /** * Biome - specific Forest Desert plains Swamp Jungle Tundra Taiga Extreme Hills * Ocean * * swamp: python, bright green, #1 plains: coral, cobra #1, #2, #3, #4 desert: * rattlesnake , #2 jungle: all except rattlesnake hills: all except python, * bright green, bright orange tundra-taiga: none ocean: leave alone * */ public class MoCEntitySnake extends MoCEntityAnimal { private float fTongue; private float fMouth; private boolean isBiting; private float fRattle; private boolean isPissed; private int hissCounter; private int movInt; private boolean isNearPlayer; public float bodyswing; public static final String snakeNames[] = { "Dark", "Spotted", "Orange", "Green", "Coral", "Cobra", "Rattle", "Python" }; public MoCEntitySnake(World world) { super(world); setSize(1.4F, 0.5F); health = 10; //moveSpeed = 0.6F; bodyswing = 2F; movInt = rand.nextInt(10); setEdad(50 + rand.nextInt(50)); //forceUpdates = true; } //@SideOnly(Side.CLIENT) @Override public void selectType() { // snake types: // 1 small blackish/dark snake (passive) // 2 dark green /brown snake (passive) // 3 bright orangy snake aggressive venomous swamp, jungle, forest // 4 bright green snake aggressive venomous swamp, jungle, forest // 5 coral (aggressive - venomous) small / plains, forest // 6 cobra (aggressive - venomous - spitting) plains, forest // 7 rattlesnake (aggressive - venomous) desert // 8 python (aggressive - non venomous) big - swamp // 9 sea snake (aggressive - venomous) if (getType() == 0) { int k = rand.nextInt(100); if (k <= 12) { setType(1); } else if (k <= 25) { setType(2); } else if (k <= 37) { setType(3); } else if (k <= 50) { setType(4); } else if (k <= 62) { setType(5); } else if (k <= 75) { setType(6); } else if (k <= 87) { setType(7); } else { setType(8); } } } @Override public String getTexture() { switch (getType()) { case 1: return MoCreatures.proxy.MODEL_TEXTURE + "snake1.png"; case 2: return MoCreatures.proxy.MODEL_TEXTURE + "snake2.png"; case 3: return MoCreatures.proxy.MODEL_TEXTURE + "snake3.png"; case 4: return MoCreatures.proxy.MODEL_TEXTURE + "snake4.png"; case 5: return MoCreatures.proxy.MODEL_TEXTURE + "snake5.png"; case 6: return MoCreatures.proxy.MODEL_TEXTURE + "snake6.png"; case 7: return MoCreatures.proxy.MODEL_TEXTURE + "snake7.png"; case 8: return MoCreatures.proxy.MODEL_TEXTURE + "snake8.png"; default: return MoCreatures.proxy.MODEL_TEXTURE + "snake1.png"; } } @Override public int getMaxHealth() { return 10; } @Override public float getMoveSpeed() { return 0.6F; } @Override protected void fall(float f) { } @Override public boolean isOnLadder() { return isCollidedHorizontally; } @Override // snakes can't jump protected void jump() { } @Override protected boolean canDespawn() { return !getIsTamed(); } public boolean pickedUp() { return (this.ridingEntity != null); } @Override public boolean interact(EntityPlayer entityplayer) { //TODO //this doesn't work yet, make the player feed the mouse to this snake /*if (entityplayer.riddenByEntity != null && entityplayer.riddenByEntity instanceof MoCEntityMouse) { //System.out.println("player has a mouse"); }*/ if (super.interact(entityplayer)) { return false; } if (!getIsTamed()) { return false; } ItemStack itemstack = entityplayer.inventory.getCurrentItem(); //changes name /*if ((itemstack != null) && getIsTamed() //&& MoCreatures.isServer() && ((itemstack.itemID == MoCreatures.medallion.shiftedIndex) || (itemstack.itemID == Item.book.shiftedIndex))) { if (!MoCreatures.isServer()) { MoCreatures.proxy.setName(entityplayer, this); } return true; }*/ rotationYaw = entityplayer.rotationYaw; if (this.ridingEntity == null) { if (MoCreatures.isServer()) { mountEntity(entityplayer); } } else { worldObj.playSoundAtEntity(this, "mob.chickenplop", 1.0F, ((rand.nextFloat() - rand.nextFloat()) * 0.2F) + 1.0F); if (MoCreatures.isServer()) { this.mountEntity(null); } } motionX = entityplayer.motionX * 5D; motionY = (entityplayer.motionY / 2D) + 0.5D; motionZ = entityplayer.motionZ * 5D; return true; } @Override public boolean isNotScared() { // TODO depending on size! if (getType() > 2 && getEdad() > 50) { return true; } return false; } /** * returns true when is climbing up * * @return */ public boolean isClimbing() { return isOnLadder() && motionY > 0.01F; } public boolean isResting() { return (!getNearPlayer() && onGround && (motionX < 0.01D && motionX > -0.01D) && (motionZ < 0.01D && motionZ > -0.01D)); // return (onGround && (motionX < 0.01D && motionX > -0.01D) && (motionZ // < 0.01D && motionZ > -0.01D)); } public boolean getNearPlayer() { return isNearPlayer; } public int getMovInt() { return movInt; } @Override public boolean swimmerEntity() { return true; } @Override public boolean canBreatheUnderwater() { return true; } public void setNearPlayer(boolean flag) { isNearPlayer = flag; } /*@Override public double getYOffset() { // If we are in SMP, do not alter offset on any client other than the player being mounted on if (((ridingEntity instanceof EntityPlayer) && !worldObj.isRemote) || ridingEntity == MoCreatures.proxy.getPlayer())//MoCProxy.mc().thePlayer) { return(yOffset - 1.5F); } else { return yOffset; } }*/ @Override public double getYOffset() { if (ridingEntity instanceof EntityPlayer && ridingEntity == MoCreatures.proxy.getPlayer() && !MoCreatures.isServer()) { return (yOffset - 1.5F); } if ((ridingEntity instanceof EntityPlayer) && !MoCreatures.isServer()) { return (yOffset + 0.1F); } else { return yOffset; } } public float getSizeF() { float factor = 1.0F; if (getType() == 1 || getType() == 2)// small shy snakes { factor = 0.8F; } else if (getType() == 5)// coral { factor = 0.6F; } if (getType() == 6)// cobra 1.1 { factor = 1.1F; } if (getType() == 7)// rattlesnake { factor = 0.9F; } if (getType() == 8)// python { factor = 1.5F; } // float f = 1.0F*factor; return this.getEdad() * 0.01F * factor;// */ } @Override public void onUpdate() { super.onUpdate(); if (getEdad() < 100 && rand.nextInt(500) == 0) { setEdad(getEdad() + 1); } if (pickedUp()) { movInt = 0; // System.out.println("mov rand # = " + movInt); } if (isResting()) { prevRenderYawOffset = renderYawOffset = rotationYaw = prevRotationYaw; } if (!onGround && (ridingEntity != null)) { rotationYaw = ridingEntity.rotationYaw;// -90F; } if (getfTongue() != 0.0F) { setfTongue(getfTongue() + 0.2F); if (getfTongue() > 8.0F) { setfTongue(0.0F); } } /* * if (getNearPlayer() && !getIsTamed())//&& rand.nextInt(2)==0) { * setfMouth(0.3F); }else */ if (worldObj.difficultySetting > 0 && getNearPlayer() && !getIsTamed() && isNotScared()) { // setfMouth(0.3F); hissCounter++; //System.out.println("Hissing! " + hissCounter); // TODO synchronize and get sound // hiss if (hissCounter % 25 == 0) { setfMouth(0.3F); worldObj.playSoundAtEntity(this, "snakeupset", 1.0F, 1.0F + ((rand.nextFloat() - rand.nextFloat()) * 0.2F)); } if (hissCounter % 35 == 0) { setfMouth(0.0F); } if (hissCounter > 100 && rand.nextInt(50) == 0) { // then randomly get pissed setPissed(true); hissCounter = 0; } } if (hissCounter > 500) { hissCounter = 0; } if (getfMouth() != 0.0F && hissCounter == 0)// && !isPissed()) //biting { setfMouth(getfMouth() + 0.1F); if (getfMouth() > 0.5F) { setfMouth(0.0F); } } if (getType() == 7 && getfRattle() != 0.0F) // rattling { setfRattle(getfRattle() + 0.2F); if (getfRattle() == 1.0F) { // TODO synchronize worldObj.playSoundAtEntity(this, "snakerattle", 1.0F, 1.0F + ((rand.nextFloat() - rand.nextFloat()) * 0.2F)); } if (getfRattle() > 8.0F) { setfRattle(0.0F); } } // super.onUpdate(); } /** * from 0.0 to 4.0F 0.0 = inside mouth 2.0 = completely stuck out 3.0 = * returning 4.0 = in. * * @return */ public float getfTongue() { return fTongue; } public void setfTongue(float fTongue) { this.fTongue = fTongue; } public float getfMouth() { return fMouth; } public void setfMouth(float fMouth) { this.fMouth = fMouth; } public float getfRattle() { return fRattle; } public void setfRattle(float fRattle) { this.fRattle = fRattle; } @Override public void onLivingUpdate() { super.onLivingUpdate(); // type = 7); /* * if (!hasPath() && riddenByEntity == null && !isMovementCeased() && * entityToAttack == null) { updateWanderPath(); } */ // setfMouth(0.3F); /** * stick tongue */ if (rand.nextInt(50) == 0 && getfTongue() == 0.0F) { setfTongue(0.1F); } /** * Open mouth */ if (rand.nextInt(100) == 0 && getfMouth() == 0.0F) { setfMouth(0.1F); } if (getType() == 7) { int chance = 0; if (getNearPlayer()) { chance = 30; } else { chance = 100; } if (rand.nextInt(chance) == 0) { setfRattle(0.1F); } } /** * change in movement pattern */ if (!isResting() && !pickedUp() && rand.nextInt(50) == 0) { movInt = rand.nextInt(10); } // if (attackTime<=0) bodyswing -= 0.3F; /** * Biting animation */ if (isBiting()) { bodyswing -= 0.5F; setfMouth(0.3F); if (bodyswing < 0F) { worldObj.playSoundAtEntity(this, "snakesnap", 1.0F, 1.0F + ((rand.nextFloat() - rand.nextFloat()) * 0.2F)); bodyswing = 2.5F; setfMouth(0.0F); setBiting(false); } } /** * this stops chasing the target randomly */ if (entityToAttack != null && rand.nextInt(100) == 0) { entityToAttack = null; } /** * Follow player that is carrying a mice * */ EntityPlayer entityplayer1 = worldObj.getClosestPlayerToEntity(this, 12D); if (entityplayer1 != null) { double distP = MoCTools.getSqDistanceTo(entityplayer1, posX, posY, posZ); if (isNotScared()) { if (distP < 5D) { setNearPlayer(true); } else { setNearPlayer(false); } if (entityplayer1.riddenByEntity != null && (entityplayer1.riddenByEntity instanceof MoCEntityMouse || entityplayer1.riddenByEntity instanceof MoCEntityBird)) { PathEntity pathentity = worldObj.getPathEntityToEntity(this, entityplayer1, 16F, true, false, false, true); setPathToEntity(pathentity); setPissed(false); hissCounter = 0; } } else { setNearPlayer(false); if (distP < 3D && !getIsTamed()) { fleeingTick = 40; // System.out.println("Fleeing!"); } } } else { setNearPlayer(false); // setPissed(false); } } @Override protected void attackEntity(Entity entity, float f) { if ((getType() < 3 || getIsTamed()) && entity instanceof EntityPlayer) { entityToAttack = null; return; } // attack only after hissing/rattling! if (!isPissed()) { return; } if (attackTime <= 0 && (f < 2.5D) && (entity.boundingBox.maxY > boundingBox.minY) && (entity.boundingBox.minY < boundingBox.maxY)) // if((f < 2.5D) && (entity.boundingBox.maxY > boundingBox.minY) && // (entity.boundingBox.minY < boundingBox.maxY)) { /* * if (attackTime == 5)//<5 && attackTime >0) { //start biting * setBiting(true); } else if (attackTime <=0) */ { setBiting(true); attackTime = 20; // venom! if (rand.nextInt(2) == 0 && entity instanceof EntityPlayer && getType() > 2 && getType() < 8) { MoCreatures.poisonPlayer((EntityPlayer) entity); ((EntityPlayer) entity).addPotionEffect(new PotionEffect(Potion.poison.id, 120, 0)); } entity.attackEntityFrom(DamageSource.causeMobDamage(this), 2); if (!(entity instanceof EntityPlayer)) { MoCTools.destroyDrops(this, 3D); } } } } @Override public void performAnimation(int i) { setBiting(true); } public boolean isBiting() { return isBiting; } public void setBiting(boolean flag) { if (flag && MoCreatures.isServer()) { MoCServerPacketHandler.sendAnimationPacket(this.entityId, this.worldObj.provider.dimensionId, 0); } this.isBiting = flag; } public boolean isPissed() { return isPissed; } public void setPissed(boolean isPissed) { this.isPissed = isPissed; } @Override public boolean attackEntityFrom(DamageSource damagesource, int i) { if (getType() < 3) { return super.attackEntityFrom(damagesource, i); } if (super.attackEntityFrom(damagesource, i)) { Entity entity = damagesource.getEntity(); if ((riddenByEntity == entity) || (ridingEntity == entity)) { return true; } if ((entity != this) && (worldObj.difficultySetting > 0))// && !getIsTamed()) { setPissed(true); entityToAttack = entity; } return true; } else { return false; } } @Override protected Entity findPlayerToAttack() { if (worldObj.difficultySetting > 0) { EntityPlayer entityplayer = worldObj.getClosestVulnerablePlayerToEntity(this, 4D); if (!getIsTamed() && (entityplayer != null)) // && getIsAdult() ) { if (isNotScared() && isPissed()) { return entityplayer; } } if ((rand.nextInt(100) == 0)) { EntityLiving entityliving = getClosestEntityLiving(this, 8D); return entityliving; } } return null; } @Override protected void dropFewItems(boolean flag, int x) { if (getEdad() > 60) { // int i = rand.nextInt(10); // if(i < 5) { int j = rand.nextInt(3); for (int l = 0; l < j; l++) { entityDropItem(new ItemStack(MoCreatures.fishyegg, 1, getType() + 20), 0.0F); } } } } // ignores big entities, everything else is prey! @Override public boolean entitiesToIgnore(Entity entity) { return ((super.entitiesToIgnore(entity)) || (entity instanceof MoCEntitySnake) || (entity.height > 0.5D && entity.width > 0.5D) ); } @Override protected void playStepSound(int par1, int par2, int par3, int par4) { if (isInsideOfMaterial(Material.water)) { worldObj.playSoundAtEntity(this, "snakeswimm", 1.0F, 1.0F); } else { worldObj.playSoundAtEntity(this, "snakeslither", 1.0F, 1.0F); } } @Override protected String getDeathSound() { return "snakedying"; } @Override protected String getHurtSound() { return "snakehurt"; } @Override protected String getLivingSound() { return "snakehiss"; } @Override public boolean getCanSpawnHere() { if (MoCTools.isNearTorch(this)) { return false; } return (checkSpawningBiome() && (MoCreatures.proxy.getFrequency(this.getEntityName()) > 0) && getCanSpawnHereCreature() && getCanSpawnHereLiving()); } @Override public boolean checkSpawningBiome() { int i = MathHelper.floor_double(posX); int j = MathHelper.floor_double(boundingBox.minY); int k = MathHelper.floor_double(posZ); String s = MoCTools.BiomeName(worldObj, i, j, k); /** * swamp: python, bright green, #1 (done) plains: coral, cobra #1, #2, * #3, #4 (everyone but 7) desert: rattlesnake , #2 jungle: all except * rattlesnake forest: all except rattlesnake hills: all except python, * bright green, bright orange, rattlesnake tundra-taiga: none ocean: * leave alone */ /** * Biome lists: Ocean Plains Desert Extreme Hills Forest Taiga Swampland * River Frozen Ocean Frozen River Ice Plains Ice Mountains Mushroom * Island Mushroom Island Shore Beach DesertHills ForestHills TaigaHills * Extreme Hills Edge Jungle JungleHills * */ int l = rand.nextInt(10); if (s.equals("Taiga") || s.equals("FrozenOcean") || s.equals("FrozenRiver") || s.equals("Ice Plains") || s.equals("Ice Mountains") || s.equals("TaigaHills")) { return false; } if (s.equals("Desert") || s.equals("DesertHills")) { if (l < 5) { setType(7); // rattlesnake or spotted brownish ? } else { setType(2); } } if (getType() == 7 && !(s.equals("Desert") || s.equals("DesertHills"))) { return false; // type = 0); // chooseType(); } if (s.equals("Extreme Hills") || s.equals("ForestHills") || s.equals("Extreme Hills Edge")) { if (l < 4) { setType(1); } else if (l < 7) { setType(5); } else { setType(6); } } if (s.equals("Swampland")) { // python or bright green bright orange if (l < 4) { setType(8); } else if (l < 8) { setType(4); } else { setType(1); } } return true; } @Override public boolean updateMount() { return getIsTamed(); } @Override public boolean forceUpdates() { return getIsTamed(); } @Override public int nameYOffset() { return -20; } @Override public boolean isMyHealFood(ItemStack par1ItemStack) { return par1ItemStack != null && (par1ItemStack.itemID == MoCreatures.ratRaw.itemID); } }