Package com.flansmod.common.driveables.mechas

Source Code of com.flansmod.common.driveables.mechas.EntityMecha

package com.flansmod.common.driveables.mechas;

import java.util.ArrayList;

import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.World;
import net.minecraft.world.WorldSettings.GameType;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.event.world.BlockEvent;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

import com.flansmod.client.debug.EntityDebugVector;
import com.flansmod.client.gui.GuiDriveableController;
import com.flansmod.client.model.GunAnimations;
import com.flansmod.common.FlansMod;
import com.flansmod.common.RotatedAxes;
import com.flansmod.common.driveables.DriveableData;
import com.flansmod.common.driveables.DriveablePart;
import com.flansmod.common.driveables.DriveableType;
import com.flansmod.common.driveables.EntityDriveable;
import com.flansmod.common.driveables.EntitySeat;
import com.flansmod.common.driveables.EnumDriveablePart;
import com.flansmod.common.guns.BulletType;
import com.flansmod.common.guns.EnumFireMode;
import com.flansmod.common.guns.GunType;
import com.flansmod.common.guns.InventoryHelper;
import com.flansmod.common.guns.ItemBullet;
import com.flansmod.common.guns.ItemGun;
import com.flansmod.common.network.PacketDriveableDamage;
import com.flansmod.common.network.PacketDriveableGUI;
import com.flansmod.common.network.PacketDriveableKey;
import com.flansmod.common.network.PacketMechaControl;
import com.flansmod.common.network.PacketPlaySound;
import com.flansmod.common.parts.ItemPart;
import com.flansmod.common.teams.TeamsManager;
import com.flansmod.common.tools.ItemTool;
import com.flansmod.common.vector.Vector3f;
import com.flansmod.common.vector.Vector3i;

public class EntityMecha extends EntityDriveable
{
  private int ticksSinceUsed;
    public int toggleTimer = 0;
    private float moveX = 0, moveZ = 0;
    public RotatedAxes legAxes;
    public float prevLegsYaw = 0F;
    private int jumpDelay = 0;
    public MechaInventory inventory;
    public float legSwing = 0;
    /** Used for shooting guns */
    public int shootDelayLeft = 0, shootDelayRight = 0;
    /** Used for gun sounds */
    public int soundDelayLeft = 0, soundDelayRight = 0;
    /** The coords of the blocks being destroyed */
    public Vector3i breakingBlock = null;
    /** Progress made towards breaking each block */
    public float breakingProgress = 0F;
    /** Timer for the RocketPack Sound */
    private float rocketTimer = 0F;
    private int diamondTimer = 0;
   
    /** Gun animations */
    public GunAnimations leftAnimations = new GunAnimations(), rightAnimations = new GunAnimations();
   
    /** The ID of the slot that we are pulling fuel from. -1 means we have not found one */
    private int foundFuel = -1;
    /** True if we need fuel but could not find any in the inventory. Reset when the inventory updated */
    public boolean couldNotFindFuel = false;

  public EntityMecha(World world)
  {
    super(world);
    setSize(2F, 3F);
    stepHeight = 3;
    legAxes = new RotatedAxes();
    inventory = new MechaInventory(this);
  }
 
  public EntityMecha(World world, double x, double y, double z, MechaType type, DriveableData data, NBTTagCompound tags)
  {
    super(world, type, data);
    legAxes = new RotatedAxes();
    setSize(2F, 3F);
    stepHeight = 3;
    setPosition(x, y, z);
    initType(type, false);
    inventory = new MechaInventory(this, tags);
  }
 
  public EntityMecha(World world, double x, double y, double z, EntityPlayer placer, MechaType type, DriveableData data, NBTTagCompound tags)
  {
    this(world, x, y, z, type, data, tags);
    rotateYaw(placer.rotationYaw + 90F);
    legAxes.rotateGlobalYaw(placer.rotationYaw + 90F);
    prevLegsYaw = legAxes.getYaw();
  }
 
    @Override
    protected void initType(DriveableType type, boolean clientSide)
    {
      super.initType(type, clientSide);
      setSize(((MechaType)type).width, ((MechaType)type).height);
      stepHeight = ((MechaType)type).stepHeight;
    }
 
  @Override
    protected void writeEntityToNBT(NBTTagCompound tag)
    {
        super.writeEntityToNBT(tag);
        tag.setFloat("LegsYaw", legAxes.getYaw());
        tag.setTag("Inventory", inventory.writeToNBT(new NBTTagCompound()));
    }

  @Override
    protected void readEntityFromNBT(NBTTagCompound tag)
    {
        super.readEntityFromNBT(tag);
        legAxes.setAngles(tag.getFloat("LegsYaw"), 0, 0);
        inventory.readFromNBT(tag.getCompoundTag("Inventory"));
    }
 
  @Override
  public void writeSpawnData(ByteBuf data)
  {
    super.writeSpawnData(data);
    ByteBufUtils.writeTag(data, inventory.writeToNBT(new NBTTagCompound()));
  }
 
  @Override
  public void readSpawnData(ByteBuf data)
  {
    super.readSpawnData(data);
    legAxes.rotateGlobalYaw(axes.getYaw());
    prevLegsYaw = legAxes.getYaw();

    inventory.readFromNBT(ByteBufUtils.readTag(data));
  }

  @Override
  public void onMouseMoved(int deltaX, int deltaY)
  {
  }
 
  @Override
  public boolean interactFirst(EntityPlayer entityplayer)
    {
    if(isDead)
      return false;
    if(worldObj.isRemote)
      return false;
   
    //If they are using a repair tool, don't put them in
    ItemStack currentItem = entityplayer.getCurrentEquippedItem();
    if(currentItem != null && currentItem.getItem() instanceof ItemTool && ((ItemTool)currentItem.getItem()).type.healDriveables)
      return true;
   
    MechaType type = getMechaType();
    //Check each seat in order to see if the player can sit in it
    for(int i = 0; i <= type.numPassengers; i++)
    {
      if(seats[i].interactFirst(entityplayer))
        return true;
    }
        return false;
    }
 
  public MechaType getMechaType()
  {
    return MechaType.getMecha(driveableType);
  }
 
  @Override
  public boolean pressKey(int key, EntityPlayer player)
  {
    MechaType type = getMechaType();
      DriveableData data = getDriveableData();
    //send keys which require server side updates to the server
      if(worldObj.isRemote && (key == 6 || key == 8 || key == 9))
      {
        FlansMod.getPacketHandler().sendToServer(new PacketDriveableKey(key));
        return true;
      }
      switch(key)
      {
        case 0 : //Forwards (these movement cases are redundant, as Mechas need to stop when the key is released)
        {
          return true;
        }
        case 1 : //Backwards
        {
          return true;
        }
        case 2 : //Left
        {
          return true;
        }
        case 3 : //Right
        {
          return true;
        }
      case 4 : //Jump
      {
        boolean canThrustCreatively = seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode;
        if(onGround && (jumpDelay == 0) && (canThrustCreatively || data.fuelInTank > data.engine.fuelConsumption) && isPartIntact(EnumDriveablePart.hips))
        {
          jumpDelay = 20;
          motionY += type.jumpVelocity;
          if(!canThrustCreatively)
            data.fuelInTank -= data.engine.fuelConsumption;
        }
        return true;
      }
      case 5 : //Down : Do nothing
      {
        return true;
      }
      case 6 : //Exit : Get out
      {
        seats[0].riddenByEntity.mountEntity(null);
              return true;
      }
      case 7 : //Inventory
      {
        FlansMod.getPacketHandler().sendToServer(new PacketDriveableGUI(4));
        ((EntityPlayer)seats[0].riddenByEntity).openGui(FlansMod.INSTANCE, 10, worldObj, chunkCoordX, chunkCoordY, chunkCoordZ);
        return true;
      }
      case 8 : //UseR
      {
        return true; //useItem(false);
      }
      case 9 : //UseL
      {
        return true; //useItem(true);
      }
      case 10 : //Change control mode : Do nothing
      {
        return true;
      }
      case 11 : //Roll left : Do nothing
      {
        return true;
      }
      case 12 : //Roll right : Do nothing
      {
        return true;
      }
      case 13 : //Gear : Do nothing
      {
        return true;
      }
      case 14 : //Door : Do nothing
      {
        return true;
      }
      case 15 : //???
      {
        return true;
      }
      case 16 : //???
      {
        return true;
      }
      case 17 : //???
      {
        return true;
      }
     
      }
    return false;
  }
 
  private boolean useItem(boolean left)
  {
        if(left? isPartIntact(EnumDriveablePart.leftArm) : isPartIntact(EnumDriveablePart.rightArm))
          {
      boolean creative = !(seats[0].riddenByEntity instanceof EntityPlayer) || ((EntityPlayer) seats[0].riddenByEntity).capabilities.isCreativeMode;
      ItemStack heldStack = left ? inventory.getStackInSlot(EnumMechaSlotType.leftTool) : inventory.getStackInSlot(EnumMechaSlotType.rightTool);
      if(heldStack == null)
        return false;
     
      Item heldItem = heldStack.getItem();
     
      MechaType mechaType = getMechaType();
     
      if(heldItem instanceof ItemMechaAddon)
      {
        MechaItemType toolType = ((ItemMechaAddon)heldItem).type;
       
        float reach = toolType.reach * mechaType.reach;
       
        Vector3f lookOrigin = new Vector3f((float)mechaType.seats[0].x / 16F, (float)mechaType.seats[0].y / 16F + seats[0].riddenByEntity.getMountedYOffset(), (float)mechaType.seats[0].z / 16F);
        lookOrigin = axes.findLocalVectorGlobally(lookOrigin);
        Vector3f.add(lookOrigin, new Vector3f(posX, posY, posZ), lookOrigin);
   
        Vector3f lookVector = axes.findLocalVectorGlobally(seats[0].looking.findLocalVectorGlobally(new Vector3f(reach, 0F, 0F)));
       
        worldObj.spawnEntityInWorld(new EntityDebugVector(worldObj, lookOrigin, lookVector, 20));
       
        Vector3f lookTarget = Vector3f.add(lookVector, lookOrigin, null);
       
        MovingObjectPosition hit = worldObj.rayTraceBlocks(lookOrigin.toVec3(), lookTarget.toVec3());
       
        //MovingObjectPosition hit = ((EntityLivingBase)seats[0].riddenByEntity).rayTrace(reach, 1F);
        if(hit != null && hit.typeOfHit == MovingObjectType.BLOCK)
        {
          if(breakingBlock == null || breakingBlock.x != hit.blockX || breakingBlock.y != hit.blockY || breakingBlock.z != hit.blockZ)
            breakingProgress = 0F;
          breakingBlock = new Vector3i(hit.blockX, hit.blockY, hit.blockZ);
        }
      }
     
      else if(heldItem instanceof ItemGun)
      {
        ItemGun gunItem = (ItemGun)heldItem;
        GunType gunType = gunItem.type;
       
        //Get the correct shoot delay
        int delay = left ? shootDelayLeft : shootDelayRight;
       
        //If we can shoot
        if(delay <= 0)
        {
          //Go through the bullet stacks in the gun and see if any of them are not null
          int bulletID = 0;
          ItemStack bulletStack = null;
          for(; bulletID < gunType.numAmmoItemsInGun; bulletID++)
          {
            ItemStack checkingStack = gunItem.getBulletItemStack(heldStack, bulletID);
            if(checkingStack != null && checkingStack.getItem() != null && checkingStack.getItemDamage() < checkingStack.getMaxDamage())
            {
              bulletStack = checkingStack;
              break;
            }
          }

          //If no bullet stack was found, reload
          if(bulletStack == null)
          {
            gunItem.reload(heldStack, gunType, worldObj, this, driveableData, (infiniteAmmo() ? true : creative), false);       
          }
          //A bullet stack was found, so try shooting with it
          else if(bulletStack.getItem() instanceof ItemBullet)
          {
            //Shoot
            shoot(heldStack, gunType, bulletStack, creative, left);
           
            //Apply animations to 3D modelled guns
            //TODO : Move to client side and sync
            if(worldObj.isRemote)
            {
              int pumpDelay = gunType.model == null ? 0 : gunType.model.pumpDelay;
              int pumpTime = gunType.model == null ? 1 : gunType.model.pumpTime;
              if(left)
              {
                leftAnimations.doShoot(pumpDelay, pumpTime);
              }
              else
              {
                rightAnimations.doShoot(pumpDelay, pumpTime);
              }
            }
            //Damage the bullet item
            bulletStack.setItemDamage(bulletStack.getItemDamage() + 1);
           
            //Update the stack in the gun
            gunItem.setBulletItemStack(heldStack, bulletStack, bulletID);
          }
        }
      }
        }
    return true;
  }

  private void shoot(ItemStack stack, GunType gunType, ItemStack bulletStack, boolean creative, boolean left)
  {
    MechaType mechaType = getMechaType();
    BulletType bulletType = ((ItemBullet)bulletStack.getItem()).type;
    RotatedAxes a = new RotatedAxes();
   
    Vector3f armVector = new Vector3f(mechaType.armLength, 0F, 0F);
    Vector3f gunVector = new Vector3f(mechaType.armLength + 1.2F * mechaType.heldItemScale, 0.5F * mechaType.heldItemScale, 0F);
    Vector3f armOrigin = left ?  mechaType.leftArmOrigin : mechaType.rightArmOrigin;
   
    a.rotateGlobalYaw(axes.getYaw());
    armOrigin = a.findLocalVectorGlobally(armOrigin);
   
    a.rotateLocalPitch(-seats[0].looking.getPitch());
    gunVector = a.findLocalVectorGlobally(gunVector);
    armVector = a.findLocalVectorGlobally(armVector);
   
    Vector3f bulletOrigin = Vector3f.add(armOrigin, gunVector, null);
   
    bulletOrigin  = Vector3f.add(new Vector3f(posX, posY, posZ), bulletOrigin, null);
       
    if(!worldObj.isRemote)
      for (int k = 0; k < gunType.numBullets; k++)
        worldObj.spawnEntityInWorld(((ItemBullet)bulletStack.getItem()).getEntity(worldObj, bulletOrigin, armVector, (EntityLivingBase)(seats[0].riddenByEntity), gunType.getSpread(stack) / 2F, gunType.getDamage(stack), gunType.getBulletSpeed(stack),bulletStack.getItemDamage(), mechaType));
   
    if(left)
      shootDelayLeft = gunType.mode == EnumFireMode.SEMIAUTO ? Math.max(gunType.shootDelay, 5) : gunType.shootDelay;
    else shootDelayRight = gunType.mode == EnumFireMode.SEMIAUTO ? Math.max(gunType.shootDelay, 5) : gunType.shootDelay;
   
    if(bulletType.dropItemOnShoot != null && !creative)
      ItemGun.dropItem(worldObj, this, bulletType.dropItemOnShoot);
   
    // Play a sound if the previous sound has finished
    if((left ? soundDelayLeft : soundDelayRight) <= 0 && gunType.shootSound != null)
    {
      PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, gunType.shootSound, gunType.distortSound);
      if(left)
        soundDelayLeft = gunType.shootSoundLength;
      else soundDelayRight = gunType.shootSoundLength;
    }   
  }
 
  @Override
    protected void fall(float f)
    {
    attackEntityFrom(DamageSource.fall, f);
    }
 
  @Override
    public boolean attackEntityFrom(DamageSource damagesource, float i)
    {
        if(worldObj.isRemote || isDead)
            return true;
       
        MechaType type = getMechaType();
       
        if(damagesource.getDamageType().equals("fall"))
        {
          boolean takeFallDamage = type.takeFallDamage && !stopFallDamage();
          boolean damageBlocksFromFalling = type.damageBlocksFromFalling || breakBlocksUponFalling();
         
          float damageToInflict = takeFallDamage ? i * type.fallDamageMultiplier * vulnerability() : 0;
          float blockDamageFromFalling = damageBlocksFromFalling ? i * type.blockDamageFromFalling / 10F : 0;
                   
          driveableData.parts.get(EnumDriveablePart.hips).attack(damageToInflict, false);
          checkParts();
          FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension);
          if(blockDamageFromFalling > 1)
          {
            worldObj.createExplosion(this, posX, posY, posZ, blockDamageFromFalling, TeamsManager.explosions);
          }
        }
       
        else if(damagesource.damageType.equals("player") && damagesource.getEntity().onGround && (seats[0] == null || seats[0].riddenByEntity == null))
    {
      ItemStack mechaStack = new ItemStack(type.item, 1, 0);
      mechaStack.stackTagCompound = new NBTTagCompound();
      driveableData.writeToNBT(mechaStack.stackTagCompound);
      inventory.writeToNBT(mechaStack.stackTagCompound);
      entityDropItem(mechaStack, 0.5F);
       setDead();
    }
        else
        {
          driveableData.parts.get(EnumDriveablePart.core).attack(i * vulnerability(), damagesource.isFireDamage());
        }
        return true;
    }
 
  @Override
  public void onUpdate()
  {
    super.onUpdate();
   
    //Decrement delay variables
    if(jumpDelay > 0) jumpDelay--;
    if(shootDelayLeft > 0shootDelayLeft--;
    if(shootDelayRight > 0) shootDelayRight--;
    if(soundDelayLeft > 0soundDelayLeft--;
    if(soundDelayRight > 0) soundDelayRight--;
   
    //If the player left the driver's seat, stop digging / whatever
    if(!worldObj.isRemote && (seats[0] == null || seats[0].riddenByEntity == null))
      rightMouseHeld = leftMouseHeld = false;
   
    //Update gun animations
    leftAnimations.update();
    rightAnimations.update();
   
    //Get Mecha Type
    MechaType type = this.getMechaType();
    DriveableData data = getDriveableData();
    if (type == null)
    {
      FlansMod.log("Mecha type null. Not ticking mecha");
      return;
    }
   
    prevLegsYaw = legAxes.getYaw();
   
    //Autorepair. Like a Boss.
   
    if(toggleTimer == 0 && autoRepair())
    {
      for(EnumDriveablePart part: EnumDriveablePart.values())
      {
        DriveablePart thisPart = data.parts.get(part);
        boolean hasCreativePlayer = seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode;
        if(thisPart != null && thisPart.health < thisPart.maxHealth && (hasCreativePlayer || data.fuelInTank >= 10F))
        {
          thisPart.health += 1;
          if(!hasCreativePlayer)
            data.fuelInTank -= 10F;
        }
      }
      toggleTimer = 20;
    }

    if(diamondDetect() != null && diamondTimer == 0 && worldObj.isRemote && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)seats[0].riddenByEntity))
    {
      float sqDistance = 901;
      for(float i = -30; i <= 30; i++)
      {
        for(float j = -30; j <= 30; j++)
        {
          for(float k = -30; k <= 30; k++)
          {
            int x = MathHelper.floor_double(i + posX);
            int y = MathHelper.floor_double(j + posY);
            int z = MathHelper.floor_double(k + posZ);
            if(i * i + j * j + k * k < sqDistance && worldObj.getBlock(x, y, z) == (Blocks.diamond_ore))
            {
              sqDistance = i * i + j * j + k * k;
            }
          }
        }
      }
      if(sqDistance < 901)
      {
        PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, diamondDetect().detectSound, false);
        diamondTimer = 1 + 2 * MathHelper.floor_float(MathHelper.sqrt_float(sqDistance));
      }
    }
    if(diamondTimer > 0) --diamondTimer;
   
    //TODO better implement this
    if(isPartIntact(EnumDriveablePart.hips))
    {
      setSize(type.width, type.height);
      yOffset = type.yOffset;
    }
    else
    {
      setSize(type.width, type.height - type.chassisHeight);
      yOffset = type.yOffset - type.chassisHeight;
    }
   
    //Work out of this is client side and the player is driving
    boolean thePlayerIsDrivingThis = worldObj.isRemote && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)seats[0].riddenByEntity);
    boolean driverIsLiving = seats[0] != null && seats[0].riddenByEntity instanceof EntityLivingBase;
   
    //Despawning
    ticksSinceUsed++;
    if(!worldObj.isRemote && seats[0].riddenByEntity != null)
      ticksSinceUsed = 0;
    if(!worldObj.isRemote && TeamsManager.mechaLove > 0 && ticksSinceUsed > TeamsManager.mechaLove * 20)
    {
      setDead();
    }
   
    //Timer, for general use (only current use is for Auto Repair)
    if(toggleTimer > 0)
      toggleTimer--;
   
    //Player is not driving this. Update its position from server update packets
    if(worldObj.isRemote && !thePlayerIsDrivingThis)
    {
      //The driveable is currently moving towards its server position. Continue doing so.
            if (serverPositionTransitionTicker > 0)
            {
                double x = posX + (serverPosX - posX) / serverPositionTransitionTicker;
                double y = posY + (serverPosY - posY) / serverPositionTransitionTicker;
                double z = posZ + (serverPosZ - posZ) / serverPositionTransitionTicker;
                double dYaw = MathHelper.wrapAngleTo180_double(serverYaw - axes.getYaw());
                double dPitch = MathHelper.wrapAngleTo180_double(serverPitch - axes.getPitch());
                double dRoll = MathHelper.wrapAngleTo180_double(serverRoll - axes.getRoll());
                rotationYaw = (float)(axes.getYaw() + dYaw / serverPositionTransitionTicker);
                rotationPitch = (float)(axes.getPitch() + dPitch / serverPositionTransitionTicker);
                float rotationRoll = (float)(axes.getRoll() + dRoll / serverPositionTransitionTicker);
                --serverPositionTransitionTicker;
                setPosition(x, y, z);
                setRotation(rotationYaw, rotationPitch, rotationRoll);
                //return;
            }
            //If the driveable is at its server position and does not have the next update, it should just simulate itself as a server side driveable would, so continue
    }
   
    //Movement
   
    if(seats[0] != null)
    {
      if(seats[0].riddenByEntity instanceof EntityLivingBase && !(seats[0].riddenByEntity instanceof EntityPlayer))
        axes.setAngles(((EntityLivingBase)seats[0].riddenByEntity).renderYawOffset + 90F, 0F, 0F);
      else
      {
        //Function to limit Head Movement Left/Right
        if(type.limitHeadTurn)
        {
          float axesLegs = legAxes.getYaw();
          float axesBody = axes.getYaw();
         
          double dYaw = axesBody - axesLegs;
          if(dYaw > 180)
            axesBody -= 360F;
          if(dYaw < -180)
            axesBody += 360F;
         
          if(axesLegs + type.limitHeadTurnValue < axesBody)
            axes.setAngles(axesLegs + type.limitHeadTurnValue, 0F, 0F);
         
          if(axesLegs - type.limitHeadTurnValue > axesBody)
            axes.setAngles(axesLegs - type.limitHeadTurnValue, 0F, 0F);
        }

        float yaw = seats[0].looking.getYaw() - seats[0].prevLooking.getYaw();
        axes.rotateGlobalYaw(yaw);
        seats[0].looking.rotateGlobalYaw(-yaw);
      }
    }
   
    moveX = 0;
    moveZ = 0;
   
    float jetPack = jetPackPower();
    if(!onGround && thePlayerIsDrivingThis && Minecraft.getMinecraft().currentScreen instanceof GuiDriveableController && FlansMod.proxy.isKeyDown(4) && shouldFly() && (((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode || data.fuelInTank >= (10F*jetPack)))
    {
      motionY *= 0.95;
      motionY += (0.07*jetPack);
      fallDistance = 0;
      if(!((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode)
        data.fuelInTank -= (10F*jetPack);
      if(rocketTimer <= 0 && rocketPack().soundEffect != null)
      {
        PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, rocketPack().soundEffect, false);
        rocketTimer = rocketPack().soundTime;
      }
    }
    else if(isInWater() && shouldFloat())
    {
      motionY *= 0.89;
      motionY += 0.1;
    }
   
    if(rocketTimer != 0) rocketTimer --;
   
    Vector3f actualMotion = new Vector3f(0F, motionY - (16F / 400F), 0F);
   
    if(driverIsLiving)
    {
      EntityLivingBase entity = (EntityLivingBase)seats[0].riddenByEntity;
      boolean driverIsCreative = entity instanceof EntityPlayer && ((EntityPlayer)entity).capabilities.isCreativeMode;
      if(thePlayerIsDrivingThis && Minecraft.getMinecraft().currentScreen instanceof GuiDriveableController)
      {
        if(FlansMod.proxy.isKeyDown(0)) moveX = 1;
        if(FlansMod.proxy.isKeyDown(1)) moveX = -1;
        if(FlansMod.proxy.isKeyDown(2)) moveZ = -1;
        if(FlansMod.proxy.isKeyDown(3)) moveZ = 1;
      }
      else if(seats[0].riddenByEntity instanceof EntityLiving && !(seats[0].riddenByEntity instanceof EntityPlayer))
      {

        moveZ = 1;
        /*
        EntityLiving ent = (EntityLiving)seats[0].riddenByEntity;
        //System.out.println(ent.moveForward);
        Vec3 target = Vec3.createVectorHelper(0D, 0D, 0D);
        if(ent.getNavigator().getPath() != null)
          target = ent.getNavigator().getPath().getPosition(ent);
        moveX = (float) target.xCoord;
        moveZ = (float) target.zCoord;
        */
      }
     
      Vector3f intent = new Vector3f(moveX, 0, moveZ);
     
      if(Math.abs(intent.lengthSquared()) > 0.1)
      {
        intent.normalise();
       
        ++legSwing;
     
        intent = axes.findLocalVectorGlobally(intent);
             
        Vector3f intentOnLegAxes = legAxes.findGlobalVectorLocally(intent);
        float intentAngle = (float)Math.atan2(intent.z, intent.x) * 180F / 3.14159265F;
        float angleBetween = intentAngle - legAxes.getYaw();
        if(angleBetween > 180F) angleBetween -= 360F;
        if(angleBetween < -180F) angleBetween += 360F;
                 
        float signBetween = Math.signum(angleBetween);
        angleBetween = Math.abs(angleBetween);
       
        if(angleBetween > 0.1)
        {
          legAxes.rotateGlobalYaw(Math.min(angleBetween, type.rotateSpeed)*signBetween);
        }
       
        Vector3f motion = legAxes.getXAxis();
       
        motion.scale((type.moveSpeed * data.engine.engineSpeed * speedMultiplier())*(4.3F/20F)*(intent.lengthSquared()));
       
        boolean canThrustCreatively = seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode;
 
        if((canThrustCreatively || data.fuelInTank > data.engine.fuelConsumption) && isPartIntact(EnumDriveablePart.hips))
        {
          if(onGround || jumpDelay != 0)
          {
            //Move!
          Vector3f.add(actualMotion, motion, actualMotion);
          }
          else if(!onGround && shouldFly())
          {
            Vector3f flyMotion = new Vector3f(intent.x, 0F, intent.z);
            Vector3f.add(actualMotion, flyMotion, actualMotion);
          }

          //If we can't thrust creatively, we must thrust using fuel. Nom.
          if(!canThrustCreatively)
            data.fuelInTank -= data.engine.fuelConsumption;
        }
      }
     
      //Block breaking
      if(!worldObj.isRemote)
      {
        //Use left and right items on the server side
        if(leftMouseHeld)
          useItem(true);
        if(rightMouseHeld)
          useItem(false);
       
        //Check the left block being mined
        if(breakingBlock != null)
        {
          //Get block and material
          Block blockHit = worldObj.getBlock(breakingBlock.x, breakingBlock.y, breakingBlock.z);
          int metadata = worldObj.getBlockMetadata(breakingBlock.x, breakingBlock.y, breakingBlock.z);
          Material material = blockHit.getMaterial();
         
          //Get the itemstacks in each hand
          ItemStack leftStack = inventory.getStackInSlot(EnumMechaSlotType.leftTool);
          ItemStack rightStack = inventory.getStackInSlot(EnumMechaSlotType.rightTool);
         
          //Work out if we are actually breaking blocks
          boolean leftStackIsTool = leftStack != null && leftStack.getItem() instanceof ItemMechaAddon;
          boolean rightStackIsTool = rightStack != null && rightStack.getItem() instanceof ItemMechaAddon;
          boolean breakingBlocks = (leftMouseHeld && leftStackIsTool) || (rightMouseHeld && rightStackIsTool);
         
          //If we are not breaking blocks, reset everything
          if(blockHit == null || !breakingBlocks)
          {
            //if(worldObj.isRemote)
            //  Minecraft.getMinecraft().renderGlobal.destroyBlockPartially(getEntityId(), breakingBlock.x, breakingBlock.y, breakingBlock.z, -1);
            breakingBlock = null;
          }
          else
          {
            //Get the block hardness
            float blockHardness = blockHit.getBlockHardness(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z);
           
            //Calculate the mine speed
            float mineSpeed = 1F;
            boolean atLeastOneEffectiveTool = false;
            if(leftStackIsTool)
            {
              MechaItemType leftType = ((ItemMechaAddon)leftStack.getItem()).type;
              if(leftType.function.effectiveAgainst(material) && leftType.toolHardness > blockHardness)
              {
                mineSpeed *= leftType.speed;
                atLeastOneEffectiveTool = true;
              }
            }
            if(rightStackIsTool)
            {
              MechaItemType rightType = ((ItemMechaAddon)rightStack.getItem()).type;
              if(rightType.function.effectiveAgainst(material) && rightType.toolHardness > blockHardness)
              {
                mineSpeed *= rightType.speed;
                atLeastOneEffectiveTool = true;
              }
            }
           
            //If this block is immortal, do not break it
            if(blockHardness < -0.01F)
              mineSpeed = 0F;
            //If this block's hardness is zero-ish, then the tool's power is OVER 9000!!!!
            else if(Math.abs(blockHardness) < 0.01F)
              mineSpeed = 9001F;
            else
            {
              mineSpeed /= blockHit.getBlockHardness(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z);
            }
           
            //Add block digging overlay
            //if(worldObj.isRemote)
            //  Minecraft.getMinecraft().renderGlobal.destroyBlockPartially(getEntityId(), breakingBlock.x, breakingBlock.y, breakingBlock.z, (int)(breakingProgress * 10));
            breakingProgress += 0.1F * mineSpeed;
            if(breakingProgress >= 1F)
            {
              boolean cancelled = false;
              if(entity instanceof EntityPlayerMP)
              {
                BlockEvent.BreakEvent event = ForgeHooks.onBlockBreakEvent(worldObj, ((EntityPlayerMP)entity).capabilities.isCreativeMode ? GameType.CREATIVE : ((EntityPlayerMP)entity).capabilities.allowEdit ? GameType.SURVIVAL : GameType.ADVENTURE, (EntityPlayerMP)entity, breakingBlock.x, breakingBlock.y, breakingBlock.z);
                cancelled = event.isCanceled();
              }
                  if(!cancelled)
                  {
                    //blockHit.dropBlockAsItem(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z, worldObj.getBlockMetadata(breakingBlock.x, breakingBlock.y, breakingBlock.z), 1);
                //FlansMod.proxy.playBlockBreakSound(breakingBlock.x, breakingBlock.y, breakingBlock.z, worldObj.getBlockId(breakingBlock.x, breakingBlock.y, breakingBlock.z));
                //worldObj.setBlockToAir(breakingBlock.x, breakingBlock.y, breakingBlock.z);
 
                boolean vacuumItems = vacuumItems();
                if(vacuumItems)
                {
                  for(ItemStack stack : blockHit.getDrops(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z, metadata, 0))
                  {
                    //Check for iron regarding refining
                    if(refineIron() && (stack.getItem() == Blocks.iron_ore.getItem(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z)) && (((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode || data.fuelInTank >= 5F))
                    {
                      stack = (new ItemStack(Items.iron_ingot, 1, 0));
                      if (!((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode)
                        data.fuelInTank -= 5F;
                    }
                   
                    //Check for waste to be compacted
                    if(wasteCompact() && ((stack.getItem() == Blocks.cobblestone.getItem(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z)) || (stack.getItem() == Blocks.sand.getItem(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z)) || (stack.getItem() == Blocks.dirt.getItem(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z))))
                    {
                      stack.stackSize = 0;
                    }
                   
                    //Check for item multipliers
                    if(stack.getItem() == Items.diamond)
                    {
                      float multiplier = diamondMultiplier();
                      stack.stackSize *= MathHelper.floor_float(multiplier) + (rand.nextFloat() < tailFloat(multiplier) ? 1 : 0);
                    }
                    if(stack.getItem() == Items.redstone)
                    {
                      float multiplier = redstoneMultiplier();
                      stack.stackSize *= MathHelper.floor_float(multiplier) + (rand.nextFloat() < tailFloat(multiplier) ? 1 : 0);
                    }
                    if(stack.getItem() == Items.coal)
                    {
                      float multiplier = coalMultiplier();
                      stack.stackSize *= MathHelper.floor_float(multiplier) + (rand.nextFloat() < tailFloat(multiplier) ? 1 : 0);
                    }
                    if(stack.getItem() == Items.emerald)
                    {
                      float multiplier = emeraldMultiplier();
                      stack.stackSize *= MathHelper.floor_float(multiplier) + (rand.nextFloat() < tailFloat(multiplier) ? 1 : 0);
                    }
                    if(stack.getItem() == Blocks.iron_ore.getItem(worldObj, breakingBlock.x, breakingBlock.y, breakingBlock.z) || stack.getItem() == Items.iron_ingot)
                    {
                      float multiplier = ironMultiplier();
                      stack.stackSize *= MathHelper.floor_float(multiplier) + (rand.nextFloat() < tailFloat(multiplier) ? 1 : 0);
                    }
                   
                    //Check for auto coal consumption
                    if(autoCoal() && (stack.getItem() == Items.coal) && (data.fuelInTank + 250F < type.fuelTankSize))
                    {
                      data.fuelInTank = Math.min(data.fuelInTank + 1000F, type.fuelTankSize);
                      couldNotFindFuel = false;
                      stack.stackSize = 0;
                    }
                   
                    //Add the itemstack to mecha inventory
                    if(!InventoryHelper.addItemStackToInventory(driveableData, stack, driverIsCreative) && !worldObj.isRemote && worldObj.getGameRules().getGameRuleBooleanValue("doTileDrops"))
                    {
                      worldObj.spawnEntityInWorld(new EntityItem(worldObj, breakingBlock.x + 0.5F, breakingBlock.y + 0.5F, breakingBlock.z + 0.5F, stack));
                    }
                  }
                }
                //Destroy block
                worldObj.func_147480_a(breakingBlock.x, breakingBlock.y, breakingBlock.z, atLeastOneEffectiveTool && !vacuumItems);
                  }
            }
          }
        }
      }
    }
    motionY = actualMotion.y; 
    moveEntity(actualMotion.x, actualMotion.y, actualMotion.z);
    //FlansMod.log("" + fallDistance);
      setPosition(posX, posY, posZ);
   
    //Fuel Handling
    if(!couldNotFindFuel)
    {
      ItemStack fuelStack = foundFuel == -1 ? null : driveableData.getStackInSlot(foundFuel);
     
      //If the fuel item has stack size <= 0, delete it
      if(fuelStack != null && fuelStack.stackSize <= 0)
      {
        driveableData.setInventorySlotContents(foundFuel, null);
        fuelStack = null;
      }
     
      //Find the next fuelling slot
      if(fuelStack == null || !(fuelStack.getItem() instanceof ItemPart && ((ItemPart)fuelStack.getItem()).type.category == 9))
      {
        foundFuel = -1;
        couldNotFindFuel = true;
        for(int i = driveableData.getCargoInventoryStart(); i < driveableData.getCargoInventoryStart() + type.numCargoSlots; i++)
        {
          ItemStack tempStack = driveableData.getStackInSlot(i);
          if(tempStack != null && tempStack.getItem() instanceof ItemPart && ((ItemPart)tempStack.getItem()).type.category == 9)
          {
            foundFuel = i;
            fuelStack = tempStack;
            couldNotFindFuel = false;
            break;
          }
        }
      }
     
      //Work out if we are fuelling (from a Flan's Mod fuel item)
      fuelling = foundFuel != -1 && fuelStack != null && data.fuelInTank < type.fuelTankSize && fuelStack.stackSize > 0 && fuelStack.getItem() instanceof ItemPart && ((ItemPart)fuelStack.getItem()).type.category == 9;
     
      //If we are fuelling
      if(fuelling)
      {
        int damage = fuelStack.getItemDamage();
        //Consume 10 points of fuel (1 damage)
        fuelStack.setItemDamage(damage + 1);
        //Put 10 points of fuel
        data.fuelInTank += 10;
        //If we have finished this fuel item
        if(damage >= fuelStack.getMaxDamage())
        {
          //Reset the damage to 0
          fuelStack.setItemDamage(0);
          //Consume one item
          fuelStack.stackSize--;
          //If we consumed the last one, destroy the stack
          if(fuelStack.stackSize <= 0)
            data.fuel = null;
       
      }
     
      //Check inventory slots for buildcraft buckets and if found, take fuel from them
      if(FlansMod.hooks.BuildCraftLoaded && !fuelling)
      {
        for(int i = data.getCargoInventoryStart(); i < data.numCargo + type.numCargoSlots; i++)
        {
          ItemStack stack = data.getStackInSlot(i);
          if(stack != null && stack.isItemEqual(FlansMod.hooks.BuildCraftOilBucket) && data.fuelInTank + 5000 <= type.fuelTankSize)
          {
            data.fuelInTank += 5000;
            data.setInventorySlotContents(i, new ItemStack(Items.bucket));
            couldNotFindFuel = false;
          }
          else if(stack != null && stack.isItemEqual(FlansMod.hooks.BuildCraftFuelBucket) && data.fuelInTank + 10000 <= type.fuelTankSize)
          {
            data.fuelInTank += 10000;
            data.setInventorySlotContents(i, new ItemStack(Items.bucket));
            couldNotFindFuel = false;
          }
        }
      }
    }
   
    //Calculate movement on the client and then send position, rotation etc to the server
    if(thePlayerIsDrivingThis)
    {
      FlansMod.getPacketHandler().sendToServer(new PacketMechaControl(this));
      serverPosX = posX;
      serverPosY = posY;
      serverPosZ = posZ;
      serverYaw = axes.getYaw();
    }
   
    //If this is the server, send position updates to everyone, having received them from the driver
    if(!worldObj.isRemote && ticksExisted % 5 == 0)
    {
      FlansMod.getPacketHandler().sendToAllAround(new PacketMechaControl(this), posX, posY, posZ, FlansMod.driveableUpdateRange, dimension);
    }
   
    for(EntitySeat seat : seats)
    {
      if(seat != null)
        seat.updatePosition();
    }
   
    if(!driverIsLiving || thePlayerIsDrivingThis)
      legSwing = legSwing / type.legSwingLimit;
  }
 
  private float tailFloat(float f)
  {
    return f - MathHelper.floor_float(f);
  }
 
  /** This is a series of iterators which check all upgrades
   *  for various triggers and multipliers */
 
  /** Stop fall damage? */
  public boolean stopFallDamage()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.stopMechaFallDamage)
        return true;
    }
    return false;
  }
 
  /** Force fall to break blocks? */
  public boolean breakBlocksUponFalling()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.forceBlockFallDamage)
        return true;
    }
    return false;
  }
 
  /** Vacuum items? */
  public boolean vacuumItems()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.vacuumItems)
        return true;
    }
    return false;
  }
 
  /** Refine iron? */
  public boolean refineIron()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.refineIron)
        return true;
    }
    return false;
  }
 
  /** Detect Diamonds? */
  public MechaItemType diamondDetect()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.diamondDetect)
        return type;
    }
    return null;
  }
 
  /** Compact Waste? */
  public Boolean wasteCompact()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.wasteCompact)
        return true;
    }
    return false;
  }
 
  /** Diamond yield multiplier */
  public float diamondMultiplier()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= type.fortuneDiamond;
    }
    return multiplier;
  }
 
  /** Movement speed multiplier */
  public float speedMultiplier()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= type.speedMultiplier;
    }
    return multiplier;
  }
 
  /** Coal yield multiplier */
  public float coalMultiplier()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= type.fortuneCoal;
    }
    return multiplier;
  }
 
  /** Redstone yield multiplier */
  public float redstoneMultiplier()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= type.fortuneRedstone;
    }
    return multiplier;
  }
 
  /** Vulnerability */
  public float vulnerability()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= (1 - type.damageResistance);
    }
    return multiplier;
  }
 
  /** Emerald yield multiplier */
  public float emeraldMultiplier()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= type.fortuneEmerald;
    }
    return multiplier;
  }
 
  /** Iron yield multiplier */
  public float ironMultiplier()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= type.fortuneIron;
    }
    return multiplier;
  }
 
  /** Light Level */
  public int lightLevel()
  {
    int level = 0;
    for(MechaItemType type : getUpgradeTypes())
    {
      level = Math.max(level, type.lightLevel);
    }
    return level;
  }
 
  /** Force Darkness */
  public boolean forceDark()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.forceDark)
        return true;
    }
    return false;
  }

  /** Convert coal to fuel? */
  public boolean autoCoal()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.autoCoal)
        return true;
    }
    return false;
  }
 
  /** Automatically repair damage? */
  public boolean autoRepair()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.autoRepair)
        return true;
    }
    return false;
  }
 
  /** Float in water? */
  public boolean shouldFloat()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.floater)
        return true;
    }
    return false;
  }
 
  /** Have infinite ammo? */
  public boolean infiniteAmmo()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.infiniteAmmo)
        return true;
    }
    return false;
  }
 
  /** Have a Rocket Pack? */
  public MechaItemType rocketPack()
  {
    for(MechaItemType type : getUpgradeTypes())
    {
      if(type.rocketPack)
        return type;
    }
    return null;
  }
 
  public boolean shouldFly()
  {
    return rocketPack() != null;
  }
 
  /** Jetpack multiplier */
  public float jetPackPower()
  {
    float multiplier = 1F;
    for(MechaItemType type : getUpgradeTypes())
    {
      multiplier *= type.rocketPower;
    }
    return multiplier;
  }
 
  public ArrayList<MechaItemType> getUpgradeTypes()
  {
    ArrayList<MechaItemType> types = new ArrayList<MechaItemType>();
    for(ItemStack stack : inventory.stacks.values())
    {
      if(stack != null && stack.getItem() instanceof ItemMechaAddon)
      {
        types.add(((ItemMechaAddon)stack.getItem()).type);
      }
    }
    return types;
  }
 
  @SideOnly(Side.CLIENT)
  @Override
  public boolean showInventory(int seat)
  {
    return seat != 0;
  }
 
  @Override
  protected void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part)
  {

  }

  @Override
  public boolean hasMouseControlMode()
  {
    return false;
  }

  @Override
  public String getBombInventoryName()
  {
    return "";
  }
 
  @Override
  public String getMissileInventoryName()
  {
    return "";
  }
 
  @Override
  @SideOnly(Side.CLIENT)
  public EntityLivingBase getCamera()
  {
    return null;
  }
}
TOP

Related Classes of com.flansmod.common.driveables.mechas.EntityMecha

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.