Advertisement
Guest User

Untitled

a guest
Jan 6th, 2018
1,044
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 98.91 KB | None | 0 0
  1. package com.flansmod.common.driveables;
  2.  
  3. import io.netty.buffer.ByteBuf;
  4.  
  5. import java.util.ArrayList;
  6.  
  7. import org.lwjgl.opengl.GL11;
  8.  
  9. import net.minecraft.block.Block;
  10. import net.minecraft.block.material.Material;
  11. import net.minecraft.entity.Entity;
  12. import net.minecraft.entity.EntityLiving;
  13. import net.minecraft.entity.EntityLivingBase;
  14. import net.minecraft.entity.item.EntityItem;
  15. import net.minecraft.entity.passive.EntityAnimal;
  16. import net.minecraft.entity.player.EntityPlayer;
  17. import net.minecraft.entity.player.EntityPlayerMP;
  18. import net.minecraft.init.Items;
  19. import net.minecraft.item.Item;
  20. import net.minecraft.item.ItemStack;
  21. import net.minecraft.nbt.NBTTagCompound;
  22. import net.minecraft.util.AxisAlignedBB;
  23. import net.minecraft.util.ChatComponentText;
  24. import net.minecraft.util.DamageSource;
  25. import net.minecraft.util.EntityDamageSourceIndirect;
  26. import net.minecraft.util.MathHelper;
  27. import net.minecraft.util.MovingObjectPosition;
  28. import net.minecraft.util.MovingObjectPosition.MovingObjectType;
  29. import net.minecraft.util.Vec3;
  30. import net.minecraft.world.World;
  31. import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
  32. import cofh.api.energy.IEnergyContainerItem;
  33.  
  34. import com.flansmod.api.IControllable;
  35. import com.flansmod.api.IExplodeable;
  36. import com.flansmod.client.EntityCamera;
  37. import com.flansmod.client.FlansModClient;
  38. import com.flansmod.client.debug.EntityDebugVector;
  39. import com.flansmod.common.FlansMod;
  40. import com.flansmod.common.RotatedAxes;
  41. import com.flansmod.common.driveables.DriveableType.ParticleEmitter;
  42. import com.flansmod.common.driveables.DriveableType.ShootParticle;
  43. import com.flansmod.common.driveables.collisions.CollisionPlane;
  44. import com.flansmod.common.driveables.collisions.CollisionShapeBox;
  45. import com.flansmod.common.driveables.collisions.CollisionTest;
  46. import com.flansmod.common.driveables.collisions.RidingEntityPosition;
  47. import com.flansmod.common.driveables.mechas.EntityMecha;
  48. import com.flansmod.common.guns.EntityBullet;
  49. import com.flansmod.common.guns.EntityDamageSourceGun;
  50. import com.flansmod.common.guns.EntityShootable;
  51. import com.flansmod.common.guns.EnumFireMode;
  52. import com.flansmod.common.guns.GunType;
  53. import com.flansmod.common.guns.InventoryHelper;
  54. import com.flansmod.common.guns.ItemBullet;
  55. import com.flansmod.common.guns.ItemShootable;
  56. import com.flansmod.common.guns.ShootableType;
  57. import com.flansmod.common.guns.raytracing.BulletHit;
  58. import com.flansmod.common.guns.raytracing.DriveableHit;
  59. import com.flansmod.common.network.PacketDriveableDamage;
  60. import com.flansmod.common.network.PacketDriveableKeyHeld;
  61. import com.flansmod.common.network.PacketParticle;
  62. import com.flansmod.common.network.PacketPlaySound;
  63. import com.flansmod.common.parts.ItemPart;
  64. import com.flansmod.common.parts.PartType;
  65. import com.flansmod.common.teams.TeamsManager;
  66. import com.flansmod.common.tools.ItemTool;
  67. import com.flansmod.common.types.InfoType;
  68. import com.flansmod.common.vector.Vector3f;
  69.  
  70. import cpw.mods.fml.common.eventhandler.SubscribeEvent;
  71. import cpw.mods.fml.common.gameevent.TickEvent.PlayerTickEvent;
  72. import cpw.mods.fml.common.network.ByteBufUtils;
  73. import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
  74. import cpw.mods.fml.relauncher.Side;
  75. import cpw.mods.fml.relauncher.SideOnly;
  76.  
  77. public abstract class EntityDriveable extends Entity implements IControllable, IExplodeable, IEntityAdditionalSpawnData
  78. {
  79.     //I�m Rick Harrison, and this is my pawn shop. I work here with my old man and my son, Big Hoss. Everything in here has a story and a price. One thing I�ve learned after 21 years � you never know WHAT is gonna come through that doo
  80.     public boolean syncFromServer = true;
  81.     /** Ticks since last server update. Use to smoothly transition to new position */
  82.     public int serverPositionTransitionTicker;
  83.     /** Server side position, as synced by PacketVehicleControl packets */
  84.     public double serverPosX, serverPosY, serverPosZ;
  85.     /** Server side rotation, as synced by PacketVehicleControl packets */
  86.     public double serverYaw, serverPitch, serverRoll;
  87.  
  88.     /** The driveable data which contains the inventory, the engine and the fuel */
  89.     public DriveableData driveableData;
  90.     /** The shortName of the driveable type, used to obtain said type */
  91.     public String driveableType;
  92.  
  93.     /** The throttle, in the range -1, 1 is multiplied by the maxThrottle (or maxNegativeThrottle) from the plane type to obtain the thrust */
  94.     public float throttle;
  95.     /** The wheels on this plane */
  96.     public EntityWheel[] wheels;
  97.  
  98.     public boolean fuelling;
  99.     /** Extra prevRoation field for smoothness in all 3 rotational axes */
  100.     public float prevRotationRoll;
  101.     /** Angular velocity */
  102.     public Vector3f angularVelocity = new Vector3f(0F, 0F, 0F);
  103.  
  104.     /** Whether each mouse button is held */
  105.     public boolean leftMouseHeld = false, rightMouseHeld = false;
  106.  
  107.     /** Shoot delay variables */
  108.     public int shootDelayPrimary, shootDelaySecondary;
  109.     /** Minigun speed variables */
  110.     public float minigunSpeedPrimary, minigunSpeedSecondary;
  111.     /** Current gun variables for alternating weapons. */
  112.     public int currentGunPrimary, currentGunSecondary;
  113.  
  114.     /** Angle of harvester aesthetic piece */
  115.     public float harvesterAngle;
  116.  
  117.     public RotatedAxes prevAxes;
  118.     public RotatedAxes axes;
  119.  
  120.     public EntitySeat[] seats;
  121.  
  122.     /** The ID of the slot that we are pulling fuel from. -1 means we have not found one */
  123.     private int foundFuel = -1;
  124.     /** True if we need fuel but could not find any in the inventory. Reset when the inventory updated */
  125.     public boolean couldNotFindFuel = false;
  126.  
  127.     public boolean isAmmoPlaced = false;
  128.  
  129.     public int lockOnSoundDelay;
  130.  
  131.     private int[] emitterTimers;
  132.  
  133.     public int animCountLeft = 0;
  134.     public int animFrameLeft = 0;
  135.     public int animCountRight = 0;
  136.     public int animFrameRight = 0;
  137.    
  138.     public boolean leftTurnHeld = false;
  139.     public boolean rightTurnHeld = false;
  140.  
  141.    
  142.     public boolean isShowedPosition = false;
  143.  
  144.     public int tickCount = 0;
  145.  
  146.     public int impactX;
  147.     public int impactY;
  148.     public int impactZ;
  149.    
  150.     //public boolean isLockedOn = false;
  151.  
  152.     //public int soundTime;
  153.  
  154.     public boolean neverLocked = true;
  155.     public String key = "ChangeMe";
  156.     private String lastKey;
  157.    
  158.     //Gun recoil
  159.     public boolean isRecoil = false;
  160.     public float recoilPos = 0;
  161.     public float lastRecoilPos = 0;
  162.     public int recoilTimer = 0;
  163.    
  164.     public Vector3f lastPos = new Vector3f(0,0,0);
  165.     public boolean hugeBoat = false;
  166.     public boolean onDeck = false;
  167.     public double deckHeight = 0;
  168.     public int deckCheck = 0;
  169.     public int prevDeckCheck = 0;
  170.    
  171.     public boolean isMecha = false;
  172.     public boolean disabled = false;
  173.    
  174.     /** The angle of the propeller for the renderer */
  175.     public float propAngle = 0;
  176.     public float prevPropAngle = 0;
  177.    
  178.     public float rotorAngle = 0;
  179.     public float prevRotorAngle = 0;
  180.    
  181.     //Flares
  182.     public int flareDelay = 0;
  183.     public int ticksFlareUsing = 0;
  184.     public boolean varFlare;
  185.    
  186.     //IT1 stuff
  187.     public float drakonDoorAngle = 0;
  188.     public float drakonArmAngle = 0;
  189.     public float drakonRailAngle = 0;
  190.    
  191.     public float prevDrakonDoorAngle = 0;
  192.     public float prevDrakonArmAngle = 0;
  193.     public float prevDrakonRailAngle = 0;
  194.    
  195.     public boolean reloadingDrakon = false;
  196.     public boolean canFireIT1 = true;
  197.    
  198.     public int stage = 1;
  199.     public int reloadAnimTime = 0;
  200.    
  201.     public boolean toDeactivate = false;
  202.     public int timeTillDeactivate = 0;
  203.    
  204.     //
  205.     public boolean canFire = true;
  206.    
  207.    
  208.     @SideOnly(Side.CLIENT)
  209.     public EntityLivingBase camera;
  210.  
  211.     protected int invulnerableUnmountCount;
  212.  
  213.     private ItemStack[][] prevInventoryItems = new ItemStack[][]{ null, null };
  214.  
  215.     public Entity lastAtkEntity = null;
  216.    
  217.     //public ArrayList<EntityPlayer> playerIDs = new ArrayList<EntityPlayer>();
  218.  
  219.     public EntityDriveable(World world)
  220.     {
  221.         super(world);
  222.         axes = new RotatedAxes();
  223.         prevAxes = new RotatedAxes();
  224.         preventEntitySpawning = true;
  225.         setSize(1F, 1F);
  226.         yOffset = 6F / 16F;
  227.         ignoreFrustumCheck = true;
  228.         renderDistanceWeight = 200D;
  229.     }
  230.  
  231.  
  232.     public EntityDriveable(World world, DriveableType t, DriveableData d)
  233.     {
  234.         this(world);
  235.         driveableType = t.shortName;
  236.         driveableData = d; 
  237.     }
  238.  
  239.     protected void initType(DriveableType type, boolean clientSide)
  240.     {
  241.         seats = new EntitySeat[type.numPassengers + 1];
  242.         for(int i = 0; i < type.numPassengers + 1; i++)
  243.         {
  244.             if(!clientSide)
  245.             {
  246.                 seats[i] = new EntitySeat(worldObj, this, i);
  247.                 worldObj.spawnEntityInWorld(seats[i]);
  248.             }
  249.         }
  250.         wheels = new EntityWheel[type.wheelPositions.length];
  251.         for(int i = 0; i < wheels.length; i++)
  252.         {
  253.             if(!clientSide)
  254.             {
  255.                 wheels[i] = new EntityWheel(worldObj, this, i);
  256.                 worldObj.spawnEntityInWorld(wheels[i]);
  257.             }
  258.         }
  259.         stepHeight = type.wheelStepHeight;
  260.         yOffset = type.yOffset;
  261.  
  262.         emitterTimers = new int[type.emitters.size()];
  263.         for(int i = 0; i < type.emitters.size(); i++)
  264.         {
  265.             emitterTimers[i] = rand.nextInt(type.emitters.get(i).emitRate);
  266.         }
  267.  
  268.         getEntityData().setBoolean("CanMountEntity", type.canMountEntity);
  269.  
  270.         //Register Plane to Radar on Spawning
  271.         //if(type.onRadar == true)
  272.         //  RadarRegistry.register(this);
  273.  
  274.         for(int ps=0; ps < 2; ps ++)
  275.         {
  276.             EnumWeaponType weaponType = ps==0? type.primary: type.secondary;
  277.             if(weaponType == EnumWeaponType.GUN)
  278.             {
  279.                 weaponType = EnumWeaponType.NONE;
  280.             }
  281.             int istart = getInventoryStart(weaponType);
  282.             if(istart == driveableData.getAmmoInventoryStart())
  283.             {
  284.                 istart += type.numPassengerGunners;
  285.             }
  286.             final int isize  = getInventorySize(weaponType);
  287.             if(istart >= 0 || isize > 0)
  288.             {
  289.                 prevInventoryItems[ps] = new ItemStack[isize];
  290.                 for(int i=0; i<isize; i++)
  291.                 {
  292.                     prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i);
  293.                 }
  294.             }
  295.         }
  296.     }
  297.  
  298.     @Override
  299.     protected void writeEntityToNBT(NBTTagCompound tag)
  300.     {
  301.         driveableData.writeToNBT(tag);
  302.         tag.setString("Type", driveableType);
  303.         tag.setFloat("RotationYaw", axes.getYaw());
  304.         tag.setFloat("RotationPitch", axes.getPitch());
  305.         tag.setFloat("RotationRoll", axes.getRoll());
  306.         if(key != null)
  307.         tag.setString("key", key);
  308.     }
  309.  
  310.     @Override
  311.     protected void readEntityFromNBT(NBTTagCompound tag)
  312.     {
  313.         driveableType = tag.getString("Type");
  314.         driveableData = new DriveableData(tag);
  315.         initType(DriveableType.getDriveable(driveableType), false);
  316.  
  317.         prevRotationYaw = tag.getFloat("RotationYaw");
  318.         prevRotationPitch = tag.getFloat("RotationPitch");
  319.         prevRotationRoll = tag.getFloat("RotationRoll");
  320.         key = tag.getString("key");
  321.         axes = new RotatedAxes(prevRotationYaw, prevRotationPitch, prevRotationRoll);
  322.     }
  323.  
  324.     @Override
  325.     public void writeSpawnData(ByteBuf data)
  326.     {
  327.         ByteBufUtils.writeUTF8String(data, driveableType);
  328.  
  329.         NBTTagCompound tag = new NBTTagCompound();
  330.         driveableData.writeToNBT(tag);
  331.         ByteBufUtils.writeTag(data, tag);
  332.  
  333.         data.writeFloat(axes.getYaw());
  334.         data.writeFloat(axes.getPitch());
  335.         data.writeFloat(axes.getRoll());
  336.  
  337.         //Write damage
  338.         for(EnumDriveablePart ep : EnumDriveablePart.values())
  339.         {
  340.             DriveablePart part = getDriveableData().parts.get(ep);
  341.             data.writeShort((short)part.health);
  342.             data.writeBoolean(part.onFire);
  343.         }
  344.         if(key != null)
  345.         ByteBufUtils.writeUTF8String(data, key);
  346.     }
  347.  
  348.     @Override
  349.     public void readSpawnData(ByteBuf data)
  350.     {
  351.         try
  352.         {
  353.             driveableType = ByteBufUtils.readUTF8String(data);
  354.             driveableData = new DriveableData(ByteBufUtils.readTag(data));
  355.             initType(getDriveableType(), true);
  356.  
  357.             axes.setAngles(data.readFloat(), data.readFloat(), data.readFloat());
  358.             prevRotationYaw = axes.getYaw();
  359.             prevRotationPitch = axes.getPitch();
  360.             prevRotationRoll = axes.getRoll();
  361.  
  362.             //Read damage
  363.             for(EnumDriveablePart ep : EnumDriveablePart.values())
  364.             {
  365.                 DriveablePart part = getDriveableData().parts.get(ep);
  366.                 part.health = data.readShort();
  367.                 part.onFire = data.readBoolean();
  368.             }
  369.             key = ByteBufUtils.readUTF8String(data);
  370.  
  371.         }
  372.         catch(Exception e)
  373.         {
  374.             FlansMod.log("Failed to retreive plane type from server.");
  375.             super.setDead();
  376.             e.printStackTrace();
  377.         }
  378.  
  379.         camera = new EntityCamera(worldObj, this);
  380.         worldObj.spawnEntityInWorld(camera);
  381.     }
  382.     /**
  383.      * Called with the movement of the mouse. Used in controlling vehicles if need be.
  384.      * @param deltaY
  385.      * @param deltaX
  386.      * @return if mouse movement was handled.
  387.      */
  388.     @Override
  389.     public abstract void onMouseMoved(int deltaX, int deltaY);
  390.  
  391.     @Override
  392.     @SideOnly(Side.CLIENT)
  393.     public EntityLivingBase getCamera()
  394.     {
  395.         return camera;
  396.     }
  397.  
  398.     protected boolean canSit(int seat)
  399.     {
  400.         return getDriveableType().numPassengers >= seat && seats[seat].riddenByEntity == null;
  401.     }
  402.  
  403.     @Override
  404.     protected boolean canTriggerWalking()
  405.     {
  406.         return false;
  407.     }
  408.  
  409.     @Override
  410.     protected void entityInit()
  411.     {
  412.     }
  413.  
  414.  
  415.     @Override
  416.     public AxisAlignedBB getCollisionBox(Entity entity)
  417.     {
  418.         if(getDriveableType().collisionDamageEnable)
  419.         {
  420.             if(throttle > getDriveableType().collisionDamageThrottle)
  421.             {
  422.                 if(entity instanceof EntityLiving){
  423.                     entity.attackEntityFrom(DamageSource.generic, throttle*getDriveableType().collisionDamageTimes);
  424.                 }else if(entity instanceof EntityPlayer){
  425.                     entity.attackEntityFrom(DamageSource.generic, throttle*getDriveableType().collisionDamageTimes);
  426.                 }
  427.             }
  428.         }
  429.         return boundingBox;
  430.     }
  431.  
  432.     @Override
  433.     public AxisAlignedBB getBoundingBox()
  434.     {
  435.         return boundingBox;
  436.     }
  437.  
  438.     @Override
  439.     public boolean canBePushed()
  440.     {
  441.         return false;
  442.     }
  443.  
  444.     @Override
  445.     public double getMountedYOffset()
  446.     {
  447.         return -0.3D;
  448.     }
  449.  
  450.     @Override
  451.     /** Pass generic damage to the core */
  452.     public boolean attackEntityFrom(DamageSource damagesource, float i) {
  453.         if(worldObj.isRemote || isDead) return true;
  454. //      if(damagesource.getDamageType().indexOf("explosion") < 0)
  455.         {
  456.             if(isMountedEntity(damagesource.getEntity()))
  457.             {
  458.                 return false;
  459.             }
  460.         }
  461.  
  462. //      FlansMod.log(String.format("EntityDriveable.attackEntityFrom %.1f: %s : %s : %s", i,
  463. //              damagesource.getDamageType(), damagesource.getEntity(), damagesource.getSourceOfDamage()));
  464.  
  465.         boolean broken = attackPart(EnumDriveablePart.core, damagesource, i);
  466.         if(i > 0)
  467.         {
  468.             //checkParts();
  469.             checkPartsWhenAttacked();
  470.             //If it hit, send a damage update packet
  471.             FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension);
  472.         }
  473.         return true;
  474.     }
  475.  
  476.     public boolean isMountedEntity(Entity entity)
  477.     {
  478.         if(entity != null)
  479.         {
  480.             Entity entity2 = this.worldObj.getEntityByID(entity.getEntityId());
  481.             for(Entity seat :  seats)
  482.             {
  483.                 if(seat.riddenByEntity != null)
  484.                 {
  485.                     if( seat.riddenByEntity == entity || seat.riddenByEntity == entity2)
  486.                     {
  487.                         return true;
  488.                     }
  489.                 }
  490.             }
  491.         }
  492.  
  493.         return false;
  494.     }
  495.  
  496.     @Override
  497.     public void setDead()
  498.     {
  499.         super.setDead();
  500.  
  501.         //Unregister to Radar
  502.         //RadarRegistry.unregister(this);
  503.         if(worldObj.isRemote)
  504.             camera.setDead();
  505.  
  506.         for(EntitySeat seat : seats)
  507.             if(seat != null)
  508.                 seat.setDead();
  509.     }
  510.  
  511.     @Override
  512.     public void onCollideWithPlayer(EntityPlayer par1EntityPlayer)
  513.     {
  514.         return;
  515.     }
  516.  
  517.     @Override
  518.     public boolean canBeCollidedWith()
  519.     {
  520.         return true;
  521.     }
  522.  
  523.     @Override
  524.     public void applyEntityCollision(Entity entity)
  525.     {
  526.         //if(!isPartOfThis(entity))
  527.             //super.applyEntityCollision(entity);
  528.     }
  529.  
  530.     @Override
  531.     public void setPositionAndRotation2(double d, double d1, double d2, float f, float f1, int i)
  532.     {
  533.         if(ticksExisted > 1)
  534.             return;
  535.         if(riddenByEntity instanceof EntityPlayer && FlansMod.proxy.isThePlayer((EntityPlayer)riddenByEntity))
  536.         {
  537.         }
  538.         else
  539.         {
  540.             if(syncFromServer)
  541.             {
  542.                 serverPositionTransitionTicker = i + 5;
  543.             }
  544.             else
  545.             {
  546.                 double var10 = d - posX;
  547.                 double var12 = d1 - posY;
  548.                 double var14 = d2 - posZ;
  549.                 double var16 = var10 * var10 + var12 * var12 + var14 * var14;
  550.  
  551.                 if (var16 <= 1.0D)
  552.                 {
  553.                     return;
  554.                 }
  555.  
  556.                 serverPositionTransitionTicker = 3;
  557.             }
  558.             serverPosX = d;
  559.             serverPosY = d1;
  560.             serverPosZ = d2;
  561.             serverYaw = f;
  562.             serverPitch = f1;
  563.         }
  564.     }
  565.    
  566.     public void setIT1(boolean canFire, boolean reloading, int stag, int stageTime)
  567.     {  
  568.         if(worldObj.isRemote && ticksExisted % 5 == 0)
  569.         {
  570.             canFireIT1 = canFire;
  571.             reloadingDrakon = reloading;
  572.             stage = stag;
  573.             reloadAnimTime = stageTime;
  574.         }
  575.     }
  576.  
  577.     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)
  578.     {
  579.         if(worldObj.isRemote)
  580.         {
  581.             serverPosX = x;
  582.             serverPosY = y;
  583.             serverPosZ = z;
  584.             serverYaw = yaw;
  585.             serverPitch = pitch;
  586.             serverRoll = roll;
  587.             serverPositionTransitionTicker = 5;
  588.         }
  589.         else
  590.         {
  591.             setPosition(x, y, z);
  592.             prevRotationYaw = yaw;
  593.             prevRotationPitch = pitch;
  594.             prevRotationRoll = roll;
  595.             setRotation(yaw, pitch, roll);
  596.         }
  597.         //Set the motions regardless of side.
  598.         motionX = motX;
  599.         motionY = motY;
  600.         motionZ = motZ;
  601.         angularVelocity = new Vector3f(velYaw, velPitch, velRoll);
  602.         throttle = throt;
  603.     }
  604.  
  605.  
  606.     @Override
  607.     public void setVelocity(double d, double d1, double d2)
  608.     {
  609.         motionX = d;
  610.         motionY = d1;
  611.         motionZ = d2;
  612.     }
  613.  
  614.     @Override
  615.     public boolean pressKey(int key, EntityPlayer player)
  616.     {
  617.         if(!worldObj.isRemote && key == 9 && getDriveableType().modePrimary == EnumFireMode.SEMIAUTO) //Primary
  618.         {
  619.             shoot(false);
  620.             return true;
  621.         }
  622.         else if(!worldObj.isRemote && key == 8 && getDriveableType().modeSecondary == EnumFireMode.SEMIAUTO) //Secondary
  623.         {
  624.             shoot(true);
  625.             return true;
  626.         }
  627.         return false;
  628.     }
  629.  
  630.     @Override
  631.     public void updateKeyHeldState(int key, boolean held)
  632.     {
  633.         if(worldObj.isRemote)
  634.         {
  635.             FlansMod.getPacketHandler().sendToServer(new PacketDriveableKeyHeld(key, held));
  636.            
  637.             if(key == 2){
  638.                 leftTurnHeld = true;
  639.                 rightTurnHeld = false;
  640.             } else if (key == 3){
  641.                 rightTurnHeld = true;
  642.                 leftTurnHeld = false;
  643.             } else {
  644.                 leftTurnHeld = false;
  645.                 rightTurnHeld = false;
  646.             }
  647.         }
  648.         switch(key)
  649.         {
  650.         case 9 : leftMouseHeld = held;
  651.         break;
  652.         case 8 : rightMouseHeld = held; break;
  653.         }
  654.     }
  655.  
  656.     /** Shoot method called by pressing / holding shoot buttons */
  657.     public void shoot(boolean secondary)
  658.     {
  659.         DriveableType type = getDriveableType();
  660.         if(seats[0] == null)
  661.             return;
  662.        
  663.         if(type.IT1 && !canFireIT1 && type.weaponType(secondary) == EnumWeaponType.MISSILE) return;
  664.        
  665.         if(!canFire) return;
  666.        
  667.         //Check shoot delay
  668.         if(getShootDelay(secondary) <= 0)
  669.         {
  670.                 //We can shoot, so grab the available shoot points and the weaponType
  671.                 ArrayList<ShootPoint> shootPoints = type.shootPoints(secondary);
  672.                 EnumWeaponType weaponType = type.weaponType(secondary);
  673.                 //If there are no shoot points, return
  674.                 if(shootPoints.size() == 0)
  675.                     return;
  676.                 //For alternating guns, move on to the next one
  677.                 int currentGun = getCurrentGun(secondary);
  678.                 if(type.alternate(secondary))
  679.                 {
  680.                     currentGun = (currentGun + 1) % shootPoints.size();
  681.                     setCurrentGun(currentGun, secondary);
  682.                     shootEach(type, shootPoints.get(currentGun), currentGun, secondary, weaponType);
  683.                 }
  684.                 else for(int i = 0; i < shootPoints.size(); i++)
  685.                     shootEach(type, shootPoints.get(i), i, secondary, weaponType);
  686.         }
  687.     }
  688.  
  689.     private boolean driverIsCreative()
  690.     {
  691.         return seats != null && seats[0] != null && seats[0].riddenByEntity instanceof EntityPlayer && ((EntityPlayer)seats[0].riddenByEntity).capabilities.isCreativeMode;
  692.     }
  693.  
  694.     public void spawnParticle(ArrayList<ShootParticle> list, ShootPoint shootPoint, Vector3f v)
  695.     {
  696.         for(ShootParticle s : list)
  697.         {
  698.             float bkx = shootPoint.rootPos.position.x;
  699.             float bky = shootPoint.rootPos.position.y;
  700.             float bkz = shootPoint.rootPos.position.z;
  701.            
  702.             Vector3f velocity = new Vector3f(s.x, s.y, s.z);
  703.             Vector3f vv = lastPos;
  704.  
  705.             //if(shootPoint.rootPos.part == EnumDriveablePart.turret){
  706.             velocity = getDirection(shootPoint, velocity);
  707.             //}
  708.            
  709.             //Vector3f v = getFiringPosition(shootPoint);
  710.  
  711.             if(shootPoint.rootPos.part == EnumDriveablePart.core){
  712.                 Vector3f v2 = axes.findLocalVectorGlobally(shootPoint.rootPos.position);
  713.                 Vector3f v3 = rotate(seats[0].looking.findLocalVectorGlobally(shootPoint.offPos));             
  714.                 Vector3f.add(v2, v3, v);
  715.             }
  716.  
  717.             FlansMod.getPacketHandler().sendToAllAround(
  718.                     new PacketParticle(s.name, posX+v.x, posY+v.y, posZ+v.z, velocity.x,velocity.y,velocity.z),
  719.                     posX+v.x, posY+v.y, posZ+v.z, 150, dimension);
  720.  
  721.             shootPoint.rootPos.position.x = bkx;
  722.             shootPoint.rootPos.position.y = bky;
  723.             shootPoint.rootPos.position.z = bkz;
  724.         }
  725.     }
  726.  
  727.  
  728.     private void shootEach(DriveableType type, ShootPoint shootPoint, int currentGun, boolean secondary, EnumWeaponType weaponType)
  729.     {
  730.         //Rotate the gun vector to global axes
  731.         Vector3f gunVec = getFiringPosition(shootPoint);
  732.         Vector3f lookVector = getLookVector(shootPoint);
  733.        
  734.         if(!secondary && type.fixedPrimaryFire){
  735.             lookVector = axes.findLocalVectorGlobally(type.primaryFireAngle);
  736.             if(shootPoint.rootPos.part == EnumDriveablePart.turret){
  737.                 lookVector = getPositionOnTurret(type.primaryFireAngle, false);
  738.             }
  739.             if(shootPoint.rootPos.part == EnumDriveablePart.barrel){
  740.                 lookVector = getPositionOnTurret(type.primaryFireAngle, true);
  741.             }
  742.         }
  743.        
  744.         if(weaponType == EnumWeaponType.SHELL)
  745.             isRecoil = true;
  746.        
  747.         if(!isPartIntact(shootPoint.rootPos.part)) return;
  748.    
  749.         if(disabled) return;
  750.        
  751.         //If its a pilot gun, then it is using a gun type, so do the following
  752.         if(shootPoint.rootPos instanceof PilotGun)
  753.         {
  754.             PilotGun pilotGun = (PilotGun)shootPoint.rootPos;
  755.             //Get the gun from the plane type and the ammo from the data
  756.             GunType gunType = pilotGun.type;
  757.             float shellSpeed = gunType.bulletSpeed;
  758.             if(type.rangingGun)
  759.             shellSpeed = type.bulletSpeed;
  760.             ItemStack bulletItemStack = driveableData.ammo[getDriveableType().numPassengerGunners + currentGun];
  761.             //Check that neither is null and that the bullet item is actually a bullet
  762.             if(gunType != null && bulletItemStack != null && bulletItemStack.getItem() instanceof ItemShootable && TeamsManager.bulletsEnabled)
  763.             {
  764.                 ShootableType bullet = ((ItemShootable)bulletItemStack.getItem()).type;
  765.                 if(gunType.isAmmo(bullet))
  766.                 {
  767.                     //spawnParticle(gunType, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY,V (float)posZ), null));
  768.  
  769.                     spawnParticle(type.shootParticle(secondary), shootPoint, gunVec);
  770.                     //Spawn a new bullet item
  771.                     worldObj.spawnEntityInWorld(((ItemShootable)bulletItemStack.getItem()).getEntity(worldObj, Vector3f.add(new Vector3f(posX, posY, posZ), gunVec, null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, gunType.bulletSpread / 2, gunType.damage, shellSpeed,bulletItemStack.getItemDamage(), type));
  772.                     //Play the shoot sound
  773.                     PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false);
  774.                     //Get the bullet item damage and increment it
  775.                     int damage = bulletItemStack.getItemDamage();
  776.                     bulletItemStack.setItemDamage(damage + 1);
  777.                     //If the bullet item is completely damaged (empty)
  778.                     if(damage + 1 == bulletItemStack.getMaxDamage())
  779.                     {
  780.                         //Set the damage to 0 and consume one ammo item (unless in creative)
  781.                         bulletItemStack.setItemDamage(0);
  782.                         if(!driverIsCreative())
  783.                         {
  784.                             bulletItemStack.stackSize--;
  785.                             if(bulletItemStack.stackSize <= 0)
  786.                             {
  787.                                 onWeaponInventoryChanged(secondary);
  788.                                 bulletItemStack = null;
  789.                             }
  790.                             driveableData.setInventorySlotContents(getDriveableType().numPassengerGunners + currentGun, bulletItemStack);
  791.                         }
  792.                     }
  793.                     //Reset the shoot delay
  794.                     setShootDelay(type.shootDelay(secondary), secondary);
  795.                 }
  796.             }
  797.         }
  798.         else //One of the other modes
  799.         {
  800.  
  801.  
  802.             switch(weaponType)
  803.             {
  804.             case BOMB :
  805.             {
  806.                 if(TeamsManager.bombsEnabled)
  807.                 {
  808.                     int slot = -1;
  809.                     for(int i = driveableData.getBombInventoryStart(); i < driveableData.getBombInventoryStart() + type.numBombSlots; i++)
  810.                     {
  811.                         ItemStack bomb = driveableData.getStackInSlot(i);
  812.                         if(bomb != null && bomb.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)bomb.getItem()).type, weaponType))
  813.                         {
  814.                             slot = i;
  815.                         }
  816.                     }
  817.  
  818.                     if(slot != -1)
  819.                     {
  820.                         int spread = 0;
  821.                         int damageMultiplier = 1;
  822.                         float shellSpeed = 0F;
  823.  
  824.                         ItemStack bulletStack = driveableData.getStackInSlot(slot);
  825.                         ItemBullet bulletItem = (ItemBullet)bulletStack.getItem();
  826.                         if(shootPoint.rootPos instanceof PilotGun)
  827.                         {
  828.                             PilotGun pilotGun = (PilotGun)shootPoint.rootPos;
  829.                             //Get the gun from the plane type and the ammo from the data
  830.                             GunType gunType = pilotGun.type;
  831.                         }
  832.  
  833.                         EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vec3.createVectorHelper(gunVec.x + posX, gunVec.y + posY, gunVec.z + posZ), axes.getYaw(), axes.getPitch(), motionX, motionY, motionZ, (EntityLivingBase)seats[0].riddenByEntity, damageMultiplier, driveableData.getStackInSlot(slot).getItemDamage(), type);
  834.                         worldObj.spawnEntityInWorld(bulletEntity);
  835.  
  836.                         spawnParticle(type.shootParticle(secondary), shootPoint, gunVec);
  837.                        
  838.  
  839.                         if(type.shootSound(secondary) != null)
  840.                             PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false);
  841.                         if(!driverIsCreative())
  842.                         {
  843.                             bulletStack.setItemDamage(bulletStack.getItemDamage() + 1);
  844.                             if(bulletStack.getItemDamage() == bulletStack.getMaxDamage())
  845.                             {
  846.                                 bulletStack.setItemDamage(0);
  847.                                 bulletStack.stackSize--;
  848.                                 if(bulletStack.stackSize == 0)
  849.                                 {
  850.                                     onWeaponInventoryChanged(secondary);
  851.                                     bulletStack = null;
  852.                                 }
  853.                             }
  854.                             driveableData.setInventorySlotContents(slot, bulletStack);
  855.                         }
  856.                         setShootDelay(type.shootDelay(secondary), secondary);
  857.                     }
  858.                 }
  859.                 break;
  860.             }
  861.             case MISSILE : //These two are actually almost identical
  862.             case SHELL :
  863.             {
  864.                 //int numnum = driveableData.getMissileInventoryStart();
  865.                 /*ItemStack AmmoPlaced = driveableData.getStackInSlot(1);
  866.                 if(AmmoPlaced == null && type.enableReloadTime){
  867.                     isAmmoPlaced = false;
  868.                     break;
  869.                 }
  870.                 isAmmoPlaced = true;
  871.                 setShootDelay(type.shootDelay(secondary), secondary);*/
  872.                 tryRecoil();
  873.  
  874.                 if(TeamsManager.shellsEnabled)
  875.                 {
  876.                     int slot = -1;
  877.                     for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++)
  878.                     {
  879.                         ItemStack shell = driveableData.getStackInSlot(i);
  880.                         if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)shell.getItem()).type, weaponType))
  881.                         {
  882.                             slot = i;
  883.                         }
  884.                     }
  885.  
  886.                     if(slot != -1)
  887.                     {
  888.                         //int spread = 0;
  889.                         int damageMultiplier = 1;
  890.                         //float shellSpeed = 3F;
  891.                         float spread = type.bulletSpread;
  892.                         float shellSpeed = type.bulletSpeed;
  893.                         ItemStack bulletStack = driveableData.getStackInSlot(slot);
  894.                         ItemBullet bulletItem = (ItemBullet)bulletStack.getItem();
  895.                         EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f(posX, posY, posZ), null), lookVector, (EntityLivingBase)seats[0].riddenByEntity , spread, damageMultiplier, shellSpeed, driveableData.getStackInSlot(slot).getItemDamage(), type);
  896.                         //EntityShootable bulletEntity = bulletItem.getEntity(worldObj, Vector3f.add(gunVec, new Vector3f((float)posX, (float)posY, (float)posZ), null), lookVector, (EntityLivingBase)seats[0].riddenByEntity, spread, damageMultiplier, shellSpeed, bulletStack.getItemDamage(), type);
  897.                         //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);
  898.                         worldObj.spawnEntityInWorld(bulletEntity); //SHELL
  899.                         spawnParticle(type.shootParticle(secondary), shootPoint, gunVec);
  900.                         isRecoil = true;
  901.  
  902.                         if(type.shootSound(secondary) != null)
  903.                             PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension, type.shootSound(secondary), false);
  904.                         if(!driverIsCreative())
  905.                         {
  906.                             bulletStack.setItemDamage(bulletStack.getItemDamage() + 1);
  907.                             if(bulletStack.getItemDamage() == bulletStack.getMaxDamage())
  908.                             {
  909.                                 bulletStack.setItemDamage(0);
  910.                                 bulletStack.stackSize--;
  911.                                 if(bulletStack.stackSize == 0)
  912.                                 {
  913.                                     onWeaponInventoryChanged(secondary);
  914.                                     bulletStack = null;
  915.                                 }
  916.                             }
  917.                             driveableData.setInventorySlotContents(slot, bulletStack);
  918.                         }
  919.                         setShootDelay(type.shootDelay(secondary), secondary);
  920.                         canFireIT1 = false;
  921.                     }
  922.                 }
  923.                 break;
  924.             }
  925.             case GUN: //Handled above
  926.                 break;
  927.             case MINE:
  928.                 break;
  929.             case NONE:
  930.                 break;
  931.             }
  932.         }
  933.     }
  934.  
  935.     public Vector3f getOrigin(ShootPoint dp)
  936.     {
  937.         //Rotate the gun vector to global axes
  938.         Vector3f localGunVec = new Vector3f(dp.rootPos.position);
  939.  
  940.         if(dp.rootPos.part == EnumDriveablePart.turret)
  941.         {
  942.             //Untranslate by the turret origin, to get the rotation about the right point
  943.             Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec);
  944.             //Rotate by the turret angles
  945.             localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec);
  946.             //Translate by the turret origin
  947.             Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec);
  948.         }
  949.  
  950.         return rotate(localGunVec);
  951.     }
  952.    
  953.     public Vector3f getPositionOnTurret(Vector3f vecIn, boolean barrel)
  954.     {
  955.         Vector3f transform = vecIn;    
  956.         RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0);
  957.         if(barrel) yawOnlyLooking = seats[0].looking;
  958.        
  959.         //Calculate the root of the gun
  960.         //Untranslate by the turret origin, to get the rotation about the right point
  961.         Vector3f.sub(transform, getDriveableType().turretOrigin, transform);
  962.         //Rotate by the turret angles
  963.         transform = yawOnlyLooking.findLocalVectorGlobally(transform);
  964.         //Translate by the turret origin
  965.         Vector3f.add(transform, getDriveableType().turretOrigin, transform);
  966.         Vector3f turretOriginOffset = new Vector3f(getDriveableType().turretOriginOffset);
  967.         turretOriginOffset = yawOnlyLooking.findLocalVectorGloballyYaw(turretOriginOffset);
  968.         Vector3f.add(transform, turretOriginOffset, transform);
  969.        
  970.         return rotate(transform);
  971.     }
  972.    
  973.     public Vector3f getDirection(ShootPoint dp, Vector3f vIn)
  974.     {
  975.         //Rotate the gun vector to global axes
  976.         Vector3f localGunVec = new Vector3f(vIn);
  977.  
  978.         //if(dp.rootPos.part == EnumDriveablePart.turret)
  979.         //{
  980.             //localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec);
  981.         //}
  982.        
  983.         localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec);
  984.  
  985.         return rotate(localGunVec);
  986.     }
  987.  
  988.     public Vector3f getLookVector(ShootPoint dp)
  989.     {
  990.         return axes.getXAxis();
  991.     }
  992.    
  993.     public Vector3f getFiringPosition(ShootPoint dp)
  994.     {
  995.         Vector3f rootVector = new Vector3f(dp.rootPos.position);
  996.         Vector3f offsetVector = new Vector3f(dp.offPos);
  997.         Vector3f localGunVec = new Vector3f(dp.rootPos.position);
  998.  
  999.         if(dp.rootPos.part == EnumDriveablePart.turret)
  1000.         {
  1001.             if(offsetVector.x == 0 && offsetVector.y == 0 && offsetVector.z == 0)
  1002.             {
  1003.             //Untranslate by the turret origin, to get the rotation about the right point
  1004.             Vector3f.sub(localGunVec, getDriveableType().turretOrigin, localGunVec);
  1005.             //Rotate by the turret angles
  1006.             localGunVec = seats[0].looking.findLocalVectorGlobally(localGunVec);
  1007.             //Translate by the turret origin
  1008.             Vector3f.add(localGunVec, getDriveableType().turretOrigin, localGunVec);
  1009.             } else {
  1010.             RotatedAxes yawOnlyLooking = new RotatedAxes(seats[0].looking.getYaw(), 0, 0);
  1011.                
  1012.             //Calculate the root of the gun
  1013.             //Untranslate by the turret origin, to get the rotation about the right point
  1014.             Vector3f.sub(rootVector, getDriveableType().turretOrigin, rootVector);
  1015.             //Rotate by the turret angles
  1016.             rootVector = yawOnlyLooking.findLocalVectorGlobally(rootVector);
  1017.             //Translate by the turret origin
  1018.             Vector3f.add(rootVector, getDriveableType().turretOrigin, rootVector);                 
  1019.                    
  1020.             //Calculate the tip of the gun
  1021.             //Untranslate by the turret origin, to get the rotation about the right point
  1022.             Vector3f.sub(offsetVector, getDriveableType().turretOrigin, offsetVector);
  1023.             //Rotate by the turret angles
  1024.             offsetVector = seats[0].looking.findLocalVectorGlobally(offsetVector);
  1025.             //Translate by the turret origin
  1026.                
  1027.             Vector3f.add(rootVector, offsetVector, localGunVec);
  1028.             }
  1029.         }
  1030.  
  1031.         return rotate(localGunVec);
  1032.     }
  1033.  
  1034.     public void correctWheelPos()
  1035.     {
  1036.         if(this.ticksExisted % (10*20) == 0)
  1037.         {
  1038.             for(EntityWheel wheel : wheels)
  1039.             {
  1040.                 if(wheel == null)   continue;
  1041.  
  1042.                 Vector3f target = axes.findLocalVectorGlobally(getDriveableType().wheelPositions[wheel.ID].position);
  1043.                 target.x += posX;
  1044.                 target.y += posY;
  1045.                 target.z += posZ;
  1046.  
  1047.                 int tf = 1;
  1048.                 int cf = 1;
  1049.                 int range = 5;
  1050.  
  1051.                 if(MathHelper.abs(target.x - (float)wheel.posX) > range)
  1052.                 {
  1053.                     wheel.posX = (target.x*tf + (float)wheel.posX*cf) / (tf+cf);
  1054.                 }
  1055.                 if(MathHelper.abs(target.y - (float)wheel.posY) > range)
  1056.                 {
  1057.                     wheel.posY = (target.y*tf + (float)wheel.posY*cf) / (tf+cf);
  1058.                 }
  1059.                 if(MathHelper.abs(target.z - (float)wheel.posZ) > range)
  1060.                 {
  1061.                     wheel.posZ = (target.z*tf + (float)wheel.posZ*cf) / (tf+cf);
  1062.                 }
  1063.             }
  1064.         }
  1065.     }
  1066.  
  1067.     @Override
  1068.     public void onUpdate()
  1069.     {
  1070.         super.onUpdate();
  1071.         //playerIDs.clear();
  1072.         DriveableType type = getDriveableType();
  1073.         DriveableData data = getDriveableData();
  1074.         //if(type.fancyCollision)
  1075.         //checkCollsionBox();
  1076.         hugeBoat = (getDriveableType().floatOnWater && getDriveableType().wheelStepHeight == 0);
  1077.         //hugeBoat = true;
  1078.        
  1079.         if(hugeBoat){
  1080.         for(int i = 0; i < worldObj.loadedEntityList.size(); i++)
  1081.         {
  1082.             Object obj = worldObj.loadedEntityList.get(i);
  1083.             if(obj instanceof EntityPlayer && !isPartOfThis((Entity)obj))
  1084.             {
  1085.             moveRiders((Entity)obj);
  1086.             }
  1087.            
  1088.             if(obj instanceof EntityWheel && !isPartOfThis((Entity)obj) && getDistanceToEntity((Entity)obj) <= getDriveableType().bulletDetectionRadius)
  1089.             {
  1090.             //moveRiders((Entity)obj);
  1091.             }
  1092.            
  1093.             if(obj instanceof EntityDriveable && !isPartOfThis((Entity)obj) && getDistanceToEntity((Entity)obj) <= getDriveableType().bulletDetectionRadius)
  1094.             {
  1095.             //moveRiders((Entity)obj);
  1096.             }
  1097.         }
  1098.         }
  1099.        
  1100.        
  1101.         if(deckCheck != prevDeckCheck)
  1102.             onDeck = true;
  1103.         else onDeck = false;
  1104.  
  1105.        
  1106.         //Aesthetics
  1107.         if(type.IT1 && !disabled)
  1108.         {
  1109.             boolean fireButtonheld = false;
  1110.             if(type.weaponType(false) == EnumWeaponType.MISSILE) fireButtonheld = leftMouseHeld;
  1111.             if(type.weaponType(true) == EnumWeaponType.MISSILE) fireButtonheld = rightMouseHeld;
  1112.  
  1113.             prevDrakonDoorAngle = drakonDoorAngle;
  1114.             prevDrakonArmAngle = drakonArmAngle;
  1115.             prevDrakonRailAngle = drakonRailAngle;
  1116.             if(canFireIT1) reloadingDrakon = false;
  1117.             if(stage == 0) stage = 1;
  1118.            
  1119.             if(stage == 8 && fireButtonheld){stage = 1; timeTillDeactivate = 5; toDeactivate = true;}
  1120.             if(timeTillDeactivate <= 0 && toDeactivate) {canFireIT1 = false; toDeactivate = false;}
  1121.            
  1122.             if(reloadAnimTime <= 0)
  1123.             IT1Reload();
  1124.            
  1125.             reloadAnimTime--;
  1126.             timeTillDeactivate--;
  1127.         }
  1128.        
  1129.         //Aesthetics
  1130.         prevPropAngle = propAngle;
  1131.         prevRotorAngle = rotorAngle;
  1132.         if(throttle != 0)
  1133.         {
  1134.             propAngle += (Math.pow(throttle, 0.4))*1.5;
  1135.             rotorAngle += throttle/7F;
  1136.         }
  1137.        
  1138.        
  1139.        
  1140.         //Gun recoil
  1141.         if(leftMouseHeld && !disabled){
  1142.             tryRecoil();
  1143.             setRecoilTimer();
  1144.         }
  1145.         lastRecoilPos = recoilPos;
  1146.        
  1147.         if(recoilPos > 180-(180/type.recoilTime))
  1148.         {
  1149.             recoilPos = 0;
  1150.             isRecoil = false;
  1151.         }
  1152.        
  1153.         if(isRecoil)
  1154.         recoilPos = recoilPos + (180/type.recoilTime);
  1155.        
  1156.         if(recoilTimer >= 0)
  1157.         recoilTimer--;
  1158.  
  1159.         checkInventoryChanged();
  1160.        
  1161.         if(worldObj.isAnyLiquid(this.boundingBox) && !hugeBoat)
  1162.         {
  1163.             if(throttle >= type.maxThrottleInWater)
  1164.             {
  1165.                 throttle = type.maxThrottleInWater;
  1166.             }
  1167.            
  1168.             if(throttle <= -type.maxThrottleInWater)
  1169.             {
  1170.                 throttle = -type.maxThrottleInWater;
  1171.             }
  1172.            
  1173.             if(worldObj.isAnyLiquid(this.boundingBox.copy().offset(0, type.maxDepth, 0)))
  1174.             {
  1175.                 throttle = 0;
  1176.                 //this.driveableData.parts.get(EnumDriveablePart.core).health -= 1;
  1177.                 disabled = true;
  1178.             }
  1179.         } else disabled = false;
  1180.  
  1181.        
  1182.         if(type.lockOnToLivings || type.lockOnToMechas || type.lockOnToPlanes || type.lockOnToPlayers || type.lockOnToVehicles)
  1183.         {
  1184.             if(!worldObj.isRemote && this.seats.length > 0 && lockOnSoundDelay <= 0)
  1185.             {
  1186.                 if(this.seats[0]!=null && this.seats[0].riddenByEntity instanceof EntityPlayer)
  1187.                 {
  1188.                     int currentGun = getCurrentGun(false);
  1189.                     Vector3f playerVec = getOrigin(type.shootPoints(false).get(currentGun));
  1190.  
  1191.                     for (Object obj : worldObj.loadedEntityList)
  1192.                     {
  1193.                         Entity entity = (Entity) obj;
  1194.                         if( (type.lockOnToMechas   && entity instanceof EntityMecha)   ||
  1195.                             (type.lockOnToVehicles && entity instanceof EntityVehicle) ||
  1196.                             (type.lockOnToPlanes   && entity instanceof EntityPlane)   ||
  1197.                             (type.lockOnToPlayers  && entity instanceof EntityPlayer)  ||
  1198.                             (type.lockOnToLivings  && entity instanceof EntityLivingBase))
  1199.                         {
  1200.                             double dXYZ = getDistanceToEntity(entity);
  1201.                             if(getDistanceSqToEntity(entity) < type.maxRangeLockOn*type.maxRangeLockOn)
  1202.                             {
  1203.                                 Vector3f relPosVec = new Vector3f(entity.posX - this.posX, entity.posY - this.posY, entity.posZ - this.posZ);
  1204.                                 float angle = Math.abs(Vector3f.angle(playerVec, relPosVec));
  1205.                                 if(angle < Math.toRadians(type.canLockOnAngle))
  1206.                                 {
  1207.                                     PacketPlaySound.sendSoundPacket(seats[0].posX, seats[0].posY, seats[0].posZ, 10, dimension, type.lockOnSound, false);
  1208.                                     if(entity instanceof EntityDriveable)
  1209.                                         PacketPlaySound.sendSoundPacket(entity.posX, entity.posY, entity.posZ, ((EntityDriveable) entity).getDriveableType().lockedOnSoundRange, entity.dimension, ((EntityDriveable) entity).getDriveableType().lockingOnSound, false);
  1210.                                     lockOnSoundDelay = type.lockOnSoundTime;
  1211.                                     break;
  1212.                                 }
  1213.                             }
  1214.                         }
  1215.                     }
  1216.                 }
  1217.             }
  1218.         }
  1219.         if(lockOnSoundDelay > 0)
  1220.             lockOnSoundDelay--;
  1221.  
  1222.  
  1223.         if(this.ridingEntity != null)
  1224.         {
  1225.             invulnerableUnmountCount = 20 * 4;
  1226.         }
  1227.         else if(invulnerableUnmountCount > 0)
  1228.         {
  1229.             invulnerableUnmountCount--;
  1230.         }
  1231.  
  1232.         if(!worldObj.isRemote)
  1233.         {
  1234.             for(int i = 0; i < getDriveableType().numPassengers + 1; i++)
  1235.             {
  1236.                 if(seats[i] == null || !seats[i].addedToChunk)
  1237.                 {
  1238.                     seats[i] = new EntitySeat(worldObj, this, i);
  1239.                     worldObj.spawnEntityInWorld(seats[i]);
  1240.                 }
  1241.             }
  1242.             for(int i = 0; i < type.wheelPositions.length; i++)
  1243.             {
  1244.                 if(wheels[i] == null || !wheels[i].addedToChunk)
  1245.                 {
  1246.                     wheels[i] = new EntityWheel(worldObj, this, i);
  1247.                     worldObj.spawnEntityInWorld(wheels[i]);
  1248.                 }
  1249.             }
  1250.         }
  1251.        
  1252.  
  1253.  
  1254.         if(isShowedPosition && tickCount > 0)
  1255.         {
  1256.             tickCount--;
  1257.         }
  1258.         if(tickCount <= 0)
  1259.         {
  1260.             isShowedPosition = false;
  1261.         }
  1262.  
  1263.         //Harvest stuff
  1264.         //Aesthetics
  1265.         if(hasEnoughFuel())
  1266.         {
  1267.             harvesterAngle += throttle / 5F;
  1268.         }
  1269.         //Actual harvesting
  1270.         if(type.harvestBlocks && type.harvestBoxSize != null && type.harvestBoxPos != null && TeamsManager.driveablesBreakBlocks)
  1271.         {
  1272.             Vector3f size = new Vector3f(type.harvestBoxSize.x/16F, type.harvestBoxSize.y/16F, type.harvestBoxSize.z/16F);
  1273.             Vector3f pos = new Vector3f(type.harvestBoxPos.x/16F, type.harvestBoxPos.y/16F, type.harvestBoxPos.z/16F);
  1274.             for(float x = pos.x; x <= pos.x + size.x; x++)
  1275.             {
  1276.                 for(float y = pos.y; y <= pos.y + size.y; y++)
  1277.                 {
  1278.                     for(float z = pos.z; z <= pos.z + size.z; z++)
  1279.                     {
  1280.                         Vector3f v = axes.findLocalVectorGlobally(new Vector3f(x, y, z));
  1281.  
  1282.                         int blockX = (int)Math.round(posX + v.x);
  1283.                         int blockY = (int)Math.round(posY + v.y);
  1284.                         int blockZ = (int)Math.round(posZ + v.z);
  1285.                         Block block = worldObj.getBlock(blockX, blockY, blockZ);
  1286.  
  1287.                         if(type.materialsHarvested.contains(block.getMaterial()) && block.getBlockHardness(worldObj, blockX, blockY, blockZ) >= 0F)
  1288.                         {
  1289.                             if(type.collectHarvest){
  1290.                             //Add the itemstack to mecha inventory
  1291.                             ArrayList<ItemStack> stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0);
  1292.                             for(int i = 0; i < stacks.size(); i++)
  1293.                             {
  1294.                                 ItemStack stack = stacks.get(i);
  1295.                                 FlansMod.log("");
  1296.                                 if(!InventoryHelper.addItemStackToInventory(driveableData, stack, driverIsCreative()) && !worldObj.isRemote && worldObj.getGameRules().getGameRuleBooleanValue("doTileDrops"))
  1297.                                 {
  1298.                                     worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack));
  1299.                                 }
  1300.                             }
  1301.                             } else if(type.dropHarvest){
  1302.                                 ArrayList<ItemStack> stacks = block.getDrops(worldObj, blockX, blockY, blockZ, worldObj.getBlockMetadata(blockX, blockY, blockZ), 0);
  1303.                                 for(int i = 0; i < stacks.size(); i++)
  1304.                                 {
  1305.                                     ItemStack stack = stacks.get(i);
  1306.                                     worldObj.spawnEntityInWorld(new EntityItem(worldObj, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, stack));
  1307.                                 }
  1308.                             }
  1309.                             //Destroy block
  1310.                             worldObj.func_147480_a(blockX, blockY, blockZ, false);
  1311.                         }
  1312.                     }
  1313.                 }
  1314.             }
  1315.         }
  1316.  
  1317.         /*if(this.isLockedOn && soundTime <= 0 && !this.worldObj.isRemote)
  1318.         {
  1319.             PacketPlaySound.sendSoundPacket(posX,posY,posZ, 5, dimension, type.lockedOnSound, false);
  1320.             soundTime = type.soundTime;
  1321.         }*/
  1322.  
  1323.         for(DriveablePart part : getDriveableData().parts.values())
  1324.         {
  1325.             if(part.box != null)
  1326.             {
  1327.  
  1328.                 part.update(this);
  1329.                 //Client side particles
  1330.                 if(worldObj.isRemote)
  1331.                 {
  1332.                     if(part.onFire)
  1333.                     {
  1334.                         //Pick a random position within the bounding box and spawn a flame there
  1335.                         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));
  1336.                         worldObj.spawnParticle("flame", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0);
  1337.                     }
  1338.                     if(part.health > 0 && part.health < part.maxHealth / 2)
  1339.                     {
  1340.                         //Pick a random position within the bounding box and spawn a flame there
  1341.                         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));
  1342.                         worldObj.spawnParticle(part.health < part.maxHealth / 4 ? "largesmoke" : "smoke", posX + pos.x, posY + pos.y, posZ + pos.z, 0, 0, 0);
  1343.                     }
  1344.                 }
  1345.                 //Server side fire handling
  1346.                 if(part.onFire)
  1347.                 {
  1348.                     //Rain can put out fire
  1349.                     if(worldObj.isRaining() && rand.nextInt(40) == 0)
  1350.                         part.onFire = false;
  1351.                     //Also water blocks
  1352.                     //Get the centre point of the part
  1353.                     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));
  1354.                     if(worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.water)
  1355.                     {
  1356.                         part.onFire = false;
  1357.                     }
  1358.                 }
  1359.                 else
  1360.                 {
  1361.                     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));
  1362.                     if(worldObj.getBlock(MathHelper.floor_double(posX + pos.x), MathHelper.floor_double(posY + pos.y), MathHelper.floor_double(posZ + pos.z)).getMaterial() == Material.lava)
  1363.                     {
  1364.                         part.onFire = true;
  1365.                     }
  1366.                 }
  1367.             }
  1368.         }
  1369.  
  1370.         for(int i = 0; i < type.emitters.size(); i++)
  1371.         {
  1372.             ParticleEmitter emitter = type.emitters.get(i);
  1373.             emitterTimers[i]--;
  1374.             boolean canEmit = false;
  1375.             boolean inThrottle = false;
  1376.             DriveablePart part = getDriveableData().parts.get(EnumDriveablePart.getPart(emitter.part));
  1377.             float healthPercentage = (float)part.health / (float)part.maxHealth;
  1378.             if(isPartIntact(EnumDriveablePart.getPart(emitter.part)) && healthPercentage >= emitter.minHealth && healthPercentage <= emitter.maxHealth){
  1379.                 canEmit = true;
  1380.             } else {
  1381.                 canEmit = false;
  1382.             }
  1383.            
  1384.             if((throttle >= emitter.minThrottle && throttle <= emitter.maxThrottle))
  1385.                 inThrottle = true;
  1386.             if(isMecha)
  1387.                 inThrottle = true;
  1388.            
  1389.             if(emitterTimers[i] <= 0)
  1390.             {
  1391.                 if(inThrottle && canEmit){
  1392.                 //Emit!
  1393.                 Vector3f velocity = new Vector3f(0,0,0);;
  1394.                 Vector3f pos = new Vector3f(0,0,0);
  1395.                 if(seats != null && seats[0] != null){
  1396.                 if(EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.turret && EnumDriveablePart.getPart(emitter.part) != EnumDriveablePart.barrel){
  1397.                     Vector3f localPosition = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f,
  1398.                              emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f,
  1399.                              emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f);
  1400.  
  1401.                 pos = axes.findLocalVectorGlobally(localPosition);
  1402.                 velocity = axes.findLocalVectorGlobally(emitter.velocity);
  1403.                 } else if(EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.turret || EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.head && emitter.part != "barrel"){
  1404.  
  1405.                     Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f,
  1406.                              emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f,
  1407.                              emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f);
  1408.                     pos = getPositionOnTurret(localPosition2, false);
  1409.                     velocity = getPositionOnTurret(emitter.velocity, false);
  1410.                 } else if(EnumDriveablePart.getPart(emitter.part) == EnumDriveablePart.barrel){
  1411.                     Vector3f localPosition2 = new Vector3f(emitter.origin.x + rand.nextFloat() * emitter.extents.x - emitter.extents.x * 0.5f,
  1412.                              emitter.origin.y + rand.nextFloat() * emitter.extents.y - emitter.extents.y * 0.5f,
  1413.                              emitter.origin.z + rand.nextFloat() * emitter.extents.z - emitter.extents.z * 0.5f);
  1414.  
  1415.                    
  1416.                     pos = getPositionOnTurret(localPosition2,true);
  1417.                     velocity = getPositionOnTurret(emitter.velocity, true);
  1418.                 }
  1419.                 //FlansMod.proxy.spawnParticle(emitter.effectType, posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z);
  1420.                
  1421.                 FlansMod.getPacketHandler().sendToAllAround(
  1422.                         new PacketParticle(emitter.effectType,
  1423.                                 posX + pos.x, posY + pos.y, posZ + pos.z, velocity.x, velocity.y, velocity.z),
  1424.                                 posX + pos.x, posY + pos.y, posZ + pos.z, 150, dimension);
  1425.                
  1426.                 }
  1427.                 }
  1428.                 emitterTimers[i] = emitter.emitRate;
  1429.             }
  1430.         }
  1431.  
  1432.         checkParts();
  1433.  
  1434.         prevRotationYaw = axes.getYaw();
  1435.         prevRotationPitch = axes.getPitch();
  1436.         prevRotationRoll = axes.getRoll();
  1437.         prevAxes = axes.clone();
  1438.  
  1439.         if(riddenByEntity != null && riddenByEntity.isDead)
  1440.         {
  1441.             riddenByEntity = null;
  1442.         }
  1443.         if(riddenByEntity != null && isDead)
  1444.         {
  1445.             riddenByEntity.mountEntity(null);
  1446.         }
  1447.         if(riddenByEntity != null)
  1448.             riddenByEntity.fallDistance = 0F;
  1449.  
  1450.         boolean canThrust = driverIsCreative() || driveableData.fuelInTank > 0;
  1451.  
  1452.         //If there's no player in the driveable or it cannot thrust, slow the plane and turn off mouse held actions
  1453.         if((seats[0] != null && seats[0].riddenByEntity == null) || !canThrust && getDriveableType().maxThrottle != 0 && getDriveableType().maxNegativeThrottle != 0)
  1454.         {
  1455.             throttle *= 0.99F;
  1456.         }
  1457.         if(seats[0] != null && seats[0].riddenByEntity == null)
  1458.         {
  1459.             rightMouseHeld = leftMouseHeld = false;
  1460.         }
  1461.  
  1462.         //Check if shooting
  1463.         if(shootDelayPrimary > 0)
  1464.             shootDelayPrimary--;
  1465.         if(shootDelaySecondary > 0)
  1466.             shootDelaySecondary--;
  1467. // on first update
  1468.         if(this.ticksExisted == 1)
  1469.         {
  1470.             setShootDelay(getDriveableType().placeTimePrimary,   false);
  1471.             setShootDelay(getDriveableType().placeTimeSecondary, true);
  1472.             if(!this.worldObj.isRemote)
  1473.             {
  1474.                 if(!getDriveableType().placeSoundPrimary.isEmpty())
  1475.                 {
  1476.                     PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension,
  1477.                             getDriveableType().placeSoundPrimary, false);
  1478.                 }
  1479.                 if(!getDriveableType().placeSoundSecondary.isEmpty())
  1480.                 {
  1481.                     PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension,
  1482.                             getDriveableType().placeSoundSecondary, false);
  1483.                 }
  1484.             }
  1485.         }
  1486.         if(!worldObj.isRemote)
  1487.         {
  1488.             if(leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.FULLAUTO)
  1489.                 shoot(false);
  1490.             if(rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.FULLAUTO)
  1491.                 shoot(true);
  1492.             minigunSpeedPrimary *= 0.9F;
  1493.             minigunSpeedSecondary *= 0.9F;
  1494.             if(leftMouseHeld && getDriveableType().modePrimary == EnumFireMode.MINIGUN)
  1495.             {
  1496.                 minigunSpeedPrimary += 0.1F;
  1497.                 if(minigunSpeedPrimary > 1F)
  1498.                     shoot(false);
  1499.             }
  1500.             if(rightMouseHeld && getDriveableType().modeSecondary == EnumFireMode.MINIGUN)
  1501.             {
  1502.                 minigunSpeedSecondary += 0.1F;
  1503.                 if(minigunSpeedSecondary > 1F)
  1504.                     shoot(true);
  1505.             }
  1506.         }
  1507.        
  1508.         prevDeckCheck = deckCheck;
  1509.  
  1510.         //Handle fuel
  1511.  
  1512.         int fuelMultiplier = 2;
  1513.  
  1514.         //The tank is currently full, so do nothing
  1515.         if(data.fuelInTank >= type.fuelTankSize)
  1516.             return;
  1517.  
  1518.         //Look through the entire inventory for fuel cans, buildcraft fuel buckets and RedstoneFlux power sources
  1519.         for(int i = 0; i < data.getSizeInventory(); i++)
  1520.         {
  1521.             ItemStack stack = data.getStackInSlot(i);
  1522.             if(stack == null || stack.stackSize <= 0)
  1523.                 continue;
  1524.             Item item = stack.getItem();
  1525.             //If we have an electric engine, look for RedstoneFlux power source items, such as power cubes
  1526.             if(data.engine.useRFPower)
  1527.             {
  1528.                 if(item instanceof IEnergyContainerItem)
  1529.                 {
  1530.                     IEnergyContainerItem energy = (IEnergyContainerItem)item;
  1531.                     data.fuelInTank += (fuelMultiplier * energy.extractEnergy(stack, data.engine.RFDrawRate, false)) / data.engine.RFDrawRate;
  1532.                 }
  1533.             }
  1534.             else
  1535.             {
  1536.                 //Check for Flan's Mod fuel items
  1537.                 if(item instanceof ItemPart)
  1538.                 {
  1539.                     PartType part = ((ItemPart)item).type;
  1540.                     //Check it is a fuel item
  1541.                     if(part.category == 9)
  1542.                     {
  1543.                         //Put 2 points of fuel
  1544.                         data.fuelInTank += fuelMultiplier;
  1545.  
  1546.                         //Damage the fuel item to indicate being used up
  1547.                         int damage = stack.getItemDamage();
  1548.                         stack.setItemDamage(damage + 1);
  1549.  
  1550.                         //If we have finished this fuel item
  1551.                         if(damage >= stack.getMaxDamage())
  1552.                         {
  1553.                             //Reset the damage to 0
  1554.                             stack.setItemDamage(0);
  1555.                             //Consume one item
  1556.                             stack.stackSize--;
  1557.                             //If we consumed the last one, destroy the stack
  1558.                             if(stack.stackSize <= 0)
  1559.                                 data.setInventorySlotContents(i, null);
  1560.                         }
  1561.  
  1562.                         //We found a fuel item and consumed some, so we are done
  1563.                         break;
  1564.                     }
  1565.                 }
  1566.                 //Check for Buildcraft oil and fuel buckets
  1567.                 else if(FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftOilBucket) && data.fuelInTank + 1000 * fuelMultiplier <= type.fuelTankSize)
  1568.                 {
  1569.                     data.fuelInTank += 1000 * fuelMultiplier;
  1570.                     data.setInventorySlotContents(i, new ItemStack(Items.bucket));
  1571.                 }
  1572.                 else if(FlansMod.hooks.BuildCraftLoaded && stack.isItemEqual(FlansMod.hooks.BuildCraftFuelBucket) && data.fuelInTank + 2000 * fuelMultiplier <= type.fuelTankSize)
  1573.                 {
  1574.                     data.fuelInTank += 2000 * fuelMultiplier;
  1575.                     data.setInventorySlotContents(i, new ItemStack(Items.bucket));
  1576.                 }
  1577.                
  1578.                 prevPosX = posX;
  1579.                 prevPosY = posY;
  1580.                 prevPosZ = posZ;
  1581.             }
  1582.         }
  1583.     }
  1584.  
  1585.     public void checkInventoryChanged()
  1586.     {
  1587.         DriveableType type = getDriveableType();
  1588.         if(type == null) return;
  1589.  
  1590.         if(worldObj.isRemote) return;
  1591.  
  1592.         if(!driveableData.inventoryChanged) return;
  1593.  
  1594.         driveableData.inventoryChanged = false;
  1595.  
  1596.         try
  1597.         {
  1598.             for(int ps=0; ps < 2; ps ++)
  1599.             {
  1600.                 EnumWeaponType weaponType = ps==0? type.primary: type.secondary;
  1601.                 if(weaponType == EnumWeaponType.GUN)
  1602.                 {
  1603.                     weaponType = EnumWeaponType.NONE;
  1604.                 }
  1605.                 int istart = getInventoryStart(weaponType);
  1606.                 if(istart == driveableData.getAmmoInventoryStart())
  1607.                 {
  1608.                     istart += type.numPassengerGunners;
  1609.                 }
  1610.                 final int isize  = getInventorySize(weaponType);
  1611.                 if(istart >= 0 || isize > 0)
  1612.                 {
  1613.                     if(prevInventoryItems[ps] == null)
  1614.                     {
  1615.                         prevInventoryItems[ps] = new ItemStack[isize];
  1616.                     }
  1617.  
  1618.                     for(int i=0; i<isize; i++)
  1619.                     {
  1620.                         ItemStack itemStack = driveableData.getStackInSlot(istart + i);
  1621.                         if(itemStack != null && itemStack.getItem() instanceof ItemBullet)
  1622.                         {
  1623.                             if(prevInventoryItems[ps][i]==null || !ItemStack.areItemStacksEqual(itemStack, prevInventoryItems[ps][i]))
  1624.                             {
  1625.                                 if(type.isValidAmmo(((ItemBullet)itemStack.getItem()).type, weaponType))
  1626.                                 {
  1627.                                     onWeaponInventoryChanged(ps==1);
  1628.                                     break;
  1629.                                 }
  1630.                             }
  1631.                         }
  1632.                     }
  1633.  
  1634.                     for(int i=0; i<isize; i++)
  1635.                     {
  1636.                         prevInventoryItems[ps][i] = driveableData.getStackInSlot(istart + i);
  1637.                     }
  1638.                 }
  1639.             }
  1640.         }
  1641.         catch(Exception e)
  1642.         {
  1643.             e.printStackTrace();
  1644.         }
  1645.     }
  1646.  
  1647.     public void onWeaponInventoryChanged(boolean secondary)
  1648.     {
  1649.         DriveableType type = getDriveableType();
  1650.         if(!secondary)
  1651.         {
  1652.             if(type.reloadTimePrimary > 0 && getShootDelay(secondary) <= 0)
  1653.             {
  1654.                 FlansMod.log("EntityDriveable Reload Primary " + type.reloadTimePrimary + " tick");
  1655.                 setShootDelay(type.reloadTimePrimary, secondary);
  1656.                 PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension,
  1657.                         getDriveableType().reloadSoundPrimary, false);
  1658.             }
  1659.         }
  1660.         else
  1661.         {
  1662.             if(type.reloadTimeSecondary > 0 && getShootDelay(secondary) <= 0)
  1663.             {
  1664.                 FlansMod.log("EntityDriveable Reload Secondary " + type.reloadTimeSecondary + " tick");
  1665.                 setShootDelay(type.reloadTimeSecondary, secondary);
  1666.                 PacketPlaySound.sendSoundPacket(posX, posY, posZ, FlansMod.soundRange, dimension,
  1667.                         getDriveableType().reloadSoundSecondary, false);
  1668.             }
  1669.         }
  1670.     }
  1671.  
  1672.     public int getInventoryStart(EnumWeaponType wt)
  1673.     {
  1674.         switch (wt)
  1675.         {
  1676.         case NONE:
  1677.         case GUN:
  1678.             return driveableData.getAmmoInventoryStart();
  1679.  
  1680.         case MISSILE:
  1681.         case SHELL:
  1682.             return driveableData.getMissileInventoryStart();
  1683.  
  1684.         case BOMB:
  1685.         case MINE:
  1686.             return driveableData.getBombInventoryStart();
  1687.  
  1688.         default:
  1689.             break;
  1690.         }
  1691.         return -1;
  1692.     }
  1693.     public int getInventorySize(EnumWeaponType wt)
  1694.     {
  1695.         switch (wt)
  1696.         {
  1697.         case NONE:
  1698.         case GUN:
  1699.             return driveableData.ammo.length;
  1700.  
  1701.         case MISSILE:
  1702.         case SHELL:
  1703.             return driveableData.missiles.length;
  1704.  
  1705.         case BOMB:
  1706.         case MINE:
  1707.             return driveableData.bombs.length;
  1708.  
  1709.         default:
  1710.             break;
  1711.         }
  1712.         return -1;
  1713.     }
  1714.  
  1715.     public void checkForCollisions()
  1716.     {
  1717.         boolean damagePart = false;
  1718.         boolean crashInWater = false;
  1719.         double speed = getSpeedXYZ();
  1720.         for(DriveablePosition p : getDriveableType().collisionPoints)
  1721.         {
  1722.             if(driveableData.parts.get(p.part).dead)
  1723.                 continue;
  1724.             Vector3f lastRelPos = prevAxes.findLocalVectorGlobally(p.position);
  1725.             Vec3 lastPos = Vec3.createVectorHelper(prevPosX + lastRelPos.x, prevPosY + lastRelPos.y, prevPosZ + lastRelPos.z);
  1726.  
  1727.             Vector3f currentRelPos = axes.findLocalVectorGlobally(p.position);
  1728.             Vec3 currentPos = Vec3.createVectorHelper(posX + currentRelPos.x, posY + currentRelPos.y, posZ + currentRelPos.z);
  1729.  
  1730.             if(FlansMod.DEBUG && worldObj.isRemote)
  1731.             {
  1732.                 worldObj.spawnEntityInWorld(new EntityDebugVector(worldObj, new Vector3f(lastPos), Vector3f.sub(currentRelPos, lastRelPos, null), 10, 1F, 0F, 0F));
  1733.             }
  1734.  
  1735.             MovingObjectPosition hit = worldObj.rayTraceBlocks(lastPos, currentPos, crashInWater);
  1736.             if(hit != null && hit.typeOfHit == MovingObjectType.BLOCK)
  1737.             {
  1738.                 int x = hit.blockX;
  1739.                 int y = hit.blockY;
  1740.                 int z = hit.blockZ;
  1741.                 Block blockHit = worldObj.getBlock(x, y, z);
  1742.                 int meta = worldObj.getBlockMetadata(x, y, z);
  1743.  
  1744.                 float blockHardness = blockHit.getBlockHardness(worldObj, x, y, z);
  1745.                 float damage = blockHardness * blockHardness * (float)speed;
  1746.  
  1747.                 if(null==blockHit.getCollisionBoundingBoxFromPool(this.worldObj, x,y,z))
  1748.                 {
  1749.                     damage = 0;
  1750.                 }
  1751.  
  1752.                 if(damage > 0)
  1753.                 {
  1754.                     damagePart = true;
  1755.                 }
  1756.  
  1757.                 //Attack the part
  1758.                 if(!attackPart(p.part, DamageSource.inWall, damage) && TeamsManager.driveablesBreakBlocks)
  1759.                 {
  1760.                     //And if it didn't die from the attack, break the block
  1761.                     worldObj.playAuxSFXAtEntity(null, 2001, x, y, z, Block.getIdFromBlock(blockHit) + (meta << 12));
  1762.  
  1763.                     if(!worldObj.isRemote)
  1764.                     {
  1765.                         blockHit.dropBlockAsItem(worldObj, x, y, z, meta, 1);
  1766.                         worldObj.setBlockToAir(x, y, z);
  1767.                     }
  1768.                 }
  1769.                 else
  1770.                 {
  1771.                     //The part died!
  1772.                     worldObj.createExplosion(this, currentPos.xCoord, currentPos.yCoord, currentPos.zCoord, 1F, false);
  1773.                 }
  1774.             }
  1775.  
  1776.         }
  1777.  
  1778.         if(damagePart)
  1779.         {
  1780.             //This is server side bsns
  1781.             if(!worldObj.isRemote)
  1782.             {
  1783. //              checkParts();
  1784.                 //If it hit, send a damage update packet
  1785.                 FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension);
  1786.             }
  1787.         }
  1788.     }
  1789.  
  1790.     @Override
  1791.     protected void fall(float k)
  1792.     {
  1793.         double fallDist = ((this.posY - this.prevPosY) + this.motionY) / 2;
  1794.         float damage = (float) (fallDist < -0.3 ? -fallDist * 50 : 0);
  1795.  
  1796.         boolean no_damage = true;
  1797.         if (damage > 0 && invulnerableUnmountCount == 0 && this.ticksExisted > 20 && !no_damage)
  1798.         {
  1799.             DriveableType type = getDriveableType();
  1800.             damage = (int)(damage * type.fallDamageFactor);
  1801.             attackPart(EnumDriveablePart.core, DamageSource.fall, damage);
  1802.             if (type.wheelPositions.length > 0)
  1803.             {
  1804.                 attackPart(type.wheelPositions[0].part, DamageSource.fall, damage / 5);
  1805.             }
  1806.  
  1807.             no_damage = false;
  1808.         }
  1809.     //  FlansMod.log("fall%s : tick=%d damage=%.1f, posY-prevPosY=%.3f, mY=%.3f, fallDist=%.2f",
  1810.     //      no_damage? " no damage":"", this.ticksExisted, damage, this.posY - this.prevPosY,
  1811.     //      this.motionY, fallDist);
  1812.     }
  1813.  
  1814.     /** Attack a certain part of a driveable and return whether it broke or not */
  1815.     public boolean attackPart(EnumDriveablePart ep, DamageSource source, float damage)
  1816.     {
  1817.         if( ep==EnumDriveablePart.core )
  1818.         {
  1819.             if(source.getSourceOfDamage() instanceof EntityLivingBase)
  1820.             {
  1821.                 this.lastAtkEntity = source.getSourceOfDamage();
  1822.             }
  1823.             else if(source.getEntity() instanceof EntityLivingBase)
  1824.             {
  1825.                 this.lastAtkEntity = source.getEntity();
  1826.             }
  1827.             else
  1828.             {
  1829.                 this.lastAtkEntity = null;
  1830.             }
  1831.         }
  1832.         DriveablePart part = driveableData.parts.get(ep);
  1833.     //  FlansMod.log("EntityDriveable.attackPart %s : %s : damage=%.1f : %s : health=%d", ep.name(), ep.getName(), damage,
  1834.     //          part.type.name(), part.health);
  1835.         return part.attack(damage, source.isFireDamage());
  1836.     }
  1837.  
  1838.     /** Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates */
  1839.     public Vector3f rotate(Vector3f inVec)
  1840.     {
  1841.         return axes.findLocalVectorGlobally(inVec);
  1842.     }
  1843.  
  1844.     /** Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates */
  1845.     public Vector3f rotate(Vec3 inVec)
  1846.     {
  1847.         return rotate(inVec.xCoord, inVec.yCoord, inVec.zCoord);
  1848.     }
  1849.  
  1850.     /** Takes a vector (such as the origin of a seat / gun) and translates it from local coordinates to global coordinates */
  1851.     public Vector3f rotate(double x, double y, double z)
  1852.     {
  1853.         return rotate(new Vector3f((float)x, (float)y, (float)z));
  1854.     }
  1855.  
  1856.     //Rotate the plane locally by some angle about the yaw axis
  1857.     public void rotateYaw(float rotateBy)
  1858.     {
  1859.         if(Math.abs(rotateBy) < 0.01F)
  1860.             return;
  1861.         axes.rotateLocalYaw(rotateBy);
  1862.         updatePrevAngles();
  1863.     }
  1864.  
  1865.     //Rotate the plane locally by some angle about the pitch axis
  1866.     public void rotatePitch(float rotateBy)
  1867.     {
  1868.         if(Math.abs(rotateBy) < 0.01F)
  1869.             return;
  1870.         axes.rotateLocalPitch(rotateBy);
  1871.         updatePrevAngles();
  1872.     }
  1873.  
  1874.     //Rotate the plane locally by some angle about the roll axis
  1875.     public void rotateRoll(float rotateBy)
  1876.     {
  1877.         if(Math.abs(rotateBy) < 0.01F)
  1878.             return;
  1879.         axes.rotateLocalRoll(rotateBy);
  1880.         updatePrevAngles();
  1881.     }
  1882.  
  1883.     public void updatePrevAngles()
  1884.     {
  1885.         //Correct angles that crossed the +/- 180 line, so that rendering doesnt make them swing 360 degrees in one tick.
  1886.         double dYaw = axes.getYaw() - prevRotationYaw;
  1887.         if(dYaw > 180)
  1888.             prevRotationYaw += 360F;
  1889.         if(dYaw < -180)
  1890.             prevRotationYaw -= 360F;
  1891.  
  1892.         double dPitch = axes.getPitch() - prevRotationPitch;
  1893.         if(dPitch > 180)
  1894.             prevRotationPitch += 360F;
  1895.         if(dPitch < -180)
  1896.             prevRotationPitch -= 360F;
  1897.  
  1898.         double dRoll = axes.getRoll() - prevRotationRoll;
  1899.         if(dRoll > 180)
  1900.             prevRotationRoll += 360F;
  1901.         if(dRoll < -180)
  1902.             prevRotationRoll -= 360F;
  1903.     }
  1904.  
  1905.     public void setRotation(float rotYaw, float rotPitch, float rotRoll)
  1906.     {
  1907.         axes.setAngles(rotYaw, rotPitch, rotRoll);
  1908.     }
  1909.  
  1910.     //Used to stop self collision
  1911.     public boolean isPartOfThis(Entity ent)
  1912.     {
  1913.         for(EntitySeat seat : seats)
  1914.         {
  1915.             if(seat == null)
  1916.                 continue;
  1917.             if(ent == seat)
  1918.                 return true;
  1919.             if(seat.riddenByEntity == ent)
  1920.                 return true;
  1921.         }
  1922.         return ent == this;
  1923.     }
  1924.  
  1925.     @Override
  1926.     public float getShadowSize()
  1927.     {
  1928.         return 0.0F;
  1929.     }
  1930.  
  1931.     public DriveableType getDriveableType()
  1932.     {
  1933.         return DriveableType.getDriveable(driveableType);
  1934.     }
  1935.  
  1936.     public DriveableData getDriveableData()
  1937.     {
  1938.         return driveableData;
  1939.     }
  1940.  
  1941.     @Override
  1942.     public boolean isDead()
  1943.     {
  1944.         return isDead;
  1945.     }
  1946.  
  1947.     @Override
  1948.     public Entity getControllingEntity()
  1949.     {
  1950.         return seats[0].getControllingEntity();
  1951.     }
  1952.  
  1953.     @Override
  1954.     public ItemStack getPickedResult(MovingObjectPosition target)
  1955.     {
  1956.         ItemStack stack = new ItemStack(getDriveableType().item, 1, 0);
  1957.         stack.stackTagCompound = new NBTTagCompound();
  1958.         driveableData.writeToNBT(stack.stackTagCompound);
  1959.         return stack;
  1960.     }
  1961.  
  1962.  
  1963.     public boolean hasFuel() {
  1964.         if (seats == null || seats[0] == null || seats[0].riddenByEntity == null)
  1965.             return false;
  1966.         return driverIsCreative() || driveableData.fuelInTank > 0;
  1967.     }
  1968.  
  1969.     public boolean hasEnoughFuel() {
  1970.         //if (seats == null || seats[0] == null || seats[0].riddenByEntity == null)
  1971.             //return false;
  1972.         return driverIsCreative() || driveableData.fuelInTank > driveableData.engine.fuelConsumption * throttle;
  1973.  
  1974.     }
  1975.  
  1976.     //Physics time! Oooh yeah
  1977.  
  1978.     public double getSpeedXYZ()
  1979.     {
  1980.         return Math.sqrt(motionX * motionX + motionY * motionY + motionZ * motionZ);
  1981.     }
  1982.  
  1983.     public double getSpeedXZ()
  1984.     {
  1985.         return Math.sqrt(motionX * motionX + motionZ * motionZ);
  1986.     }
  1987.  
  1988.     /** To be overriden by vehicles to get alternate collision system */
  1989.     public boolean landVehicle()
  1990.     {
  1991.         return false;
  1992.     }
  1993.  
  1994.     /** Overriden by planes for wheel parts */
  1995.     public boolean gearDown()
  1996.     {
  1997.         return true;
  1998.     }
  1999.  
  2000.     /** Whether or not the plane is on the ground
  2001.      * TODO : Replace with proper check based on wheels
  2002.      * */
  2003.     public boolean onGround()
  2004.     {
  2005.         return onGround;
  2006.     }
  2007.    
  2008.    
  2009.     //Collision mechanism mkII
  2010.     public void moveRiders(Entity rider)
  2011.     {
  2012.         if(isPartOfThis(rider)) return;
  2013.         boolean isHuman = false;
  2014.         boolean isDriveable = false;
  2015.         if(!(rider instanceof EntityPlayer)) return;
  2016.         Vector3f riderPos = new Vector3f (rider.posX, rider.posY, rider.posZ);
  2017.         Vector3f riderMotion = new Vector3f(rider.motionX, rider.motionY, rider.motionY);
  2018.         Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z);
  2019.         if(rider instanceof EntityVehicle) vehicleMotion = ((EntityVehicle)rider).lastPos;
  2020.         //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion);
  2021.         Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ);
  2022.         Vector3f relativePos = Vector3f.sub(riderPos, vehiclePos, null);
  2023.         if(rider instanceof EntityPlayer) isHuman = true;
  2024.         if(rider instanceof EntityDriveable) isDriveable = true;
  2025.         relativePos = new Vector3f(relativePos.x, relativePos.y - ((isHuman)?0.55F:0), relativePos.z);
  2026.  
  2027.         Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos);
  2028.         Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(riderMotion);
  2029.        
  2030.         Vector3f ellipsoid = new Vector3f(rider.width/2, rider.height, rider.width/2);
  2031.        
  2032.         CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), riderMotion);
  2033.         test.collisionRecursiveDepth = 0;
  2034.        
  2035.         Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position);
  2036.         Vector3f eSpaceVelocity = test.velocity;
  2037.        
  2038.         //Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity);
  2039.         DriveableType type = getDriveableType();
  2040.         //Check parts for collision
  2041.         if(type.fancyCollision)
  2042.         {
  2043.             //checkCollision(test, getDriveableType().colbox);
  2044.             for(CollisionShapeBox sbox: type.collisionBox)
  2045.             {
  2046.                 checkCollision(test, sbox);
  2047.             }
  2048.         } else {
  2049.             for(DriveablePart ppart : getDriveableData().parts.values())
  2050.             {
  2051.                 ppart.rayTraceRider(this, test);
  2052.             }
  2053.         }
  2054.        
  2055.         if(test.didCollide){
  2056.         Vector3f finalPos = collideWithDriveable(test, eSpacePosition, eSpaceVelocity);
  2057.         if(rider instanceof EntityAnimal) return;
  2058.         Vector3f velocity = Vector3f.sub(finalPos, test.basePoint, null);
  2059.         test.ConvertESpaceToR3(velocity);
  2060.         finalPos = new Vector3f(finalPos.x * test.eRad.x, finalPos.y * test.eRad.y, finalPos.z * test.eRad.z);
  2061.         Vector3f diff = Vector3f.sub(finalPos, vehiclePos, null);
  2062.        
  2063.        
  2064.         if(rider.onGround && (posY + finalPos.y + 10/16F) < riderPos.y)
  2065.         {
  2066.             //finalPos = new Vector3f(finalPos.x, 0, finalPos.z);
  2067.         }
  2068.         //boolean onTop = (rider.posY + 0.65 > test.intersectionPoint.y);
  2069.        
  2070.         boolean stationary = (throttle == 0);
  2071.        
  2072.         //If finalPos returns null, do something about it. Probably not the best way to handle this.
  2073.         if(finalPos == null) finalPos = new Vector3f(0,0,0);
  2074.         test.ConvertESpaceToR3(finalPos);
  2075.         boolean onTop = (test.collisionPlaneNormal.y >= 0.5F);
  2076.         if(posY + finalPos.y +10/16F< riderPos.y) finalPos.y = (riderPos.y - (float)posY - 10F/16F);
  2077.         if(!hugeBoat)
  2078.         rider.setPosition((!onTop)?riderPos.x + finalPos.x/(48*Math.abs(relativePos.x)): riderPos.x,(onTop)?posY + finalPos.y + 10/16F:riderPos.y,(!onTop)?riderPos.z + finalPos.z/(48*Math.abs(relativePos.z)): riderPos.z);
  2079.         //test.ConvertESpaceToR3(test.intersectionPoint);
  2080.         //FlansMod.proxy.spawnParticle("flame", test.intersectionPoint.x + posX, test.intersectionPoint.y + posY - 1, test.intersectionPoint.z + posZ, 0, 0, 0);
  2081.        
  2082.         if(hugeBoat && !stationary){
  2083.             rider.setPosition(riderPos.x, posY + finalPos.y + 9.5/16F,riderPos.z);
  2084.         } else if (hugeBoat && stationary) {
  2085.             rider.setPosition(riderPos.x, posY + finalPos.y + 10/16F,riderPos.z);  
  2086.         }
  2087.         finalPos = Vector3f.sub(finalPos, riderPos, null);
  2088.         finalPos.normalise();
  2089.  
  2090.         //rider.motionX = rider.motionX * finalPos.x;
  2091.         rider.motionY = 0;
  2092.         //rider.motionZ = rider.motionZ * finalPos.z;
  2093.        
  2094.        
  2095.         //Vector3f intersect = test.intersectionPoint;
  2096.         //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX + intersect.x, posY + intersect.y, posZ + intersect.z, 0,1,0);
  2097.         //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", posX, posY, posZ, 0,1,0);
  2098.         //worldObj.spawnParticle((test.isOnTop)?"fireworksSpark":"explode", riderPos.x, riderPos.y, riderPos.z, 0,1,0);
  2099.  
  2100.         //worldObj.spawnParticle("crit", posX + finalPos.x, posY + finalPos.y, posZ + finalPos.z, 0,0,0);
  2101.         //worldObj.spawnParticle("reddust", riderPos.x, riderPos.y - 0.65, riderPos.z, 0,0,0);
  2102.  
  2103.        
  2104.         updateRiderPos(rider, test, finalPos, riderMotion);
  2105.        
  2106.         if(getDriveableType().collisionDamageEnable && !test.isOnTop)
  2107.         {
  2108.             if(throttle > getDriveableType().collisionDamageThrottle)
  2109.             {
  2110.                 boolean canDamage = true;
  2111.                 if(TeamsManager.getInstance() != null && TeamsManager.getInstance().currentRound != null && rider instanceof EntityPlayerMP && seats[0].riddenByEntity instanceof EntityPlayer)
  2112.                 {
  2113.                     EntityPlayerMP attacker = (EntityPlayerMP)seats[0].riddenByEntity;
  2114.                     EntityPlayerMP player = (EntityPlayerMP)rider;
  2115.                     if(TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team != null)
  2116.                     {
  2117.                         if(TeamsManager.getInstance().currentRound.gametype.getPlayerData(player) != null && TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team != null)
  2118.                         {
  2119.                             if(TeamsManager.getInstance().currentRound.gametype.getPlayerData(player).team == TeamsManager.getInstance().currentRound.gametype.getPlayerData(attacker).team)
  2120.                             {
  2121.                                 canDamage = false;
  2122.                             }
  2123.                         }
  2124.                     }
  2125.                 }
  2126.                 for(EntitySeat seat : seats)
  2127.                 {
  2128.                     if(rider == seat.lastRiddenByEntity)
  2129.                         canDamage = false;
  2130.                 }
  2131.                
  2132.                
  2133.                
  2134.                 if(canDamage){
  2135.                     if(rider instanceof EntityLiving){
  2136.                         rider.attackEntityFrom(DamageSource.generic, throttle*getDriveableType().collisionDamageTimes);
  2137.                     }else if(rider instanceof EntityPlayer){
  2138.                         rider.attackEntityFrom(DamageSource.generic, throttle*getDriveableType().collisionDamageTimes);
  2139.                     }
  2140.                 }
  2141.             }
  2142.         }
  2143.         if(rider instanceof EntityPlayer){
  2144.             EntityPlayer player = (EntityPlayer)rider;
  2145.             //playerIDs.add(player);
  2146.             player.onGround = true;
  2147.             player.isAirBorne = false;
  2148.             player.fallDistance = 0;
  2149.         }
  2150.        
  2151.         }
  2152.        
  2153.         else
  2154.         {
  2155.             if(rider instanceof EntityDriveable)
  2156.             {
  2157.                 //((EntityDriveable)rider).onDeck = false;
  2158.                 ((EntityDriveable)rider).deckHeight = 0;
  2159.             }
  2160.         }
  2161.        
  2162.        
  2163.     }
  2164.     /**
  2165.     @SubscribeEvent
  2166.     public void updateRiders(LivingUpdateEvent event){
  2167.        
  2168.         for(EntityPlayer player: playerIDs){
  2169.             Entity p = (Entity)player;
  2170.             if(p == event.entity){
  2171.                 player.onGround = true;
  2172.                 player.isAirBorne = false;
  2173.                 player.fallDistance = 0;
  2174.                 playerIDs.remove(player);
  2175.             }
  2176.         }
  2177.     }
  2178.      */
  2179.    
  2180.     public DamageSource getBulletDamage(boolean headshot)
  2181.     {
  2182.         DriveableType type = getDriveableType();
  2183.         EntityLivingBase owner = (EntityLivingBase)seats[0].riddenByEntity;
  2184.         if(owner instanceof EntityPlayer)
  2185.             return (new EntityDamageSourceGun(getDriveableType().shortName, this, (EntityPlayer)owner, type, headshot)).setProjectile();
  2186.         else return (new EntityDamageSourceIndirect(type.shortName, this, owner)).setProjectile();
  2187.     }
  2188.     public void checkCollision(CollisionTest tester, CollisionShapeBox box)
  2189.     {
  2190.         {      
  2191.             double distance = tester.nearestDistance;
  2192.             Vector3f collisionPoint = new Vector3f(0,0,0);
  2193.             int surface = 0;
  2194.            
  2195.             Vector3f pos = new Vector3f(this.posX, this.posY, this.posZ);
  2196.            
  2197.             RotatedAxes shift = axes;
  2198.            
  2199.             float f4 = box.pos.x + box.size.x;
  2200.             float f5 = -box.pos.y + box.size.y;
  2201.             float f6 = box.pos.z + box.size.z;
  2202.            
  2203.             box.pos = new Vector3f(box.pos.x, box.pos.y, box.pos.z);
  2204.             //if(EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret) return;
  2205.             //Define box verticies, where z > 0 is right. See shapeboxes in the toolbox for a visual reference
  2206.             Vector3f p1 = new Vector3f(box.pos.x - box.p1.x, box.pos.y + box.size.y + box.p1.y - box.size.y + 0.625F, box.pos.z - box.p1.z);
  2207.             Vector3f p2 = new Vector3f(box.pos.x + box.size.x + box.p2.x,box.pos.y + box.size.y + box.p2.y - box.size.y + 0.625F, box.pos.z - box.p2.z);
  2208.             Vector3f p3 = new Vector3f(box.pos.x + box.size.x + box.p3.x, box.pos.y + box.size.y + box.p3.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p3.z);
  2209.             Vector3f p4 = new Vector3f(box.pos.x - box.p4.x, box.pos.y + box.size.y + box.p4.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p4.z);
  2210.             Vector3f p5 = new Vector3f(box.pos.x - box.p5.x, box.pos.y - box.p5.y - box.size.y + 0.625F, box.pos.z - box.p5.z);
  2211.             Vector3f p6 = new Vector3f(box.pos.x + box.size.x + box.p6.x, box.pos.y - box.p6.y - box.size.y + 0.625F, box.pos.z - box.p6.z);
  2212.             Vector3f p7 = new Vector3f(box.pos.x + box.size.x + box.p7.x, box.pos.y - box.p7.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p7.z);
  2213.             Vector3f p8 = new Vector3f(box.pos.x - box.p8.x, box.pos.y - box.p8.y - box.size.y + 0.625F, box.pos.z + box.size.z + box.p8.z);
  2214.            
  2215.             if(EnumDriveablePart.getPart(box.part) == EnumDriveablePart.turret && seats[0] != null)
  2216.             {
  2217.                 p1 = getPositionOnTurret(p1, false); //Front upper left
  2218.                 p2 = getPositionOnTurret(p2, false); //Front upper right
  2219.                 p3 = getPositionOnTurret(p3, false); //Rear upper right
  2220.                 p4 = getPositionOnTurret(p4, false); //Rear upper left
  2221.                 p5 = getPositionOnTurret(p5, false); //Front lower left
  2222.                 p6 = getPositionOnTurret(p6, false); //Front lower right
  2223.                 p7 = getPositionOnTurret(p7, false); //Rear lower right
  2224.                 p8 = getPositionOnTurret(p8, false); //Rear lower left
  2225.             } else {
  2226.                 p1 = shift.findLocalVectorGlobally(p1);
  2227.                 p2 = shift.findLocalVectorGlobally(p2);
  2228.                 p3 = shift.findLocalVectorGlobally(p3);
  2229.                 p4 = shift.findLocalVectorGlobally(p4);
  2230.                 p5 = shift.findLocalVectorGlobally(p5);
  2231.                 p6 = shift.findLocalVectorGlobally(p6);
  2232.                 p7 = shift.findLocalVectorGlobally(p7);
  2233.                 p8 = shift.findLocalVectorGlobally(p8);
  2234.             }
  2235.            
  2236.            
  2237.             //Check top face
  2238.             double topFaceDist = 100;
  2239.  
  2240.             tester.checkTriangle(tester, p3, p2, p1);
  2241.             if(tester.didCollide && tester.nearestDistance < distance)
  2242.             {
  2243.                 collisionPoint = tester.intersectionPoint;
  2244.                 surface = 1;
  2245.                 tester.part = EnumDriveablePart.getPart(box.part);
  2246.             }
  2247.                
  2248.             tester.checkTriangle(tester, p4, p3, p1);
  2249.             if(tester.didCollide && tester.nearestDistance < distance)
  2250.             {
  2251.                 collisionPoint = tester.intersectionPoint;
  2252.                 surface = 1;
  2253.                 tester.part = EnumDriveablePart.getPart(box.part);
  2254.             }
  2255.            
  2256.             if(tester.didCollide){
  2257.                 tester.isOnTop = true;
  2258.                 topFaceDist = tester.nearestDistance;
  2259.             }
  2260.            
  2261.             //Check front face
  2262.             tester.checkTriangle(tester, p6, p7, p3);
  2263.             if(tester.didCollide && tester.nearestDistance < distance)
  2264.             {
  2265.                 distance = tester.nearestDistance;
  2266.                 collisionPoint = tester.intersectionPoint;
  2267.                 surface = 2;
  2268.                 tester.part = EnumDriveablePart.getPart(box.part);
  2269.             }
  2270.             tester.checkTriangle(tester, p3, p2, p6);
  2271.             if(tester.didCollide && tester.nearestDistance < distance)
  2272.             {
  2273.                 distance = tester.nearestDistance;
  2274.                 collisionPoint = tester.intersectionPoint;
  2275.                 surface = 2;
  2276.                 tester.part = EnumDriveablePart.getPart(box.part);
  2277.             }
  2278.            
  2279.            
  2280.             //Check rear face
  2281.             tester.checkTriangle(tester, p4, p1, p5);
  2282.             if(tester.didCollide && tester.nearestDistance < distance)
  2283.             {
  2284.                 distance = tester.nearestDistance;
  2285.                 collisionPoint = tester.intersectionPoint;
  2286.                 surface = 3;
  2287.                 tester.part = EnumDriveablePart.getPart(box.part);
  2288.             }
  2289.             tester.checkTriangle(tester, p5, p8, p4);
  2290.             if(tester.didCollide && tester.nearestDistance < distance)
  2291.             {
  2292.                 distance = tester.nearestDistance;
  2293.                 collisionPoint = tester.intersectionPoint;
  2294.                 surface = 3;
  2295.                 tester.part = EnumDriveablePart.getPart(box.part);
  2296.             }
  2297.            
  2298.             //Check Left Face
  2299.             tester.checkTriangle(tester, p6, p5, p1);
  2300.             if(tester.didCollide && tester.nearestDistance < distance)
  2301.             {
  2302.                 distance = tester.nearestDistance;
  2303.                 collisionPoint = tester.intersectionPoint;
  2304.                 surface = 4;
  2305.                 tester.part = EnumDriveablePart.getPart(box.part);
  2306.             }
  2307.             tester.checkTriangle(tester, p1, p2, p6);
  2308.             if(tester.didCollide && tester.nearestDistance < distance)
  2309.             {
  2310.                 distance = tester.nearestDistance;
  2311.                 collisionPoint = tester.intersectionPoint;
  2312.                 surface = 4;
  2313.                 tester.part = EnumDriveablePart.getPart(box.part);
  2314.             }
  2315.            
  2316.             //Check right face
  2317.             tester.checkTriangle(tester, p8, p7, p3);
  2318.             if(tester.didCollide && tester.nearestDistance < distance)
  2319.             {
  2320.                 distance = tester.nearestDistance;
  2321.                 collisionPoint = tester.intersectionPoint;
  2322.                 surface = 5;
  2323.                 tester.part = EnumDriveablePart.getPart(box.part);
  2324.             }
  2325.             tester.checkTriangle(tester, p3, p4, p8);
  2326.             if(tester.didCollide && tester.nearestDistance < distance)
  2327.             {
  2328.                 distance = tester.nearestDistance;
  2329.                 collisionPoint = tester.intersectionPoint;
  2330.                 surface = 5;
  2331.                 tester.part = EnumDriveablePart.getPart(box.part);
  2332.             }
  2333.  
  2334.             //Check bottom face
  2335.             tester.checkTriangle(tester, p5, p6, p7);
  2336.             if(tester.didCollide && tester.nearestDistance < distance)
  2337.             {
  2338.                 collisionPoint = tester.intersectionPoint;
  2339.                 surface = 1;
  2340.                 tester.part = EnumDriveablePart.getPart(box.part);
  2341.             }
  2342.                
  2343.             tester.checkTriangle(tester, p8, p7, p5);
  2344.             if(tester.didCollide && tester.nearestDistance < distance)
  2345.             {
  2346.                 collisionPoint = tester.intersectionPoint;
  2347.                 surface = 1;
  2348.                 tester.part = EnumDriveablePart.getPart(box.part);
  2349.             }
  2350.            
  2351.             if(tester.didCollide){
  2352.                 tester.isOnTop = true;
  2353.                 topFaceDist = tester.nearestDistance;
  2354.             }
  2355.            
  2356.             Vector3f.add(p1, pos, p1);
  2357.             Vector3f.add(p2, pos, p2);
  2358.             Vector3f.add(p3, pos, p3);
  2359.             Vector3f.add(p4, pos, p4);
  2360.             Vector3f.add(p5, pos, p5);
  2361.             Vector3f.add(p6, pos, p6);
  2362.             Vector3f.add(p7, pos, p7);
  2363.             Vector3f.add(p8, pos, p8);
  2364.            
  2365.             boolean muff = true;
  2366.             String wank = "crit";
  2367.            
  2368.            
  2369.             /**
  2370.             FlansMod.proxy.spawnParticle(wank, p1.x,p1.y,p1.z, 0,0,0);
  2371.             FlansMod.proxy.spawnParticle(wank, p2.x,p2.y,p2.z, 0,0,0);
  2372.             FlansMod.proxy.spawnParticle(wank, p3.x,p3.y,p3.z, 0,0,0);
  2373.             FlansMod.proxy.spawnParticle(wank, p4.x,p4.y,p4.z, 0,0,0);
  2374.             FlansMod.proxy.spawnParticle(wank, p5.x,p5.y,p5.z, 0,0,0);
  2375.             FlansMod.proxy.spawnParticle(wank, p6.x,p6.y,p6.z, 0,0,0);
  2376.             FlansMod.proxy.spawnParticle(wank, p7.x,p7.y,p7.z, 0,0,0);
  2377.             FlansMod.proxy.spawnParticle(wank, p8.x,p8.y,p8.z, 0,0,0);
  2378.             */
  2379.             //renderTri(p1,p2,p3);
  2380.             //renderTri(p3,p4,p1);
  2381.             if(tester.nearestDistance < topFaceDist) tester.isOnTop = false;
  2382.            
  2383.            
  2384.             if(surface == 1) tester.isOnTop = true;
  2385.         }
  2386.  
  2387.     }
  2388.    
  2389.     public void renderTri(Vector3f p1, Vector3f p2, Vector3f p3)
  2390.     {
  2391.         Vector3f pos = new Vector3f (posX, posY, posZ);
  2392.         Vector3f p1a = Vector3f.add(p1, pos, null);
  2393.         Vector3f p2a = Vector3f.add(p2, pos, null);
  2394.         Vector3f p3a = Vector3f.add(p3, pos, null);
  2395.  
  2396.         renderLine(p1a,p2a);
  2397.         renderLine(p2a,p3a);
  2398.         renderLine(p3a,p1a);
  2399.     }
  2400.    
  2401.     public void renderLine(Vector3f in, Vector3f out)
  2402.     {
  2403.         float dx = out.x - in.x;
  2404.         float dy = out.y - in.y;
  2405.         float dz = out.z - in.z;
  2406.         Vector3f diff = Vector3f.sub(out, in, null);
  2407.         diff.normalise();
  2408.         float distance = (float)Math.sqrt((dx * dx) + (dy * dy) + (dz * dz));
  2409.         for(int i = 0; i < 10; i++)
  2410.         {
  2411.             float dist2 = (distance/10) * i;
  2412.             Vector3f newVec = new Vector3f(in.x + (dist2*diff.x),in.y + (dist2*diff.y), in.z + (dist2*diff.z));
  2413.             FlansMod.proxy.spawnParticle("reddust", newVec.x, newVec.y, newVec.z, 0, 0, 0);
  2414.         }
  2415.     }
  2416.    
  2417.  
  2418.     public Vector3f collideWithDriveable(CollisionTest tester, Vector3f Pos, Vector3f vel)
  2419.     {
  2420.         float unitScale = 1/16F;
  2421.         float veryCloseDistance = 0.005F * unitScale;
  2422.        
  2423.         if(tester.collisionRecursiveDepth > 2) return Pos;
  2424.        
  2425.         tester.basePoint = Pos;
  2426.         tester.didCollide = false;
  2427.        
  2428.         if(getDriveableType().fancyCollision)
  2429.         {
  2430.             //checkCollision(tester, getDriveableType().colbox);
  2431.             for(CollisionShapeBox sbox: getDriveableType().collisionBox)
  2432.             {
  2433.                 checkCollision(tester, sbox);
  2434.             }
  2435.         } else {
  2436.             for(DriveablePart ppart : getDriveableData().parts.values())
  2437.             {
  2438.                 ppart.rayTraceRider(this, tester);
  2439.             }
  2440.         }
  2441.        
  2442.         //If no collision, we just move along the velocity
  2443.         if(tester.didCollide = false) return Vector3f.add(Pos, vel, null);
  2444.        
  2445.        
  2446.         //Collision occured, time to sort this out
  2447.         Vector3f destinationPoint = Vector3f.add(Pos, vel, null);
  2448.         Vector3f newBasePoint = Pos;
  2449.        
  2450.         if(tester.nearestDistance >= veryCloseDistance)
  2451.         {
  2452.             Vector3f V = vel;
  2453.             V.normalise();
  2454.             V.scale((float)(tester.nearestDistance - veryCloseDistance));
  2455.             newBasePoint = Vector3f.add(tester.basePoint, V, null);
  2456.            
  2457.             if(V.normalise() == new Vector3f(0,0,0)) return Vector3f.add(Pos, vel, null);
  2458.            
  2459.             V.normalise();
  2460.            
  2461.             //Change polygon intersection point so that the sliding plane is unaffected by the fact we move slightly less than collision tells us
  2462.             Vector3f.sub(tester.intersectionPoint, new Vector3f(V.x * veryCloseDistance, V.y * veryCloseDistance, V.z * veryCloseDistance), tester.intersectionPoint);
  2463.         }
  2464.        
  2465.         //Determine the sliding plane
  2466.         Vector3f slidePlaneOrigin = tester.intersectionPoint;
  2467.         if(tester.intersectionPoint == null) return Vector3f.add(Pos, vel, null);
  2468.         Vector3f slidePlaneNormal = Vector3f.sub(newBasePoint, tester.intersectionPoint, null);
  2469.         slidePlaneNormal.normalise();
  2470.  
  2471.         tester.collisionPlaneNormal = slidePlaneNormal;
  2472.         CollisionPlane plane = new CollisionPlane(slidePlaneOrigin, slidePlaneNormal);
  2473.        
  2474.         double sDV = plane.signedDistanceTo(destinationPoint);
  2475.         Vector3f scaledNormal = new Vector3f(slidePlaneNormal.x * sDV, slidePlaneNormal.y * sDV, slidePlaneNormal.z * sDV);
  2476.         Vector3f newDestPoint = Vector3f.sub(destinationPoint, scaledNormal, null);
  2477.        
  2478.         //Generate slide vector
  2479.         Vector3f newVelocityVector = Vector3f.sub(newDestPoint, tester.intersectionPoint, null);
  2480.        
  2481.         if(newVelocityVector.length() < veryCloseDistance)
  2482.         {
  2483.             return newBasePoint;
  2484.         }
  2485.        
  2486.         tester.collisionRecursiveDepth++;
  2487.        
  2488.         return collideWithDriveable(tester, newBasePoint, newVelocityVector);
  2489.     }
  2490.    
  2491.     public void updateRiderPos (Entity rider, CollisionTest test, Vector3f pos, Vector3f motion)
  2492.     {
  2493.         boolean isDriveable = false;
  2494.         if(rider instanceof EntityDriveable) isDriveable = true;
  2495.         Vector3f vehicleMotion = lastPos;
  2496.        
  2497.         Vector3f riderMountPoint = new Vector3f(rider.posX - posX, rider.posY - posY, rider.posZ - posZ);
  2498.        
  2499.         float yawDiff = axes.getYaw() - prevAxes.getYaw();
  2500.         float pitchDiff = axes.getPitch() - prevAxes.getPitch();
  2501.         float rollDiff = axes.getRoll() - prevAxes.getRoll();
  2502.        
  2503.         RotatedAxes velAxes = new RotatedAxes(axes.getYaw() + yawDiff, axes.getPitch() + pitchDiff, axes.getRoll() + rollDiff);
  2504.        
  2505.         Vector3f currentLocalPos = axes.findGlobalVectorLocally(riderMountPoint);
  2506.         Vector3f nextGlobalPos = velAxes.findLocalVectorGlobally(currentLocalPos);
  2507.        
  2508.         Vector3f diff = new Vector3f(0,0,0);
  2509.        
  2510.         //Some rubbish null checks
  2511.         if(nextGlobalPos == null) nextGlobalPos = new Vector3f(0,0,0);
  2512.         if(diff == null) diff = new Vector3f(0,0,0);
  2513.        
  2514.         Vector3f.add(vehicleMotion, diff, diff);
  2515.         rider.setPosition(nextGlobalPos.x + posX + ((hugeBoat)?diff.x/(1.5):0), (!isDriveable)?rider.posY:((EntityDriveable)rider).deckHeight, nextGlobalPos.z + posZ + ((hugeBoat)?diff.z/(1.5):0));
  2516.  
  2517.                
  2518.         if(hugeBoat){
  2519.             if(lastPos.x == 0 && lastPos.y == 0 && lastPos.z == 0)
  2520.             {
  2521.                 rider.motionX = rider.motionX;
  2522.                 rider.motionY = rider.motionY;
  2523.                 rider.motionZ = rider.motionZ;
  2524.                 if(rider.motionY < 0) rider.motionY = 0;
  2525.             }
  2526.             else
  2527.             {
  2528.                 //rider.motionX = -rider.motionX + diff.x;
  2529.                 //rider.motionY = 0;
  2530.                 //rider.motionZ = -rider.motionZ + diff.z;
  2531.             }
  2532.        
  2533.         }
  2534.         else
  2535.         {
  2536.         if(lastPos.x == 0 && lastPos.y == 0 && lastPos.z == 0)
  2537.         {
  2538.             rider.motionX = rider.motionX;
  2539.             rider.motionY = rider.motionY;
  2540.             rider.motionZ = rider.motionZ;
  2541.         }
  2542.         else
  2543.         {
  2544.             rider.motionX = diff.x;
  2545.             rider.motionY = diff.y;
  2546.             rider.motionZ = diff.z;
  2547.         }
  2548.  
  2549.         }
  2550.        
  2551.     }
  2552.    
  2553.     public void handleVehicleCollision(EntityDriveable collided, CollisionTest test, Vector3f finalPos, boolean hugeBoat)
  2554.     {
  2555.        
  2556.     }
  2557.  
  2558.     /** Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit */
  2559.     public ArrayList<BulletHit> attackFromBullet(Vector3f origin, Vector3f motion)
  2560.     {
  2561.         //Make an array to contain the hits
  2562.         ArrayList<BulletHit> hits = new ArrayList<BulletHit>();
  2563.         //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates
  2564.         Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float)posX, (float)posY, (float)posZ), null);
  2565.         Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector);
  2566.         Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion);
  2567.         //Check each part
  2568.         for(DriveablePart part : getDriveableData().parts.values())
  2569.         {
  2570.             //Ray trace the bullet
  2571.             DriveableHit hit = part.rayTrace(this, rotatedPosVector, rotatedMotVector);
  2572.             if(hit != null)
  2573.                 hits.add(hit);
  2574.         }
  2575.         return hits;
  2576.     }
  2577.    
  2578.     /** Attack method called by bullets hitting the plane. Does advanced raytracing to detect which part of the plane is hit */
  2579.     public ArrayList<BulletHit> attackFromBulletButBetter(Vector3f origin, Vector3f motion, float size)
  2580.     {
  2581.         ArrayList<BulletHit> hits = new ArrayList<BulletHit>();
  2582.  
  2583.  
  2584.         Vector3f vehicleMotion = new Vector3f(posX - lastPos.x, posY - lastPos.y, posZ - lastPos.z);
  2585.         //riderMotion = Vector3f.sub(riderMotion, vehicleMotion, riderMotion);
  2586.         Vector3f vehiclePos = new Vector3f(this.posX, this.posY, this.posZ);
  2587.         Vector3f relativePos = Vector3f.sub(origin, vehiclePos, null);
  2588.  
  2589.         Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePos);
  2590.         Vector3f rotatedMotionVector = axes.findGlobalVectorLocally(motion);
  2591.        
  2592.         Vector3f ellipsoid = new Vector3f(size, size, size);
  2593.        
  2594.         CollisionTest test = new CollisionTest(ellipsoid, new Vector3f(relativePos.x, relativePos.y, relativePos.z), motion);
  2595.         test.collisionRecursiveDepth = 0;
  2596.        
  2597.         Vector3f eSpacePosition = test.ConvertR3ToESpace(test.R3Position);
  2598.         Vector3f eSpaceVelocity = test.velocity;
  2599.  
  2600.         for(DriveablePart ppart : getDriveableData().parts.values())
  2601.         {
  2602.             ppart.rayTraceRider(this, test);
  2603.         }
  2604.        
  2605.         if(test.didCollide)
  2606.         {
  2607.             Vector3f hitPos = new Vector3f(0,0,0);
  2608.             Vector3f intersect2 = new Vector3f(test.ConvertESpaceToR3(test.intersectionPoint));
  2609.             Vector3f.sub(origin, intersect2, hitPos);
  2610.             float f = (hitPos.length()/motion.length());
  2611.             DriveableHit hit = new DriveableHit(this, test.part, f);
  2612.             hits.add(hit);
  2613.         }
  2614.        
  2615.         return hits;
  2616.    
  2617.     }
  2618.  
  2619.     /** Called if the bullet actually hit the part returned by the raytrace
  2620.      * @param penetratingPower */
  2621.     public float bulletHit(EntityBullet bullet, DriveableHit hit, float penetratingPower)
  2622.     {
  2623.         DriveablePart part = getDriveableData().parts.get(hit.part);
  2624.         if(bullet != null && hit != null)
  2625.         part.hitByBullet(bullet, hit);
  2626.  
  2627.         //This is server side bsns
  2628.         if(!worldObj.isRemote)
  2629.         {
  2630.             checkParts();
  2631.             //If it hit, send a damage update packet
  2632.             FlansMod.getPacketHandler().sendToAllAround(new PacketDriveableDamage(this), posX, posY, posZ, 100, dimension);
  2633.         }
  2634.  
  2635.         return penetratingPower - 5F;
  2636.     }
  2637.  
  2638.     /** A simple raytracer for the driveable. Called by tools */
  2639.     public DriveablePart raytraceParts(Vector3f origin, Vector3f motion)
  2640.     {
  2641.         //Get the position of the bullet origin, relative to the centre of the plane, and then rotate the vectors onto local co-ordinates
  2642.         Vector3f relativePosVector = Vector3f.sub(origin, new Vector3f((float)posX, (float)posY, (float)posZ), null);
  2643.         Vector3f rotatedPosVector = axes.findGlobalVectorLocally(relativePosVector);
  2644.         Vector3f rotatedMotVector = axes.findGlobalVectorLocally(motion);
  2645.         //Check each part
  2646.         for(DriveablePart part : getDriveableData().parts.values())
  2647.         {
  2648.             //Ray trace the bullet
  2649.             if(part.rayTrace(this, rotatedPosVector, rotatedMotVector) != null)
  2650.             {
  2651.                 return part;
  2652.             }
  2653.         }
  2654.         return null;
  2655.     }
  2656.  
  2657.     /** For overriding for toggles such as gear up / down on planes */
  2658.     public boolean canHitPart(EnumDriveablePart part)
  2659.     {
  2660.         return true;
  2661.     }
  2662.  
  2663.     /** 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 */
  2664.     public void checkParts()
  2665.     {
  2666.         for(DriveablePart part : getDriveableData().parts.values())
  2667.         {
  2668.             if(part != null && !part.dead && part.health <= 0 && part.maxHealth > 0)
  2669.             {
  2670.                 killPart(part);
  2671.             }
  2672.         }
  2673.  
  2674.  
  2675.         for(EntitySeat seat : seats)
  2676.         {
  2677.  
  2678.         }
  2679.  
  2680.         //If the core was destroyed, kill the driveable
  2681.         if(getDriveableData().parts.get(EnumDriveablePart.core).dead)
  2682.         {
  2683.             int seatNum = seats.length;
  2684.  
  2685.             DriveableType type = getDriveableType();
  2686.             //Entity entityNum[] = new Entity[seatNum];
  2687.             //EntityPlayer entityPlayerPotion;
  2688.  
  2689.             if(!worldObj.isRemote)
  2690.             {
  2691.                 for(int i = 0; i<seatNum; i++){
  2692.                     if(seats[i].riddenByEntity != null && seats[i].riddenByEntity instanceof EntityPlayer)
  2693.                     {
  2694. //                      ((EntityPlayer)seats[i].riddenByEntity).addPotionEffect(new PotionEffect(Potion.harm.id, 10, 5));
  2695.                         Entity entity = seats[i].riddenByEntity;
  2696.                         seats[i].riddenByEntity.mountEntity(null);
  2697.                         if(this.lastAtkEntity instanceof EntityPlayer)
  2698.                         {
  2699.                             entity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) this.lastAtkEntity), 10000000);
  2700.                         }
  2701.                         else if(this.lastAtkEntity instanceof EntityLivingBase)
  2702.                         {
  2703.                             entity.attackEntityFrom(DamageSource.causeMobDamage((EntityLivingBase) this.lastAtkEntity), 10000000);
  2704.                         }
  2705.                     }
  2706.                 }
  2707.  
  2708.                 if(type.isExplosionWhenDestroyed)
  2709.                     this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, 4, false);//Explosion when vehicle is destroyed
  2710.  
  2711.  
  2712.                 for(DriveablePart part : driveableData.parts.values())
  2713.                 {
  2714.                     if(part.health > 0 && !part.dead)
  2715.                         killPart(part);
  2716.                 }
  2717.             }
  2718.             setDead();
  2719.  
  2720.         }
  2721.  
  2722.     }
  2723.  
  2724.     public void checkPartsWhenAttacked(){
  2725.         for(DriveablePart part : getDriveableData().parts.values())
  2726.         {
  2727.             if(part != null && !part.dead && part.health <= 0 && part.maxHealth > 0)
  2728.             {
  2729.                 killPart(part);
  2730.             }
  2731.         }
  2732.     }
  2733.  
  2734.     /** Internal method for killing driveable parts */
  2735.     private void killPart(DriveablePart part)
  2736.     {
  2737.         if(part.dead)
  2738.             return;
  2739.         part.health = 0;
  2740.         part.dead = true;
  2741.  
  2742.         //Drop items
  2743.         DriveableType type = getDriveableType();
  2744.         if(!worldObj.isRemote)
  2745.         {
  2746.             Vector3f pos = new Vector3f(0, 0, 0);
  2747.  
  2748.             //Get the midpoint of the part
  2749.             if(part.box != null)
  2750.                 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));
  2751.  
  2752.             ArrayList<ItemStack> drops = type.getItemsRequired(part, getDriveableData().engine);
  2753.             if(drops != null)
  2754.             {
  2755.                 //Drop each itemstack
  2756.                 for(ItemStack stack : drops)
  2757.                 {
  2758.                     worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + pos.x, posY + pos.y, posZ + pos.z, stack.copy()));
  2759.                 }
  2760.             }
  2761.             dropItemsOnPartDeath(pos, part);
  2762.  
  2763.             //Inventory is in the core, so drop it if the core is broken
  2764.             if(part.type == EnumDriveablePart.core)
  2765.             {
  2766.                 for(int i = 0; i < getDriveableData().getSizeInventory(); i++)
  2767.                 {
  2768.                     ItemStack stack = getDriveableData().getStackInSlot(i);
  2769.                     if(stack != null)
  2770.                     {
  2771.                         worldObj.spawnEntityInWorld(new EntityItem(worldObj, posX + rand.nextGaussian(), posY + rand.nextGaussian(), posZ + rand.nextGaussian(), stack));
  2772.                     }
  2773.                 }
  2774.             }
  2775.         }
  2776.  
  2777.         //Kill all child parts to stop things floating unconnected
  2778.         for(EnumDriveablePart child : part.type.getChildren())
  2779.         {
  2780.             killPart(getDriveableData().parts.get(child));
  2781.         }
  2782.     }
  2783.  
  2784.     /** Method for planes, vehicles and whatnot to drop their own specific items if they wish */
  2785.     protected abstract void dropItemsOnPartDeath(Vector3f midpoint, DriveablePart part);
  2786.  
  2787.     @Override
  2788.     public float getPlayerRoll()
  2789.     {
  2790.         return axes.getRoll();
  2791.     }
  2792.  
  2793.     @Override
  2794.     public void explode()
  2795.     {
  2796.  
  2797.     }
  2798.  
  2799.     @Override
  2800.     public float getCameraDistance()
  2801.     {
  2802.         return getDriveableType().cameraDistance;
  2803.     }
  2804.  
  2805.     public boolean isPartIntact(EnumDriveablePart part)
  2806.     {
  2807.         DriveablePart thisPart = getDriveableData().parts.get(part);
  2808.         return thisPart.maxHealth == 0 || thisPart.health > 0;
  2809.     }
  2810.  
  2811.     public abstract boolean hasMouseControlMode();
  2812.  
  2813.     public abstract String getBombInventoryName();
  2814.  
  2815.     public abstract String getMissileInventoryName();
  2816.  
  2817.     public boolean rotateWithTurret(Seat seat)
  2818.     {
  2819.         return seat.part == EnumDriveablePart.turret;
  2820.     }
  2821.  
  2822.     @Override
  2823.     public String getCommandSenderName()
  2824.     {
  2825.         return getDriveableType().name;
  2826.     }
  2827.  
  2828.     @SideOnly(Side.CLIENT)
  2829.     public boolean showInventory(int seat)
  2830.     {
  2831.         return seat != 0 || !FlansModClient.controlModeMouse;
  2832.     }
  2833.  
  2834.     //-------------------------------------
  2835.     // Getters and setters for dual fields
  2836.     //-------------------------------------
  2837.  
  2838.     public int getShootDelay(boolean secondary)
  2839.     {
  2840.         return secondary ? shootDelaySecondary : shootDelayPrimary;
  2841.     }
  2842.    
  2843.     public boolean canLaunchIT1()
  2844.     {
  2845.         return canFireIT1;
  2846.     }
  2847.  
  2848.     public float getMinigunSpeed(boolean secondary)
  2849.     {
  2850.         return secondary ? minigunSpeedSecondary : minigunSpeedPrimary;
  2851.     }
  2852.  
  2853.     public int getCurrentGun(boolean secondary)
  2854.     {
  2855.         return secondary ? currentGunSecondary : currentGunPrimary;
  2856.     }
  2857.  
  2858.     public void setShootDelay(int i, boolean secondary)
  2859.     {
  2860.         setRecoilTimer();
  2861.         if(secondary)
  2862.             shootDelaySecondary = i > shootDelaySecondary? i : shootDelaySecondary;
  2863.         else
  2864.             shootDelayPrimary   = i > shootDelayPrimary?   i : shootDelayPrimary;
  2865.     }
  2866.  
  2867.     public void setMinigunSpeed(float f, boolean secondary)
  2868.     {
  2869.         if(secondary)
  2870.             minigunSpeedSecondary = f;
  2871.         else minigunSpeedPrimary = f;
  2872.     }
  2873.  
  2874.     public void setCurrentGun(int i, boolean secondary)
  2875.     {
  2876.         if(secondary)
  2877.             currentGunSecondary = i;
  2878.         else currentGunPrimary = i;
  2879.     }
  2880.  
  2881.     public void setEntityMarker(int tick)
  2882.     {
  2883.         this.isShowedPosition = true;
  2884.         this.tickCount = tick;
  2885.     }
  2886.  
  2887.     public void lock(String tool, EntityPlayer player){
  2888.         if(key == "ChangeMe"){
  2889.             key = tool;
  2890.             player.addChatMessage(new ChatComponentText("Registered key"));
  2891.         }else if(tool == key){
  2892.         player.addChatMessage(new ChatComponentText("Locked"));
  2893.         } else {
  2894.         player.addChatMessage(new ChatComponentText(key));         
  2895.         }
  2896.     }
  2897.    
  2898.     public void IT1Reload()
  2899.     {
  2900.         DriveableType type = getDriveableType();
  2901.        
  2902.        
  2903.         if(stage == 1)
  2904.         {
  2905.             //canFireIT1 = false;
  2906.             drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 5);
  2907.             drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3);
  2908.             drakonRailAngle = moveToTarget(drakonRailAngle, -10, 5);
  2909.            
  2910.             if(drakonRailAngle == -10) stage++;
  2911.         }
  2912.        
  2913.        
  2914.         if(stage == 2)
  2915.         {
  2916.             drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5);
  2917.             drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3);
  2918.             drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1);
  2919.            
  2920.             if(drakonDoorAngle == -90) stage++;
  2921.         }
  2922.        
  2923.         if(stage == 3)
  2924.         {
  2925.             drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5);
  2926.             drakonArmAngle = moveToTarget(drakonArmAngle, 179, 3);
  2927.             drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1);
  2928.            
  2929.             if(drakonArmAngle == 179) stage++;
  2930.         }
  2931.        
  2932.         if(stage == 4)
  2933.         {
  2934.             drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10);
  2935.             drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3);
  2936.             drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1);
  2937.            
  2938.             if(drakonDoorAngle == 0)
  2939.             {
  2940.                 if(IT1Loaded())
  2941.                 {
  2942.                     stage++;
  2943.                     reloadAnimTime = 60;
  2944.                 }
  2945.             }
  2946.         }
  2947.        
  2948.         if(stage == 5)
  2949.         {
  2950.             drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 10);
  2951.             drakonArmAngle = moveToTarget(drakonArmAngle, 180, 3);
  2952.             drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1);
  2953.             reloadingDrakon = true;
  2954.            
  2955.             if(drakonDoorAngle == -90) stage++;
  2956.         }
  2957.        
  2958.         if(stage == 6)
  2959.         {
  2960.             drakonDoorAngle = moveToTarget(drakonDoorAngle, -90, 5);
  2961.             drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3);
  2962.             drakonRailAngle = moveToTarget(drakonRailAngle, -10, 1);
  2963.            
  2964.             if(drakonArmAngle == 00) stage++;
  2965.         }
  2966.        
  2967.         if(stage == 7)
  2968.         {
  2969.             drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10);
  2970.             drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3);
  2971.             drakonRailAngle = moveToTarget(drakonRailAngle, 0, 1);
  2972.            
  2973.             if(drakonRailAngle == 0 && drakonDoorAngle == 0)
  2974.             {
  2975.                 stage++;
  2976.                 canFireIT1 = true;
  2977.                 reloadingDrakon = false;
  2978.             }
  2979.         }
  2980.        
  2981.         if(stage == 8)
  2982.         {
  2983.             drakonDoorAngle = moveToTarget(drakonDoorAngle, 0, 10);
  2984.             drakonArmAngle = moveToTarget(drakonArmAngle, 0, 3);
  2985.             if(worldObj.isRemote && this.ticksExisted > 2)
  2986.             drakonRailAngle = moveToTarget(drakonRailAngle,-seats[0].looking.getPitch(), seats[0].seatInfo.aimingSpeed.y);
  2987.             //reloadAnimTime = 60;
  2988.            
  2989.             if(!IT1Loaded()){ stage = 1; canFireIT1 = false;}
  2990.         }
  2991.     }
  2992.    
  2993.     public float moveToTarget(float current, float target, float speed)
  2994.     {  
  2995.        
  2996.         float pitchToMove = (float)((Math.sqrt(target*target)) - Math.sqrt((current*current)));
  2997.         for(; pitchToMove > 180F; pitchToMove -= 360F) {}
  2998.         for(; pitchToMove <= -180F; pitchToMove += 360F) {}
  2999.        
  3000.         float signDeltaY = 0;
  3001.         if(pitchToMove > speed){
  3002.             signDeltaY = 1;
  3003.         } else if(pitchToMove < -speed){
  3004.             signDeltaY = -1;
  3005.         } else {
  3006.             signDeltaY = 0;
  3007.             return target;
  3008.         }
  3009.        
  3010.        
  3011.         if(current > target)
  3012.         {
  3013.             current = current - speed;
  3014.         }
  3015.        
  3016.         else if(current < target)
  3017.         {
  3018.             current = current + speed;
  3019.         }
  3020.        
  3021.        
  3022.        
  3023.         return current;
  3024.     }
  3025.    
  3026.     public boolean IT1Loaded()
  3027.     {
  3028.         DriveableType type = getDriveableType();
  3029.         boolean loaded = false;
  3030.         for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++)
  3031.         {
  3032.             ItemStack shell = driveableData.getStackInSlot(i);
  3033.             if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)shell.getItem()).type, EnumWeaponType.MISSILE))
  3034.             {
  3035.                 loaded = true;
  3036.             }
  3037.         }
  3038.        
  3039.         return loaded;
  3040.     }
  3041.    
  3042.     public void tryRecoil()
  3043.     {
  3044.         int slot = -1;
  3045.         DriveableType type = getDriveableType();
  3046.         for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++)
  3047.         {
  3048.             ItemStack shell = driveableData.getStackInSlot(i);
  3049.             if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)shell.getItem()).type, EnumWeaponType.SHELL))
  3050.             {
  3051.                 slot = i;
  3052.             }
  3053.         }
  3054.  
  3055.         if(recoilTimer <= 0 && slot != -1)
  3056.         isRecoil = true;
  3057.     }
  3058.    
  3059.     public void setRecoilTimer()
  3060.     {
  3061.         int slot = -1;
  3062.         DriveableType type = getDriveableType();
  3063.         for(int i = driveableData.getMissileInventoryStart(); i < driveableData.getMissileInventoryStart() + type.numMissileSlots; i++)
  3064.         {
  3065.             ItemStack shell = driveableData.getStackInSlot(i);
  3066.             if(shell != null && shell.getItem() instanceof ItemBullet && type.isValidAmmo(((ItemBullet)shell.getItem()).type, EnumWeaponType.SHELL))
  3067.             {
  3068.                 slot = i;
  3069.             }
  3070.         }
  3071.  
  3072.         if(recoilTimer <= 0 && slot != -1)
  3073.         recoilTimer = getDriveableType().shootDelayPrimary;
  3074.     }
  3075.  
  3076.     public void unlock(String tool, EntityPlayer player){
  3077.         if(key == "ChangeMe"){
  3078.             key = tool;
  3079.             player.addChatMessage(new ChatComponentText("Registered key"));
  3080.         } else if(tool == key){
  3081.         player.addChatMessage(new ChatComponentText("Unlocked"));
  3082.         } else {
  3083.             player.addChatMessage(new ChatComponentText(key));         
  3084.         }
  3085.     }
  3086.  
  3087.  
  3088. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement