Package com.flansmod.common.driveables

Source Code of com.flansmod.common.driveables.EntityDriveable

package com.flansmod.common.driveables;

import java.util.ArrayList;

import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.MovingObjectPosition.MovingObjectType;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

import com.flansmod.api.IControllable;
import com.flansmod.api.IExplodeable;
import com.flansmod.client.EntityCamera;
import com.flansmod.client.FlansModClient;
import com.flansmod.client.debug.EntityDebugVector;
import com.flansmod.common.FlansMod;
import com.flansmod.common.RotatedAxes;
import com.flansmod.common.guns.BulletType;
import com.flansmod.common.guns.EntityBullet;
import com.flansmod.common.guns.EntityShootable;
import com.flansmod.common.guns.EnumFireMode;
import com.flansmod.common.guns.GunType;
import com.flansmod.common.guns.ItemBullet;
import com.flansmod.common.guns.ItemShootable;
import com.flansmod.common.guns.ShootableType;
import com.flansmod.common.guns.raytracing.BulletHit;
import com.flansmod.common.guns.raytracing.DriveableHit;
import com.flansmod.common.network.PacketDriveableDamage;
import com.flansmod.common.network.PacketDriveableKeyHeld;
import com.flansmod.common.network.PacketPlaySound;
import com.flansmod.common.teams.TeamsManager;
import com.flansmod.common.types.InfoType;
import com.flansmod.common.vector.Vector3f;

public abstract class EntityDriveable extends Entity implements IControllable, IExplodeable, IEntityAdditionalSpawnData
{
  public boolean syncFromServer = true;
  /** Ticks since last server update. Use to smoothly transition to new position */
  public int serverPositionTransitionTicker;
  /** Server side position, as synced by PacketVehicleControl packets */
    public double serverPosX, serverPosY, serverPosZ;
  /** Server side rotation, as synced by PacketVehicleControl packets */
    public double serverYaw, serverPitch, serverRoll;
 
  /** The driveable data which contains the inventory, the engine and the fuel */
  public DriveableData driveableData;
  /** The shortName of the driveable type, used to obtain said type */
  public String driveableType;
 
  /** The throttle, in the range -1, 1 is multiplied by the maxThrottle (or maxNegativeThrottle) from the plane type to obtain the thrust */
  public float throttle;
    /** The wheels on this plane */
  public EntityWheel[] wheels;
 
  public boolean fuelling;
  /** Extra prevRoation field for smoothness in all 3 rotational axes */
  public float prevRotationRoll;
  /** Angular velocity */
  public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F);
 
  /** Whether each mouse button is held */
  public boolean leftMouseHeld = false, rightMouseHeld = false;
 
  /** Shoot delay variables */
  public int shootDelayPrimary, shootDelaySecondary;
  /** Minigun speed variables */
  public float minigunSpeedPrimary, minigunSpeedSecondary;
  /** Current gun variables for alternating weapons. */
  public int currentGunPrimary, currentGunSecondary;
 
  public RotatedAxes prevAxes;
  public RotatedAxes axes;
 
  public EntitySeat[] seats;
 
  @SideOnly(Side.CLIENT)
  public EntityLivingBase camera;
 
    public EntityDriveable(World world)
    {
        super(world);
    axes = new RotatedAxes();
    prevAxes = new RotatedAxes();
        preventEntitySpawning = true;
        setSize(1F, 1F);
        yOffset = 6F / 16F;
    ignoreFrustumCheck = true;
    renderDistanceWeight = 200D;
    }
 
  public EntityDriveable(World world, DriveableType t, DriveableData d)
  {
    this(world);
    driveableType = t.shortName;
    driveableData = d;
  }
 
  protected void initType(DriveableType type, boolean clientSide)
  {
    seats = new EntitySeat[type.numPassengers + 1];
    for(int i = 0; i < type.numPassengers + 1; i++)
    {
      if(!clientSide)
      {
        seats[i] = new EntitySeat(worldObj, this, i);
        worldObj.spawnEntityInWorld(seats[i]);
      }
    }
    wheels = new EntityWheel[type.wheelPositions.length];
    for(int i = 0; i < wheels.length; i++)
    {
      if(!clientSide)
      {
        wheels[i] = new EntityWheel(worldObj, this, i);
        worldObj.spawnEntityInWorld(wheels[i]);
      }
    }
    stepHeight = type.wheelStepHeight;
    yOffset = type.yOffset;
   
    //Register Plane to Radar on Spawning
    //if(type.onRadar == true)
    //  RadarRegistry.register(this);
  }
 
  @Override
    protected void writeEntityToNBT(NBTTagCompound tag)
    {
    driveableData.writeToNBT(tag);
    tag.setString("Type", driveableType);
    tag.setFloat("RotationYaw", axes.getYaw());
    tag.setFloat("RotationPitch", axes.getPitch());
    tag.setFloat("RotationRoll", axes.getRoll());
    }

  @Override
    protected void readEntityFromNBT(NBTTagCompound tag)
    {
    driveableType = tag.getString("Type");
    driveableData = new DriveableData(tag);
    initType(DriveableType.getDriveable(driveableType), false);
   
    prevRotationYaw = tag.getFloat("RotationYaw");
    prevRotationPitch = tag.getFloat("RotationPitch");
    prevRotationRoll = tag.getFloat("RotationRoll");
    axes = new RotatedAxes(prevRotationYaw, prevRotationPitch, prevRotationRoll);
    }
 
  @Override
  public void writeSpawnData(ByteBuf data)
  {
    ByteBufUtils.writeUTF8String(data, driveableType);
   
    NBTTagCompound tag = new NBTTagCompound();
    driveableData.writeToNBT(tag);
    ByteBufUtils.writeTag(data, tag);
   
    data.writeFloat(axes.getYaw());
    data.writeFloat(axes.getPitch());
    data.writeFloat(axes.getRoll());
   
    //Write damage
      for(EnumDriveablePart ep : EnumDriveablePart.values())
      {
        DriveablePart part = getDriveableData().parts.get(ep);
        data.writeShort((short)part.health);
        data.writeBoolean(part.onFire);
      }
  }

  @Override
  public void readSpawnData(ByteBuf data)
  {
    try
    {
      driveableType = ByteBufUtils.readUTF8String(data);
      driveableData = new DriveableData(ByteBufUtils.readTag(data));
      initType(getDriveableType(), true);
     
      axes.setAngles(data.readFloat(), data.readFloat(), data.readFloat());
      prevRotationYaw = axes.getYaw();
      prevRotationPitch = axes.getPitch();
      prevRotationRoll = axes.getRoll();
     
      //Read damage
          for(EnumDriveablePart ep : EnumDriveablePart.values())
          {
            DriveablePart part = getDriveableData().parts.get(ep);
            part.health = data.readShort();
            part.onFire = data.readBoolean();
          }

    }
    catch(Exception e)
    {
      FlansMod.log("Failed to retreive plane type from server.");
      super.setDead();
      e.printStackTrace();
    }
   
    camera = new EntityCamera(worldObj, this);
    worldObj.spawnEntityInWorld(camera);
  }
  /**
   * Called with the movement of the mouse. Used in controlling vehicles if need be.
   * @param deltaY
   * @param deltaX
   * @return if mouse movement was handled.
   */
  @Override
  public abstract void onMouseMoved(int deltaX, int deltaY);
 
  @Override
  @SideOnly(Side.CLIENT)
  public EntityLivingBase getCamera()
  {
    return camera;
  }

  protected boolean canSit(int seat)
  {
    return getDriveableType().numPassengers >= seat && seats[seat].riddenByEntity == null;
  }
 
  @Override
    protected boolean canTriggerWalking()
    {
        return false;
    }

  @Override
    protected void entityInit()
    {
    }

  @Override
    public AxisAlignedBB getCollisionBox(Entity entity)
    {
        return null;//entity.boundingBox;
    }

  @Override
    public AxisAlignedBB getBoundingBox()
    {
        return boundingBox;
    }

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

  @Override
    public double getMountedYOffset()
    {
        return -0.3D;
    }
 
  @Override
  /** Pass generic damage to the core */
  public boolean attackEntityFrom(DamageSource damagesource, float i)
    {
      if(worldObj.isRemote || isDead)
        {
            return true;
        }
      return attackPart(EnumDriveablePart.core, damagesource, i);
  }
 
  @Override
  public void setDead()
  {
    super.setDead();
   
    //Unregister to Radar
    //RadarRegistry.unregister(this);
    if(worldObj.isRemote)
      camera.setDead();
   
    for(EntitySeat seat : seats)
      if(seat != null)
        seat.setDead();
  }
 
  @Override
  public void onCollideWithPlayer(EntityPlayer par1EntityPlayer)
  {
    //Do nothing. Like a boss.
    // TODO: perhaps send the player flying??
    //Sounds good. ^
  }

  @Override
    public boolean canBeCollidedWith()
    {
        return !isDead;
    }
 
    @Override
    public void applyEntityCollision(Entity entity)
    {
      if(!isPartOfThis(entity))
        super.applyEntityCollision(entity);
    }
 
  @Override
    public void setPositionAndRotation2(double d, double d1, double d2, float f, float f1, int i)
    {
    if(ticksExisted > 1)
      return;
    if(riddenByEntity instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)riddenByEntity))
    {
    }
    else
    {       
      if(syncFromServer)
          {
              serverPositionTransitionTicker = i + 5;
          }
          else
          {
              double var10 = d - posX;
              double var12 = d1 - posY;
              double var14 = d2 - posZ;
              double var16 = var10 * var10 + var12 * var12 + var14 * var14;
 
              if (var16 <= 1.0D)
              {
                  return;
              }
 
              serverPositionTransitionTicker = 3;
          }
          serverPosX = d;
          serverPosY = d1;
          serverPosZ = d2;
          serverYaw = f;
          serverPitch = f1;
    }
    }
 
  public void setPositionRotationAndMotion(double x, double y, double z, float yaw, float pitch, float roll, double motX, double motY, double motZ, float velYaw, float velPitch, float velRoll, float throt, float steeringYaw)
  {
    if(worldObj.isRemote)
    {
          serverPosX = x;
          serverPosY = y;
          serverPosZ = z;
          serverYaw = yaw;
          serverPitch = pitch;
          serverRoll = roll;
          serverPositionTransitionTicker = 5;
    }
    else
    {
      setPosition(x, y, z);
      prevRotationYaw = yaw;
      prevRotationPitch = pitch;
      prevRotationRoll = roll;
      setRotation(yaw, pitch, roll);
    }
    //Set the motions regardless of side.
        motionX = motX;
        motionY = motY;
        motionZ = motZ;
        angularVelocity = new Vector3f(velYaw, velPitch, velRoll);
        throttle = throt;
  }
 

  @Override
    public void setVelocity(double d, double d1, double d2)
    {
        motionX = d;
        motionY = d1;
        motionZ = d2;
    }
 
  @Override
  public boolean pressKey(int key, EntityPlayer player)
  {
    if(!worldObj.isRemote && key == 9 && getDriveableType().modePrimary == EnumFireMode.SEMIAUTO) //Primary
    {
      shoot(false);
      return true;
    }
    else if(!worldObj.isRemote && key == 8 && getDriveableType().modeSecondary == EnumFireMode.SEMIAUTO) //Secondary
    {
      shoot(true);
      return true;
    }
    return false;
  }
 
  @Override
  public void updateKeyHeldState(int key, boolean held)
  {
    if(worldObj.isRemote)
    {
      FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held));
    }
    switch(key)
    {
    case 9 : leftMouseHeld = held; break;
    case 8 : rightMouseHeld = held; break;
    }
  }
 
  /** Shoot method called by pressing / holding shoot buttons */
  public void shoot(boolean secondary)
  {
    DriveableType type = getDriveableType();
    if(seats[0] == null && !(seats[0].riddenByEntity instanceof EntityLivingBase))
      return;
    //Check shoot delay
    if(getShootDelay(secondary) <= 0)
    {
      //We can shoot, so grab the available shoot points and the weaponType
      ArrayList<DriveablePosition> shootPoints = type.shootPoints(secondary);
      EnumWeaponType weaponType = type.weaponType(secondary);
      //If there are no shoot points, return
      if(shootPoints.size() == 0)
        return;
      //For alternating guns, move on to the next one
      int currentGun = getCurrentGun(secondary);
      if(type.alternate(secondary))
      {
        currentGun = (currentGun + 1) % shootPoints.size();
        setCurrentGun(currentGun, secondary);
        shootEach(type, shootPoints.get(currentGun), currentGun, secondary, weaponType);
      }
      else for(int i = 0; i < shootPoints.size(); i++)
        shootEach(type, shootPoints.get(i), i, secondary, weaponType);
    }
  }
 
  private void shootEach(DriveableType type, DriveablePosition shootPoint, int currentGun, boolean secondary, EnumWeaponType weaponType)
  {
    //Rotate the gun vector to global axes
    Vector3f gunVec = getOrigin(shootPoint);
    Vector3f lookVector = getLookVector(shootPoint);
   
    //If its a pilot gun, then it is using a gun type, so do the following
    if(shootPoint instanceof PilotGun)
    {
      PilotGun pilotGun = (PilotGun)shootPoint;
      //Get the gun from the plane type and the ammo from the data
      GunType gunType = pilotGun.type;
      ItemStack bulletItemStack = driveableData.ammo[getDriveableType().numPassengerGunners + currentGun];
      //Check that neither is null and that the bullet item is actually a bullet
      if(gunType != null && bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable && TeamsManager.bulletsEnabled)
      {
        ShootableType bullet = ((ItemShootable)bulletItemStack.getItem()).type;
        if(gunType.isAmmo(bullet))
        {
          //Spawn a new bullet item
          worldObj.spawnEntityInWorld(((ItemShootable)bulletItemStack.getItem()).getEntity(worldObj, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY, (float)posZ), null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, gunType.bulletSpread / 2, gunType.damage, 2.0F,bulletItemStack.getItemDamage(), type));
          //Play the shoot sound
          PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false);
          //Get the bullet item damage and increment it
          int damage = bulletItemStack.getItemDamage();
          bulletItemStack.setItemDamage(damage + 1)
          //If the bullet item is completely damaged (empty)
          if(damage + 1 == bulletItemStack.getMaxDamage())
          {
            //Set the damage to 0 and consume one ammo item (unless in creative)
            bulletItemStack.setItemDamage(0);
            if(seats[0].riddenByEntity instanceof EntityPlayer && !((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode)
            {
              bulletItemStack.stackSize--;
              if(bulletItemStack.stackSize <= 0)
                bulletItemStack = null;
              driveableData.setInventorySlotContents(getDriveableType().numPassengerGunners + currentGun, bulletItemStack);
            }
          }
          //Reset the shoot delay
          setShootDelay(type.shootDelay(secondary), secondary);
        }
      }
    }
    else //One of the other modes
    {
     
     
      switch(weaponType)
      {   
      case BOMB :
      {
        if(TeamsManager.bombsEnabled)
        {
          int slot = -1;
          for(int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++)
          {
            ItemStack bomb = driveableData.getStackInSlot(i);
            if(bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)bomb.getItem()).type, weaponType))
            {
              slot = i;
            }
          }
         
          if(slot != -1)
          {
            int spread = 0;
            int damageMultiplier = 1;
            float shellSpeed = 0F;

            ItemStack bulletStack = driveableData.getStackInSlot(slot);
            ItemBullet bulletItem = (ItemBullet)bulletStack.getItem();
            EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vec3.createVectorHelper(posX + gunVec.x, posY + gunVec.y, posZ + gunVec.z), axes.getYaw(), axes.getPitch(), motionX, motionY, motionZ, (EntityLivingBase)seats[0].riddenByEntity, damageMultiplier, driveableData.getStackInSlot(slot).getItemDamage(), type);
            worldObj.spawnEntityInWorld(bulletEntity);
           
            if(type.shootSound(secondary) != null)
              PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false);         
            if(seats[0].riddenByEntity instanceof EntityPlayer && !((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode)
            {
              bulletStack.setItemDamage(bulletStack.getItemDamage() + 1);
              if(bulletStack.getItemDamage() == bulletStack.getMaxDamage())
              {
                bulletStack.setItemDamage(0);
                bulletStack.stackSize--;
                if(bulletStack.stackSize == 0)
                  bulletStack = null;
              }
              driveableData.setInventorySlotContents(slot, bulletStack);
            }
            setShootDelay(type.shootDelay(secondary), secondary);
          }
        }
        break;
      }   
      case MISSILE : //These two are actually almost identical
      case SHELL :
      {
        if(TeamsManager.shellsEnabled)
        {
          int slot = -1;
          for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++)
          {
            ItemStack shell = driveableData.getStackInSlot(i);
            if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)shell.getItem()).type, weaponType))
            {
              slot = i;
            }
          }
         
          if(slot != -1)
          {
            int spread = 0;
            int damageMultiplier = 1;
            float shellSpeed = 3F;

            ItemStack bulletStack = driveableData.getStackInSlot(slot);
            ItemBullet bulletItem = (ItemBullet)bulletStack.getItem();
            EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type);
            worldObj.spawnEntityInWorld(bulletEntity);
           
            if(type.shootSound(secondary) != null)
              PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false);         
            if(seats[0].riddenByEntity instanceof EntityPlayer && !((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode)
            {
              bulletStack.setItemDamage(bulletStack.getItemDamage() + 1);
              if(bulletStack.getItemDamage() == bulletStack.getMaxDamage())
              {
                bulletStack.setItemDamage(0);
                bulletStack.stackSize--;
                if(bulletStack.stackSize == 0)
                  bulletStack = null;
              }
              driveableData.setInventorySlotContents(slot, bulletStack);
            }
            setShootDelay(type.shootDelay(secondary), secondary);
          }
        }
        break;
      }       
      case GUN: //Handled above
        break;
      case MINE:
        break;
      case NONE:
        break;
      }
    }
  }
 
  public Vector3f getOrigin(DriveablePosition dp)
  {
    //Rotate the gun vector to global axes
    Vector3f localGunVec = new Vector3f(dp.position);
       
    if(dp.part == EnumDriveablePart.turret)
    {
      //Untranslate by the turret origin, to get the rotation about the right point
      Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec);
      //Rotate by the turret angles
      localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec);
      //Translate by the turret origin
      Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec);
    }
   
    return rotate(localGunVec);
  }
 
  public Vector3f getLookVector(DriveablePosition dp)
  {
    return axes.getXAxis();
  }
   
  @Override
    public void onUpdate()
    {
        super.onUpdate();
       
        DriveableType type = getDriveableType();
       
        if(!worldObj.isRemote)
        {
          for(int i = 0; i < getDriveableType().numPassengers + 1; i++)
          {
            if(seats[i] == null || !seats[i].addedToChunk)
            {
              seats[i] = new EntitySeat(worldObj, this, i);
            worldObj.spawnEntityInWorld(seats[i]);
            }
          }
          for(int i = 0; i < type.wheelPositions.length; i++)
          {
            if(wheels[i] == null || !wheels[i].addedToChunk)
            {
              wheels[i] = new EntityWheel(worldObj, this, i);
            worldObj.spawnEntityInWorld(wheels[i]);
            }
          }
        }
       
        for(DriveablePart part : getDriveableData().parts.values())
        {
          if(part.box != null)
          {
           
            part.update(this);
            //Client side particles
            if(worldObj.isRemote)
            {
                 if(part.onFire)
              {
                //Pick a random position within the bounding box and spawn a flame there
                Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d));
                worldObj.spawnParticle("flame", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0);
              }
                 if(part.health > 0 && part.health < part.maxHealth / 2)
              {
                //Pick a random position within the bounding box and spawn a flame there
                Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + rand.nextFloat() * part.box.w, part.box.y + rand.nextFloat() * part.box.h, part.box.z + rand.nextFloat() * part.box.d));
                worldObj.spawnParticle(part.health < part.maxHealth / 4 ? "largesmoke" : "smoke", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0);
              }
            }
            //Server side fire handling
            if(part.onFire)
            {
              //Rain can put out fire
              if(worldObj.isRaining() && rand.nextInt(40) == 0)
                part.onFire = false;
              //Also water blocks
              //Get the centre point of the part
              Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x + part.box.w / 2F, part.box.y + part.box.h / 2F, part.box.z + part.box.d / 2F));
              if(worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.water)
              {
                part.onFire = false;
              }
            }
            else
            {
              Vector3f pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F));
              if(worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.lava)
              {
                part.onFire = true;
              }
            }
          }
        }
       
        checkParts();
       
    prevRotationYaw = axes.getYaw();
    prevRotationPitch = axes.getPitch();
    prevRotationRoll = axes.getRoll();   
    prevAxes = axes.clone();
   
        if(riddenByEntity != null && riddenByEntity.isDead)
        {
            riddenByEntity = null;
        }
    if(riddenByEntity != null && isDead)
    {
      riddenByEntity.mountEntity(null);
    }
    if(riddenByEntity != null)
      riddenByEntity.fallDistance = 0F;
   
    boolean canThrust = (seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode) || driveableData.fuelInTank > 0;

    //If the player jumps out or dies, smoothly return the throttle to 0 so the plane might actually come down again */
    if((seats[0] != null && seats[0].riddenByEntity == null) || !canThrust)
    {
      throttle *= 0.98F;
      rightMouseHeld = leftMouseHeld = false;
    }
   
    //Check if shooting
    if(shootDelayPrimary > 0)
      shootDelayPrimary--;
    if(shootDelaySecondary > 0)
      shootDelaySecondary--;
    if(!worldObj.isRemote)
    {
      if(leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.FULLAUTO)
        shoot(false);
      if(rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.FULLAUTO)
        shoot(true);
      minigunSpeedPrimary *= 0.9F;
      minigunSpeedSecondary *= 0.9F;
      if(leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.MINIGUN)
      {
        minigunSpeedPrimary += 0.1F;
        if(minigunSpeedPrimary > 1F)
          shoot(false);
      }
      if(rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.MINIGUN)
      {
        minigunSpeedSecondary += 0.1F;
        if(minigunSpeedSecondary > 1F)
          shoot(true);
      }
    }
    }
 
  public void checkForCollisions()
  {
    boolean crashInWater = false;
    double speed = getSpeedXYZ();
    for(DriveablePosition p : getDriveableType().collisionPoints)
    {
      if(driveableData.parts.get(p.part).dead)
        continue;
      Vector3f lastRelPos = prevAxes.findLocalVectorGlobally(p.position);
      Vec3 lastPos = Vec3.createVectorHelper(prevPosX + lastRelPos.x, prevPosY + lastRelPos.y, prevPosZ + lastRelPos.z);
     
      Vector3f currentRelPos = axes.findLocalVectorGlobally(p.position);
      Vec3 currentPos = Vec3.createVectorHelper(posX + currentRelPos.x, posY + currentRelPos.y, posZ + currentRelPos.z);
     
      if(FlansMod.DEBUG && worldObj.isRemote)
      {
        worldObj.spawnEntityInWorld(new EntityDebugVector(worldObj, new Vector3f(lastPos), Vector3f.sub(currentRelPos, lastRelPos, null), 10, 1F, 0F, 0F));
      }
     
      MovingObjectPosition hit = worldObj.rayTraceBlocks(lastPos, currentPos, crashInWater);
      if(hit != null && hit.typeOfHit == MovingObjectType.BLOCK)
      {
        int x = hit.blockX;
        int y = hit.blockY;
        int z = hit.blockZ;
        Block blockHit = worldObj.getBlock(x, y, z);
        int meta = worldObj.getBlockMetadata(x, y, z);
       
        float blockHardness = blockHit.getBlockHardness(worldObj, x, y, z);
       
        //Attack the part
        if(!attackPart(p.part, DamageSource.inWall, blockHardness * blockHardness * (float)speed) && TeamsManager.driveablesBreakBlocks)
        {
          //And if it didn't die from the attack, break the block
          worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(blockHit) + (meta << 12));         
         
          if(!worldObj.isRemote)
          { 
            blockHit.dropBlockAsItem(worldObj, x, y, z, meta, 1);   
            worldObj.setBlockToAir(x, y, z);
          }
        }
        else
        {
          //The part died!
          worldObj.createExplosion(this, currentPos.xCoord, currentPos.yCoord, currentPos.zCoord, 1F, false);
        }
      }
     
    }
  }
 
  @Override
    protected void fall(float k)
    {
        if (k <= 0)
          return;
        //super.fall(k);
        int i = MathHelper.ceiling_float_int(k - 10F);

        if(i > 0)
          attackPart(EnumDriveablePart.core, DamageSource.fall, i / 5);
    }
 
  /** Attack a certain part of a driveable and return whether it broke or not */
  public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage)
  {
    DriveablePart part = driveableData.parts.get(ep);
    return part.attack(damage, source.isFireDamage());
  }
   
  /** Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates */
  public Vector3f rotate(Vector3f inVec)
  {
    return axes.findLocalVectorGlobally(inVec);
  }
   
  /** Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates */
  public Vector3f rotate(Vec3 inVec)
  {
    return rotate(inVec.xCoord, inVec.yCoord, inVec.zCoord);
  }

  /** Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates */
  public Vector3f rotate(double x, double y, double z)
  { 
    return rotate(new Vector3f((float)x, (float)y, (float)z));
  }
 
  //Rotate the plane locally by some angle about the yaw axis
  public void rotateYaw(float rotateBy)
  {
    if(Math.abs(rotateBy) < 0.01F)
      return;
    axes.rotateLocalYaw(rotateBy);
    updatePrevAngles();
  }
 
  //Rotate the plane locally by some angle about the pitch axis
  public void rotatePitch(float rotateBy)
  {
    if(Math.abs(rotateBy) < 0.01F)
      return;
    axes.rotateLocalPitch(rotateBy);
    updatePrevAngles();
  }
 
  //Rotate the plane locally by some angle about the roll axis
  public void rotateRoll(float rotateBy)
  {
    if(Math.abs(rotateBy) < 0.01F)
      return;
    axes.rotateLocalRoll(rotateBy);
    updatePrevAngles();
  }
   
  public void updatePrevAngles()
  {   
    //Correct angles that crossed the +/- 180 line, so that rendering doesnt make them swing 360 degrees in one tick.
    double dYaw = axes.getYaw() - prevRotationYaw;
    if(dYaw > 180)
      prevRotationYaw += 360F;
    if(dYaw < -180)
      prevRotationYaw -= 360F;
   
    double dPitch = axes.getPitch() - prevRotationPitch;
    if(dPitch > 180)
      prevRotationPitch += 360F;
    if(dPitch < -180)
      prevRotationPitch -= 360F;
   
    double dRoll = axes.getRoll() - prevRotationRoll;
    if(dRoll > 180)
      prevRotationRoll += 360F;
    if(dRoll < -180)
      prevRotationRoll -= 360F;
  }
     
  public void setRotation(float rotYaw, float rotPitch, float rotRoll)
  {
    axes.setAngles(rotYaw, rotPitch, rotRoll);
  }
 
  //Used to stop self collision
  public boolean isPartOfThis(Entity ent)
  {
    for(EntitySeat seat : seats)
    {
      if(seat == null)
        continue;
      if(ent == seat)
        return true;
      if(seat.riddenByEntity == ent)
        return true;
    }
    return ent == this
  }

  @Override
    public float getShadowSize()
    {
        return 0.0F;
    }
   
    public DriveableType getDriveableType()
    {
      return DriveableType.getDriveable(driveableType);
    }
   
    public DriveableData getDriveableData()
    {
      return driveableData;
    }
 
  @Override
  public boolean isDead()
  {
    return isDead;
  }
 
  @Override
  public Entity getControllingEntity()
  {
    return seats[0].getControllingEntity();
  }
 
  @Override
    public ItemStack getPickedResult(MovingObjectPosition target)
    {
    ItemStack stack = new ItemStack(getDriveableType().item, 1, 0);
    stack.stackTagCompound = new NBTTagCompound();
    driveableData.writeToNBT(stack.stackTagCompound);
    return stack;
    }
 
   
    public boolean hasFuel()
    {
      if(seats == null || seats[0] == null || seats[0].riddenByEntity == null)
        return false;
      if(seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode)
        return true;
      return driveableData.fuelInTank > 0;
    }
   
    public boolean hasEnoughFuel()
    {
      if(seats == null || seats[0] == null || seats[0].riddenByEntity == null)
        return false;
      if(seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode)
        return true;
     
    return driveableData.fuelInTank > driveableData.engine.fuelConsumption * throttle;
    }
 
  //Physics time! Oooh yeah
 
  public double getSpeedXYZ()
  {
    return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ);
  }
 
  public double getSpeedXZ()
  {
    return Math.sqrt(motionX * motionX + motionZ * motionZ);
  }
 
  /** To be overriden by vehicles to get alternate collision system */
  public boolean landVehicle()
  {
    return false;
  }
 
  /** Overriden by planes for wheel parts */
  public boolean gearDown()
  {
    return true;
  }
 
  /** Whether or not the plane is on the ground
   * TODO : Replace with proper check based on wheels
   * */
  public boolean onGround()
  {
    return onGround;
  }
   
  /** Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit */
  public ArrayList<BulletHit> attackFromBullet(Vector3f origin, Vector3f motion)
  {
    //Make an array to contain the hits
    ArrayList<BulletHit> hits = new ArrayList<BulletHit>();
    //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates
    Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float)posX, (float)posY, (float)posZ), null);
    Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector);
    Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion);
    //Check each part
    for(DriveablePart part : getDriveableData().parts.values())
    {
      //Ray trace the bullet
      DriveableHit hit = part.rayTrace(this, rotatedPosVector, rotatedMotVector);
      if(hit != null)
        hits.add(hit);
    }
    return hits;
  }
 
  /** Called if the bullet actually hit the part returned by the raytrace
   * @param penetratingPower */
  public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingPower)
  {
    DriveablePart part = getDriveableData().parts.get(hit.part);
    part.hitByBullet(bullet);
   
    //This is server side bsns
    if(!worldObj.isRemote)
    {
      checkParts();
      //If it hit, send a damage update packet
      FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension);
    }
   
    return penetratingPower - 5F;
  }
 
  /** A simple raytracer for the driveable. Called by tools */
  public DriveablePart raytraceParts(Vector3f origin, Vector3f motion)
  {
    //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates
    Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float)posX, (float)posY, (float)posZ), null);
    Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector);
    Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion);
    //Check each part
    for(DriveablePart part : getDriveableData().parts.values())
    {
      //Ray trace the bullet
      if(part.rayTrace(this, rotatedPosVector, rotatedMotVector) != null)
      {
        return part;
      }
    }
    return null;
  }
 
  /** For overriding for toggles such as gear up / down on planes */
  public boolean canHitPart(EnumDriveablePart part)
  {
    return true;
  }
 
  /** Internal method for checking that all parts are ok, destroying broken ones, dropping items and making sure that child parts are destroyed when their parents are */
  public void checkParts()
  {
    for(DriveablePart part : getDriveableData().parts.values())
    {
      if(part != null && !part.dead && part.health <= 0 && part.maxHealth > 0)
      {
        killPart(part);
      }
    }
   
   
    for(EntitySeat seat : seats)
    {
     
    }
   
    //If the core was destroyed, kill the driveable
    if(getDriveableData().parts.get(EnumDriveablePart.core).dead)
      setDead();
  }
 
  /** Internal method for killing driveable parts */
  private void killPart(DriveablePart part)
  {
    if(part.dead)
      return;
    part.health = 0;
    part.dead = true;
   
    //Drop items
    DriveableType type = getDriveableType();
    if(!worldObj.isRemote)
    {
      Vector3f pos = new Vector3f(0, 0, 0);
         
      //Get the midpoint of the part
      if(part.box != null)
          pos = axes.findLocalVectorGlobally(new Vector3f(part.box.x / 16F + part.box.w / 32F, part.box.y / 16F + part.box.h / 32F, part.box.z / 16F + part.box.d / 32F));
         
      ArrayList<ItemStack> drops = type.getItemsRequired(part, getDriveableData().engine);
        if(drops != null)
      {
        //Drop each itemstack
            for(ItemStack stack : drops)
        {
          worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + pos.x, posY + pos.y, posZ + pos.z, stack.copy()));
        }
      }
      dropItemsOnPartDeath(pos, part);
     
      //Inventory is in the core, so drop it if the core is broken
      if(part.type == EnumDriveablePart.core)
      {
        for(int i = 0; i < getDriveableData().getSizeInventory(); i++)
        {
          ItemStack stack = getDriveableData().getStackInSlot(i);
          if(stack != null)
          {
            worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + rand.nextGaussian(), posY + rand.nextGaussian(), posZ + rand.nextGaussian(), stack));
          }
        }
      }
    }
   
    //Kill all child parts to stop things floating unconnected
    for(EnumDriveablePart child : part.type.getChildren())
    {
      killPart(getDriveableData().parts.get(child));
    }
  }
 
  /** Method for planes, vehicles and whatnot to drop their own specific items if they wish */
  protected abstract void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part);
 
  @Override
  public float getPlayerRoll()
  {
    return axes.getRoll();
  }

  @Override
  public void explode()
  {
   
  }
 
  @Override
  public float getCameraDistance()
  {
    return getDriveableType().cameraDistance;
  }
 
  public boolean isPartIntact(EnumDriveablePart part)
  {
    DriveablePart thisPart = getDriveableData().parts.get(part);
    return thisPart.maxHealth == 0 || thisPart.health > 0;
  }
 
  public abstract boolean hasMouseControlMode();
 
  public abstract String getBombInventoryName();
 
  public abstract String getMissileInventoryName();
 
  public boolean rotateWithTurret(Seat seat)
  {
    return seat.part == EnumDriveablePart.turret;
  }
 
  @Override
  public String getCommandSenderName()
  {
    return getDriveableType().name;
  }
 
  @SideOnly(Side.CLIENT)
  public boolean showInventory(int seat)
  {
    return seat != 0 || !FlansModClient.controlModeMouse;
  }

  //-------------------------------------
  // Getters and setters for dual fields
  //-------------------------------------
 
  public int getShootDelay(boolean secondary)
  {
    return secondary ? shootDelaySecondary : shootDelayPrimary;
  }
 
  public float getMinigunSpeed(boolean secondary)
  {
    return secondary ? minigunSpeedSecondary : minigunSpeedPrimary;
  }
 
  public int getCurrentGun(boolean secondary)
  {
    return secondary ? currentGunSecondary : currentGunPrimary;
  }
 
  public void setShootDelay(int i, boolean secondary)
  {
    if(secondary)
      shootDelaySecondary = i;
    else shootDelayPrimary = i;
  }
 
  public void setMinigunSpeed(float f, boolean secondary)
  {
    if(secondary)
      minigunSpeedSecondary = f;
    else minigunSpeedPrimary = f;
  }
 
  public void setCurrentGun(int i, boolean secondary)
  {
    if(secondary)
      currentGunSecondary = i;
    else currentGunPrimary = i;
  }
 
 
 
}
TOP

Related Classes of com.flansmod.common.driveables.EntityDriveable

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.