Advertisement
Whiplash141

Whip's OGM Code - JDAM functionality

Dec 3rd, 2016
611
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 40.42 KB | None | 0 0
  1. /*  
  2. Whip's Optical Missile Guidance System v61 - revised: 10/20/16  
  3. /// PUBLIC RELEASE ///  
  4. /// Stable ///
  5. _______________________________________________________________________          
  6. ///DESCRIPTION///    
  7.     This script allows the user to manually guide a missile with the
  8.     heading of his/her ship! The missiles will behave similar to a TOW missile.
  9. _______________________________________________________________________          
  10. ///FEATURES///
  11.     * Configurable spiral trajectory to avoid turrets! (can be turned off)
  12.     * Configurable detach sequence parameters!
  13.     * Automatic thruster orientation detection! No more pesky directional naming needed :D
  14.     * Works in atmosphere!
  15.     * Runs at 10 Hz (old was 60 Hz) so it is much less laggy! SIX new missiles lag less than ONE of my old ones!
  16.     * Compensates for unwanted drift!
  17.     * Automatically shuts off and goes ballistic if vital components are damaged
  18.     * Safety mechanisms to stop the missile from flying up your tail pipe!
  19. ____________________________________________________________          
  20. ///MISSILE SETUP INSTRUCTIONS///
  21.  
  22. ===REQUIRED BLOCKS===
  23.     * A timer
  24.     * A Remote Control pointing FORWARD
  25.     * A program block with this code
  26.     * A battery or reactor (for power)
  27.     * A merge, connector, or rotor (for attachment points)
  28.     * A gyroscope pointing forward
  29.  
  30.     OPTIONAL BLOCKS:
  31.     * An artificial mass block
  32.     * A beacon
  33.     * An antenna
  34.  
  35.     ALL BLOCKS on the missile should have the name tag "Missile 1" added in their names.
  36.  
  37. ===ADDITIONAL NAME TAGS===
  38.     Some specific blocks need ADDITIONAL name tags
  39.  
  40.     * Any detach thrusters need the name tag "Detach" in addition to the missile tag
  41.  
  42. ===TIMER SETUP===
  43.     The timer should be set to:
  44.     * "Start" itself
  45.     * "Trigger Now" itself
  46.     * "Run" the missile program with the argument "fire"
  47. ______________________________________________________________________          
  48. ///SHOOTER SHIP SETUP///
  49.  
  50.     The shooter ship needs:
  51.     * A remote with name tag "Shooter Reference" pointing in the direction you eant the missile to fly.
  52.     * A method to connect to the missile (merge, rotor, or connector)
  53. ______________________________________________________________________          
  54. ///FIRING INSTRUCTIONS///
  55.  
  56.     The missile must be physically attached to the shooter ship before firing.
  57.     To fire the missile, simply trigger the missile timer :)
  58.  
  59. ______________________________________________________________________          
  60. ///TROUBLESHOOTING///
  61.  
  62.     Find the program block in the ship terminal to check if the code detects any errors.
  63.  
  64.     Before firing, type "setup" in the argument field of the program block and hit "run".  
  65.     This will tell you if any vital components are missing!
  66.  
  67. ______________________________________________________________________          
  68. ///AUTHOR'S NOTES///
  69.  
  70.     Make sure to look at the configurable variables in the section below and tweak them to your liking!
  71.  
  72.     I have spent a ton of time trying to make this code better than the previous iteration.
  73.     I hope y'all enjoy :D
  74.  
  75. Code by Whiplash141 :)
  76. */
  77.  
  78. /*
  79. ___________________________________________________________________  
  80.  
  81. ///////////////CONFIGURABLE VARIABLES/////////////////  
  82.  
  83. ========== You can edit these variables to your liking ============    
  84. ___________________________________________________________________    
  85. */
  86.  
  87. //---Missile Name Tags  
  88.     const string missileNumber = "1";
  89.     string missileTag = "Missile " + missileNumber; //(MANDATORY) unique id of the missile    
  90.     const string detachThrustTag = "Detach"; //(Optional) tag on detach thrust
  91.  
  92. //---Reference Name Tags
  93.     const string shooterReferenceName = "Shooter Reference"; //name of the remote on the shooter vessel
  94.  
  95. //---Runtime variables
  96.     const double updatesPerSecond = 10; // self explanatory :P
  97.  
  98. //---Missile Detach Parameters
  99.     const double disconnectDelay = 1; //time (in seconds) that the missile will delay disconnection from firing ship
  100.  
  101.     const double guidanceDelay = 2; // time (in seconds) that the missile will delay guidance activation by
  102.  
  103.     const double detachDuration = 1;
  104.         // time that the missile will execute detach. During the detach function, the missile
  105.         // will use its detach thrusters and any artificial mass it detects to detach from the ship.
  106.         // Setting this to ZERO will skip this feature and move on to the main ignition delay stage.
  107.  
  108.     const double mainIgnitionDelay = 1;
  109.         // time (in seconds) that the missile will delay main engine activation AFTER the
  110.         // detach function has finished. During this time, the missile will drift without
  111.         // any thrusters firing. Set this to ZERO if you do not want this :)
  112.  
  113. //---Drift Compensation Parameters
  114.     const bool driftCompensation = true;
  115.         // this determines if the missile will negate unwanted drift. This allows you to make a  
  116.         // missile using just forward thrust!
  117.  
  118. //---Spiral Trajectory Parameters
  119.     bool enableSpiralTrajectory = true; //determines if missiles will spiral to avoid turret fire
  120.     const double spiralDegrees = 5; // angular deviation of the spiral pattern  
  121.     const double timeMaxSpiral = 3; // time it takes the missile to complete a full spiral cycle
  122.  
  123. //---Rotation speed control system
  124.     const double proportionalConstant = 5; // proportional gain of gyroscopes
  125.     const double derivativeConstant = 2; // derivative gain of gyroscopes
  126.    
  127. //---Missile impact point offsets
  128.     const double offsetUp = 0; // (in meters) Positive numbers offset up, negative offset down
  129.     const double offsetLeft = 0; // (in meters) Positive numbers offset left, negative offset right
  130.    
  131. //---Missile spin parameters
  132.     const double missileSpinRPM = 0; //this specifies how fast the missile will spin when flying(only in space)
  133.    
  134. //---Missile guidance parameters
  135.     bool lockVector = true; //this will lock the vector on launch
  136.  
  137. /*    
  138. ___________________________________________________________________    
  139.  
  140. ============= Don't touch anything below this :) ==================    
  141. ___________________________________________________________________    
  142. */
  143. //---So many lists...
  144.     List<IMyTerminalBlock> missileBlocks = new List<IMyTerminalBlock>();
  145.     List<IMyTerminalBlock> unsortedThrusters = new List<IMyTerminalBlock>();
  146.     List<IMyTerminalBlock> mainThrusters = new List<IMyTerminalBlock>();
  147.     List<IMyTerminalBlock> sideThrusters = new List<IMyTerminalBlock>();
  148.     List<IMyTerminalBlock> detachThrusters = new List<IMyTerminalBlock>();
  149.     List<IMyTerminalBlock> artMasses = new List<IMyTerminalBlock>();
  150.     List<IMyTerminalBlock> mergeBlocks = new List<IMyTerminalBlock>();
  151.     List<IMyTerminalBlock> batteries = new List<IMyTerminalBlock>();
  152.     List<IMyTerminalBlock> remotes = new List<IMyTerminalBlock>();
  153.     List<IMyTerminalBlock> shooterReferenceList = new List<IMyTerminalBlock>();
  154.     List<IMyTerminalBlock> shooterTurretReferenceList = new List<IMyTerminalBlock>();
  155.     List<IMyTerminalBlock> gyros = new List<IMyTerminalBlock>();
  156.     List<IMyTerminalBlock> timers = new List<IMyTerminalBlock>();
  157.     List<IMyTerminalBlock> programs = new List<IMyTerminalBlock>();
  158.     List<IMyTerminalBlock> importantBlocks = new List<IMyTerminalBlock>();
  159.     List<IMyTerminalBlock> connectors = new List<IMyTerminalBlock>();
  160.     List<IMyTerminalBlock> rotors = new List<IMyTerminalBlock>();
  161.     List<IMyTerminalBlock> reactors = new List<IMyTerminalBlock>();
  162.     List<IMyTerminalBlock> antennas = new List<IMyTerminalBlock>();
  163.     List<IMyTerminalBlock> beacons = new List<IMyTerminalBlock>();
  164.     List<IMyTerminalBlock> sensors = new List<IMyTerminalBlock>();
  165.     List<IMyTerminalBlock> warheads = new List<IMyTerminalBlock>();
  166.  
  167. //---Yo dawg... I heard u like vectors...
  168.     Vector3D shooterForwardVec;
  169.     Vector3D shooterLeftVec;
  170.     Vector3D shooterUpVec;
  171.     Vector3D originPos;
  172.     Vector3D missilePos;
  173.     Vector3D headingVec;
  174.     Vector3D destinationVec;
  175.     Vector3D gravVec;
  176.  
  177. //---These are kinda super important
  178.     IMyTerminalBlock shooterReference = null;
  179.     IMyRemoteControl missileReference = null;
  180.  
  181. //---These booleans track the status of the missile
  182.     bool isSetup = false;
  183.     bool setupFailed = false;
  184.     bool firstRun = true;
  185.     bool shouldKill = false;
  186.     bool firstGuidance = true;
  187.     bool hasPassed = false;
  188.     bool killAllowed = false;
  189.     bool inGravity = false;
  190.     bool controlGyros = true;
  191.     bool missileStage1 = false;
  192.     bool missileStage2 = false;
  193.     bool missileStage3 = false;
  194.     bool missileStage4 = false;
  195.  
  196. //---Store all this important stuff for computations between methods
  197.     double distanceFromShooter;
  198.     double max_kill_time = 3;
  199.     double kill_time = 0;
  200.     double timeElapsed = 0; //time elapsed over current iterations  
  201.     double timeTotal = 0; //total time program has been running  
  202.     double lastYawAngle = 0;
  203.     double lastPitchAngle = 0;
  204.     double lastRollAngle = 0;
  205.  
  206.     static double max_distance = 10000; //static b/c we change it on kill command
  207.     const double degToRad = Math.PI / 180;
  208.     const double radToDeg = 180 / Math.PI;
  209.     const double max_time_to_guide = 300; //in seconds  
  210.     const double timeLimit = 1 / updatesPerSecond;
  211.  
  212. void Main(string arg)
  213. {
  214.     if (arg.ToLower() == "fire")
  215.     {
  216.         if (!isSetup)
  217.         {
  218.             GrabBlocks();
  219.         }
  220.         else //will not run or release missile until has run setup succesfully    
  221.         {
  222.             if (firstRun)
  223.             {
  224.                 timeElapsed = 0;
  225.                 timeTotal = 0;
  226.                 firstRun = false;
  227.             }
  228.             else
  229.             {
  230.                 timeElapsed += Runtime.TimeSinceLastRun.TotalSeconds;
  231.                 timeTotal += Runtime.TimeSinceLastRun.TotalSeconds;
  232.                 timeSpiral += Runtime.TimeSinceLastRun.TotalSeconds;
  233.             }
  234.  
  235.             LaunchMissile();
  236.             StatusCheck();
  237.  
  238.             if (timeTotal >= guidanceDelay && timeElapsed >= timeLimit)
  239.             {
  240.                 Echo("WMI Optical Missile Guidance System Active..."); Echo("Run Time: " + Math.Round(timeTotal).ToString());
  241.                 GuideMissile();
  242.                 timeElapsed = 0;
  243.             }
  244.         }
  245.     }
  246.     else if (arg.ToLower() == "setup")
  247.     {
  248.         GrabBlocks();
  249.     }
  250.     else if (arg.ToLower() == "kill" && killAllowed)
  251.     {
  252.         shouldKill = true;
  253.         max_distance = double.PositiveInfinity;
  254.     }
  255.  
  256.     if (timeTotal > max_time_to_guide)
  257.     {
  258.         shouldKill = true;
  259.         max_distance = double.PositiveInfinity;
  260.     }
  261. }
  262.  
  263. bool isRemote(IMyTerminalBlock block)
  264. {
  265.     var remoteTest = block as IMyRemoteControl;
  266.     return remoteTest != null;
  267. }
  268.  
  269. bool isTurret(IMyTerminalBlock block)
  270. {
  271.     var testTurret = block as IMyLargeTurretBase;
  272.     return testTurret != null;
  273. }
  274.  
  275. void ClearLists()
  276. {
  277.     missileBlocks.Clear();
  278.     unsortedThrusters.Clear();
  279.     mainThrusters.Clear();
  280.     sideThrusters.Clear();
  281.     detachThrusters.Clear();
  282.     artMasses.Clear();
  283.     mergeBlocks.Clear();
  284.     batteries.Clear();
  285.     remotes.Clear();
  286.     shooterReferenceList.Clear();
  287.     shooterTurretReferenceList.Clear();
  288.     gyros.Clear();
  289.     timers.Clear();
  290.     programs.Clear();
  291.     importantBlocks.Clear();
  292.     connectors.Clear();
  293.     rotors.Clear();
  294.     reactors.Clear();
  295.     antennas.Clear();
  296.     beacons.Clear();
  297.     sensors.Clear();
  298.     warheads.Clear();
  299. }
  300.  
  301. void GrabBlocks()
  302. {
  303.     ClearLists();
  304.    
  305.     setupFailed = false;
  306.    
  307.     GridTerminalSystem.SearchBlocksOfName(missileTag, missileBlocks);
  308.     GridTerminalSystem.SearchBlocksOfName(shooterReferenceName, shooterReferenceList, isRemote);
  309.     GridTerminalSystem.SearchBlocksOfName(shooterReferenceName, shooterTurretReferenceList, isTurret);
  310.  
  311.     for (int i = 0; i < shooterReferenceList.Count; i++)
  312.     {
  313.         importantBlocks.Add(shooterReferenceList[i]);
  314.     }
  315.  
  316.     for (int i = 0; i < shooterTurretReferenceList.Count; i++)
  317.     {
  318.         importantBlocks.Add(shooterTurretReferenceList[i]);
  319.     }
  320.  
  321.     //---Sort through all blocks with the missile tag
  322.     for (int i = 0; i < missileBlocks.Count; i++)
  323.     {
  324.         var thisBlock = missileBlocks[i] as IMyTerminalBlock;
  325.  
  326.         if (thisBlock is IMyThrust)
  327.         {
  328.             if (thisBlock.CustomName.Contains(detachThrustTag))
  329.             {
  330.                 detachThrusters.Add(thisBlock);
  331.                 unsortedThrusters.Add(thisBlock);
  332.             }
  333.             else {
  334.                 unsortedThrusters.Add(thisBlock);
  335.             }
  336.         }
  337.         else if (thisBlock is IMyVirtualMass)
  338.         {
  339.             artMasses.Add(thisBlock);
  340.         }
  341.         else if (thisBlock is IMyBatteryBlock)
  342.         {
  343.             batteries.Add(thisBlock);
  344.         }
  345.         else if (thisBlock is IMyGyro)
  346.         {
  347.             gyros.Add(thisBlock);
  348.             importantBlocks.Add(thisBlock);
  349.         }
  350.         else if (thisBlock is IMyShipMergeBlock)
  351.         {
  352.             mergeBlocks.Add(thisBlock);
  353.         }
  354.         else if (thisBlock is IMyTimerBlock)
  355.         {
  356.             timers.Add(thisBlock);
  357.             importantBlocks.Add(thisBlock);
  358.         }
  359.         else if (thisBlock is IMyProgrammableBlock)
  360.         {
  361.             programs.Add(thisBlock);
  362.             importantBlocks.Add(thisBlock);
  363.         }
  364.         else if (thisBlock is IMyRemoteControl)
  365.         {
  366.             remotes.Add(thisBlock);
  367.         }
  368.         else if (thisBlock is IMyShipConnector)
  369.         {
  370.             connectors.Add(thisBlock);
  371.         }
  372.         else if (thisBlock is IMyMotorStator)
  373.         {
  374.             rotors.Add(thisBlock);
  375.         }
  376.         else if (thisBlock is IMyReactor)
  377.         {
  378.             reactors.Add(thisBlock);
  379.         }
  380.         else if (thisBlock is IMyRadioAntenna)
  381.         {
  382.             antennas.Add(thisBlock);
  383.         }
  384.         else if (thisBlock is IMyBeacon)
  385.         {
  386.             beacons.Add(thisBlock);
  387.         }
  388.         else if (thisBlock is IMySensorBlock)
  389.         {
  390.             sensors.Add(thisBlock);
  391.         }
  392.         else if (thisBlock is IMyWarhead)
  393.         {
  394.             warheads.Add(thisBlock);
  395.         }
  396.     }
  397.  
  398.     Echo("Setup results for Missile " + missileNumber);
  399.     //---Check what we have and display any missing blocks
  400.     if (artMasses.Count == 0)
  401.     {
  402.         Echo("[OPTIONAL] No artificial masses found");
  403.     }
  404.    
  405.     if (sensors.Count == 0)
  406.     {
  407.         Echo("[OPTIONAL] No sensors found");
  408.     }
  409.    
  410.     if (warheads.Count == 0)
  411.     {
  412.         Echo("[OPTIONAL] No warheads found");
  413.     }
  414.  
  415.     if (beacons.Count == 0)
  416.     {
  417.         Echo("[OPTIONAL] No beacons found");
  418.     }
  419.  
  420.     if (antennas.Count == 0)
  421.     {
  422.         Echo("[OPTIONAL] No antennas found");
  423.     }
  424.  
  425.     if (shooterReferenceList.Count == 0 && shooterTurretReferenceList.Count == 0)
  426.     {
  427.         Echo("[FAILED] No remote or turret named '" + shooterReferenceName + "'found");
  428.         setupFailed = true;
  429.     }
  430.  
  431.     if (gyros.Count == 0)
  432.     {
  433.         Echo("[FAILED] No control gyros found");
  434.         setupFailed = true;
  435.     }
  436.  
  437.     if (remotes.Count == 0)
  438.     {
  439.         Echo("[FAILED] No remotes found");
  440.         setupFailed = true;
  441.     }
  442.     else
  443.     {
  444.         GetThrusterOrientation(remotes[0]);
  445.     }
  446.  
  447.     if (sideThrusters.Count == 0)
  448.     {
  449.         Echo("[OPTIONAL] No side thrusters found");
  450.     }
  451.  
  452.     if (detachThrusters.Count == 0)
  453.     {
  454.         Echo("[OPTIONAL] No detach thrusters found");
  455.     }
  456.  
  457.     if (mainThrusters.Count == 0)
  458.     {
  459.         if (!lockVector)
  460.         {      
  461.             Echo("[FAILED] No main thrusters found");
  462.             setupFailed = true;
  463.         }
  464.         else
  465.             Echo("[OPTIONAL] No main thrusters found");
  466.     }
  467.  
  468.     if (batteries.Count == 0 && reactors.Count == 0)
  469.     {
  470.         Echo("[FAILED] No batteries or reactors found");
  471.         setupFailed = true;
  472.     }
  473.  
  474.     if (mergeBlocks.Count == 0 && rotors.Count == 0 && connectors.Count == 0)
  475.     {
  476.         Echo("[FAILED] No merge blocks, rotors, or connectors found");
  477.         setupFailed = true;
  478.     }
  479.  
  480.     if (!setupFailed)
  481.     {
  482.         Echo("[SUCCESS] Ready to run");
  483.        
  484.         if (shooterReferenceList.Count != 0)
  485.             shooterReference = shooterReferenceList[0];
  486.         else
  487.             shooterReference = shooterTurretReferenceList[0];
  488.        
  489.         //---Get orientation vectors of our shooter vessel    
  490.         if (lockVector)
  491.         {
  492.             if (shooterReference is IMyLargeTurretBase)
  493.             {
  494.                 var turret = shooterReference as IMyLargeTurretBase;
  495.                 double azimuth = (double)turret.Azimuth;
  496.                 double elevation = (double)turret.Elevation;
  497.                
  498.                 var turretHeading = VectorAzimuthElevation(azimuth, elevation);
  499.                 shooterForwardVec = shooterReference.WorldMatrix.Forward * turretHeading.X + shooterReference.WorldMatrix.Left * turretHeading.Y + shooterReference.WorldMatrix.Up * turretHeading.Z;
  500.                 shooterForwardVec = Vector3D.Normalize( shooterForwardVec );
  501.  
  502.                 shooterLeftVec = shooterForwardVec.Cross(turret.WorldMatrix.Down);
  503.                 shooterUpVec = shooterForwardVec.Cross(shooterLeftVec);  
  504.             }
  505.             else
  506.             {
  507.                 shooterForwardVec = shooterReference.WorldMatrix.Forward;
  508.                 shooterLeftVec = shooterReference.WorldMatrix.Left;
  509.                 shooterUpVec = shooterReference.WorldMatrix.Up;
  510.             }
  511.            
  512.             //---Get positions of our origin with offsets added in
  513.             originPos = shooterReference.GetPosition() + offsetLeft * shooterLeftVec + offsetUp * shooterUpVec;
  514.         }
  515.  
  516.         missileReference = remotes[0] as IMyRemoteControl;
  517.         GetGyroOrientation(missileReference, gyros);
  518.         isSetup = true;
  519.     }
  520. }
  521.  
  522. void GetThrusterOrientation(IMyTerminalBlock refBlock)
  523. {
  524.     var forwardDirn = refBlock.WorldMatrix.Forward;
  525.  
  526.     foreach (IMyThrust thisThrust in unsortedThrusters)
  527.     {
  528.         var thrustDirn = thisThrust.WorldMatrix.Backward;
  529.         bool sameDirn = thrustDirn == forwardDirn;
  530.  
  531.         if (sameDirn)
  532.         {
  533.             mainThrusters.Add(thisThrust);
  534.         }
  535.         else {
  536.             sideThrusters.Add(thisThrust);
  537.         }
  538.     }
  539. }
  540.  
  541. void StatusCheck()
  542. {
  543.     for (int k = 0; k < importantBlocks.Count; k++)
  544.     {
  545.         IMyTerminalBlock block = importantBlocks[k];
  546.         IMySlimBlock slim = block.CubeGrid.GetCubeBlock(block.Position);
  547.         if (slim.CurrentDamage > 0)
  548.         {
  549.             Echo("Damage");
  550.             kill_time = max_kill_time;
  551.             KillGuidance(0, 0);
  552.             return;
  553.         }
  554.     }
  555. }
  556.  
  557. void LaunchMissile()
  558. {
  559.     //Stage 1: Discharge
  560.     if (!missileStage1) //set battery to discharge
  561.     {
  562.         foreach (IMyBatteryBlock thisBattery in batteries)
  563.         {
  564.             thisBattery?.ApplyAction("OnOff_On"); //make sure our battery is on  
  565.             thisBattery?.SetValue("Recharge", false);
  566.             thisBattery?.SetValue("Discharge", true);
  567.         }
  568.  
  569.         foreach (IMyReactor thisReactor in reactors)
  570.         {
  571.             thisReactor?.ApplyAction("OnOff_On"); //make sure our reactors are on  
  572.         }
  573.        
  574.         foreach (IMySensorBlock thisSensor in sensors)
  575.         {
  576.             thisSensor?.ApplyAction("OnOff_Off");
  577.         }
  578.        
  579.         foreach (IMyWarhead thisWarhead in warheads)
  580.         {  
  581.             thisWarhead?.SetValue<bool>("Safety", true);  
  582.         }
  583.        
  584.         missileStage1 = true;
  585.     }
  586.     //Stage 2: Release
  587.     else if (timeTotal >= disconnectDelay && !missileStage2) //detach missile
  588.     {
  589.         foreach (IMyVirtualMass thisMass in artMasses)
  590.         {
  591.             thisMass?.ApplyAction("OnOff_On");
  592.         }
  593.  
  594.         foreach (IMyGyro thisGyro in gyros)
  595.         {
  596.             thisGyro?.ApplyAction("OnOff_On");
  597.         }
  598.  
  599.         foreach (IMyShipMergeBlock thisMerge in mergeBlocks)
  600.         {
  601.             thisMerge?.ApplyAction("OnOff_Off");
  602.         }
  603.  
  604.         foreach (IMyShipConnector thisConnector in connectors)
  605.         {
  606.             thisConnector?.ApplyAction("Unlock");
  607.         }
  608.  
  609.         foreach (IMyMotorStator thisRotor in rotors)
  610.         {
  611.             thisRotor?.SetValue<bool>("Force weld", false);
  612.             thisRotor?.ApplyAction("Detach");
  613.         }
  614.  
  615.         foreach (IMyRadioAntenna thisAntenna in antennas)
  616.         {
  617.             thisAntenna?.SetValue<float>("Radius", 800f);
  618.             thisAntenna?.ApplyAction("OnOff_Off");
  619.             thisAntenna?.SetValue<bool>("EnableBroadCast", true);
  620.             thisAntenna?.ApplyAction("OnOff_On");
  621.             thisAntenna?.SetCustomName("");
  622.         }
  623.  
  624.         foreach (IMyBeacon thisBeacon in beacons)
  625.         {
  626.             thisBeacon?.SetValue<float>("Radius", 800f);
  627.             thisBeacon?.ApplyAction("OnOff_On");
  628.             thisBeacon?.SetCustomName("");
  629.         }
  630.  
  631.         ManeuveringThrust(false);
  632.  
  633.         foreach (IMyThrust thisThrust in detachThrusters)
  634.         {
  635.             thisThrust?.ApplyAction("OnOff_On");
  636.             thisThrust?.SetValue<float>("Override", float.MaxValue);
  637.         }
  638.  
  639.         killAllowed = true;
  640.         missileStage2 = true;
  641.  
  642.     }
  643.     //Stage 3: Drift
  644.     else if (timeTotal >= disconnectDelay + detachDuration && !missileStage3)
  645.     {
  646.         ManeuveringThrust(true);
  647.  
  648.         foreach (IMyThrust thisThrust in detachThrusters)
  649.         {
  650.             thisThrust?.SetValue<float>("Override", float.MinValue);
  651.         }
  652.         missileStage3 = true;
  653.     }
  654.     //Stage 4: Ignition
  655.     else if (timeTotal >= disconnectDelay + mainIgnitionDelay + detachDuration && !missileStage4) //fire missile    
  656.     {
  657.         foreach (IMyVirtualMass thisMass in artMasses)
  658.         {
  659.             thisMass?.ApplyAction("OnOff_Off");
  660.         }
  661.        
  662.         foreach (IMySensorBlock thisSensor in sensors)
  663.         {
  664.             thisSensor?.ApplyAction("OnOff_On");
  665.         }
  666.        
  667.         foreach (IMyWarhead thisWarhead in warheads)  
  668.         {  
  669.             thisWarhead?.SetValue<bool>("Safety", false); //arms warheads
  670.         }
  671.        
  672.         MainThrustOverride();
  673.         missileStage4 = true;
  674.     }
  675. }
  676.  
  677. void GuideMissile()
  678. {
  679.     //---Get orientation vectors of our shooter vessel    
  680.     if (!lockVector)
  681.     {
  682.         if (shooterReference is IMyLargeTurretBase)
  683.         {
  684.             var turret = shooterReference as IMyLargeTurretBase;
  685.             double azimuth = (double)turret.Azimuth;
  686.             double elevation = (double)turret.Elevation;
  687.            
  688.             var turretHeading = VectorAzimuthElevation(azimuth, elevation);
  689.             shooterForwardVec = shooterReference.WorldMatrix.Forward * turretHeading.X + shooterReference.WorldMatrix.Left * turretHeading.Y + shooterReference.WorldMatrix.Up * turretHeading.Z;
  690.             shooterForwardVec = Vector3D.Normalize( shooterForwardVec );
  691.  
  692.             shooterLeftVec = shooterForwardVec.Cross(turret.WorldMatrix.Down);
  693.             shooterUpVec = shooterForwardVec.Cross(shooterLeftVec);  
  694.         }
  695.         else
  696.         {
  697.             shooterForwardVec = shooterReference.WorldMatrix.Forward;
  698.             shooterLeftVec = shooterReference.WorldMatrix.Left;
  699.             shooterUpVec = shooterReference.WorldMatrix.Up;
  700.         }
  701.        
  702.         //---Get positions of our origin with offsets added in
  703.         originPos = shooterReference.GetPosition() + offsetLeft * shooterLeftVec + offsetUp * shooterUpVec;
  704.     }
  705.  
  706.     missilePos = missileReference.GetPosition();
  707.  
  708.     //---Find current distance from shooter to missile    
  709.     distanceFromShooter = Vector3D.Distance(originPos, missilePos);
  710.     ScaleAntennaRange(distanceFromShooter);
  711.  
  712.     //---Check if we are in range
  713.     if (distanceFromShooter > max_distance)
  714.     {
  715.         Echo("Out of range");
  716.         shouldKill = true;
  717.     }
  718.  
  719.     //---Get orientation vectors of our missile
  720.     Vector3D missileFrontVec = missileReference.WorldMatrix.Forward;
  721.     Vector3D missileLeftVec = missileReference.WorldMatrix.Left;
  722.     Vector3D missileUpVec = missileReference.WorldMatrix.Up;
  723.  
  724.     //---Find vector from shooter to missile    
  725.     var shooterToMissileVec = missilePos - originPos;
  726.  
  727.     //---Calculate angle between shooter vector and missile vector    
  728.     double rawDevAngle = VectorAngleBetween(shooterForwardVec, shooterToMissileVec) * radToDeg;
  729.  
  730.     //---Calculate perpendicular distance from shooter vector    
  731.     var projectionVec = VectorProjection(shooterToMissileVec, shooterForwardVec);
  732.     double deviationDistance = Vector3D.DistanceSquared(projectionVec, shooterToMissileVec);
  733.  
  734.     //---Check if we have gravity
  735.     double rollAngle = 0; double rollSpeed = 0;
  736.  
  737.     var remote = remotes[0] as IMyRemoteControl;
  738.     inGravity = false;
  739.  
  740.     gravVec = missileReference.GetNaturalGravity();
  741.     double gravMagSquared = gravVec.LengthSquared();
  742.     if (gravMagSquared != 0)
  743.     {
  744.         if (gravVec.Dot(missileUpVec) < 0)
  745.         {
  746.             rollAngle = Math.PI / 2 - Math.Acos(MathHelper.Clamp(gravVec.Dot(missileLeftVec) / gravVec.Length(), -1, 1));
  747.         }
  748.         else
  749.         {
  750.             rollAngle = Math.PI + Math.Acos(MathHelper.Clamp(gravVec.Dot(missileLeftVec) / gravVec.Length(), -1, 1));
  751.         }
  752.  
  753.         if (firstGuidance) lastRollAngle = rollAngle;
  754.  
  755.         rollSpeed = Math.Round(proportionalConstant * rollAngle + derivativeConstant * (rollAngle - lastRollAngle) / timeLimit, 2);
  756.  
  757.         inGravity = true;
  758.     }
  759.     else
  760.     {
  761.         if (missileStage4)
  762.             rollSpeed = missileSpinRPM * Math.PI / 30; //converts RPM to rad/s
  763.     }
  764.  
  765.     var missileSpeed = missileReference.GetShipSpeed();
  766.    
  767.     //---Determine scaling factor    
  768.     double scalingFactor;
  769.     if (rawDevAngle < 90)
  770.     {
  771.         scalingFactor = projectionVec.Length() + Math.Max(2 * missileSpeed, 200); //travel approx. 200m from current position in direction of target vector  
  772.         destinationVec = originPos + scalingFactor * shooterForwardVec;
  773.         if (!hasPassed)
  774.             hasPassed = true;
  775.     }
  776.     else if (hasPassed)
  777.     {
  778.         //---Determine where missile is in relation to shooter  
  779.         int signLeft = Math.Sign(shooterToMissileVec.Dot(shooterLeftVec));
  780.         int signUp = Math.Sign(shooterToMissileVec.Dot(shooterUpVec));
  781.  
  782.         scalingFactor = -projectionVec.Length() + Math.Max(2 * missileSpeed, 200); //added the Math.Max part for modded speed worlds
  783.         destinationVec = originPos + scalingFactor * shooterForwardVec + signLeft * 50 * shooterLeftVec + signUp * 50 * shooterUpVec;
  784.     }
  785.     else
  786.     {
  787.         scalingFactor = -projectionVec.Length() + Math.Max(2 * missileSpeed, 200);
  788.         destinationVec = originPos + scalingFactor * shooterForwardVec;
  789.     }
  790.    
  791.     //---Find vector from missile to destinationVec    
  792.     var missileToTargetVec = destinationVec - missilePos;                                                                                                                                                                                                                                                                                                     //w.H/i-P*L+a.s^H
  793.  
  794.     //---Get travel vector
  795.     var missileVelocityVec = missileReference.GetShipVelocities().LinearVelocity;
  796.    
  797.     //---Calc our new heading based upon our travel vector    
  798.     if (missileStage4)
  799.     {
  800.         headingVec = CalculateHeadingVector(missileToTargetVec, missileVelocityVec, driftCompensation);
  801.     }
  802.     else
  803.     {
  804.         headingVec = CalculateHeadingVector(missileToTargetVec, missileVelocityVec, false);
  805.     }
  806.    
  807.     //---Calc spiral trajectory
  808.     if (enableSpiralTrajectory)
  809.     {
  810.         headingVec = SpiralTrajectory(headingVec, shooterForwardVec, shooterUpVec);
  811.     }
  812.  
  813.     //---Get pitch and yaw angles
  814.     double yawAngle; double pitchAngle;
  815.     GetRotationAngles(headingVec, missileFrontVec, missileLeftVec, missileUpVec, out yawAngle, out pitchAngle);
  816.  
  817.     if (firstGuidance)
  818.     {
  819.         lastPitchAngle = pitchAngle;
  820.         lastYawAngle = yawAngle;
  821.         firstGuidance = false;
  822.     }
  823.  
  824.     //---Angle controller
  825.     double yawSpeed = Math.Round(proportionalConstant * yawAngle + derivativeConstant * (yawAngle - lastYawAngle) / timeLimit, 2);
  826.     double pitchSpeed = Math.Round(proportionalConstant * pitchAngle + derivativeConstant * (pitchAngle - lastPitchAngle) / timeLimit, 2);
  827.  
  828.     //---Set appropriate gyro override
  829.     if (controlGyros)
  830.     {
  831.         ApplyGyroOverride(pitchSpeed, yawSpeed, rollSpeed, gyros);
  832.     }
  833.  
  834.     //---Store previous values
  835.     lastYawAngle = yawAngle;
  836.     lastPitchAngle = pitchAngle;
  837.     lastRollAngle = rollAngle;
  838.  
  839.     if (shouldKill)
  840.     {
  841.         KillGuidance(rawDevAngle, deviationDistance);
  842.         lockVector = true;
  843.     }
  844. }
  845.  
  846. Vector3D CalculateHeadingVector(Vector3D targetVec, Vector3D velocityVec, bool driftComp)
  847. {
  848.     if (!driftComp)
  849.     {
  850.         return targetVec;
  851.     }
  852.  
  853.     if (velocityVec.LengthSquared() < 100)
  854.     {
  855.         return targetVec;
  856.     }
  857.    
  858.     if (targetVec.Dot(velocityVec) > 0)
  859.     {
  860.         return VectorReflection(velocityVec, targetVec);
  861.     }
  862.     else
  863.     {
  864.         return -velocityVec;
  865.     }
  866. }
  867.  
  868. //Whip's Vector from Elevation and Azimuth
  869. Vector3D VectorAzimuthElevation(double az, double el)
  870. {
  871.     el = el % (2 * Math.PI);
  872.     az = az % (2 * Math.PI);
  873.  
  874.     if (az != Math.Abs(az))
  875.     {
  876.         az = 2 * Math.PI + az;
  877.     }
  878.  
  879.     int x_mult = 1;
  880.  
  881.     if (az > Math.PI / 2 && az < Math.PI)
  882.     {
  883.         az = Math.PI - (az % Math.PI);
  884.         x_mult = -1;
  885.     }
  886.     else if (az > Math.PI && az < Math.PI * 3 / 2)
  887.     {
  888.         az = 2 * Math.PI - (az % Math.PI);
  889.         x_mult = -1;
  890.     }
  891.  
  892.     double x; double y; double z;
  893.  
  894.     if (el == Math.PI / 2)
  895.     {
  896.         x = 0;
  897.         y = 0;
  898.         z = 1;
  899.     }
  900.     else if (az == Math.PI / 2)
  901.     {
  902.         x = 0;
  903.         y = 1;
  904.         z = y * Math.Tan(el);
  905.     }
  906.     else {
  907.         x = 1 * x_mult;
  908.         y = Math.Tan(az);
  909.         double v_xy = Math.Sqrt(1 + y * y);
  910.         z = v_xy * Math.Tan(el);
  911.     }
  912.  
  913.     return new Vector3D(x, y, z);
  914. }
  915.  
  916. void ScaleAntennaRange(double dist)
  917. {
  918.     foreach (IMyRadioAntenna thisAntenna in antennas)
  919.     {
  920.         thisAntenna?.SetValue("Radius", (float)dist + 100f);
  921.     }
  922.  
  923.     foreach (IMyBeacon thisBeacon in beacons)
  924.     {
  925.         thisBeacon?.SetValue<float>("Radius", (float)dist + 100f);
  926.     }
  927. }
  928.  
  929. void ManeuveringThrust(bool turnOn)
  930. {
  931.     foreach (IMyThrust thisThrust in sideThrusters)
  932.     {
  933.         if (turnOn)
  934.         {
  935.             thisThrust?.ApplyAction("OnOff_On");
  936.         }
  937.         else
  938.         {
  939.             thisThrust?.ApplyAction("OnOff_Off");
  940.         }
  941.     }
  942. }
  943.  
  944. void MainThrustOverride()
  945. {
  946.     foreach (IMyThrust thisThrust in mainThrusters)
  947.     {
  948.         thisThrust?.ApplyAction("OnOff_On");
  949.         thisThrust?.SetValue<float>("Override", float.MaxValue);
  950.     }
  951. }
  952.  
  953. void KillGuidance(double angleOfDeviation, double distanceOfDeviation)
  954. {
  955.     if (enableSpiralTrajectory)
  956.         enableSpiralTrajectory = false;
  957.  
  958.     if (kill_time >= max_kill_time || timeTotal >= max_time_to_guide)
  959.     {
  960.         for (int i = 0; i < gyros.Count; i++)
  961.         {
  962.             var thisGyro = gyros[i] as IMyGyro;
  963.             if (thisGyro != null)
  964.             {
  965.                 thisGyro.SetValue<float>("Yaw", 0f);
  966.                 thisGyro.SetValue<float>("Pitch", 0f);
  967.                 thisGyro.SetValue<float>("Roll", 0f);
  968.                 thisGyro.SetValue("Override", true);
  969.             }
  970.         }
  971.  
  972.         if (!inGravity)
  973.         {
  974.             for (int i = 0; i < mainThrusters.Count; i++)
  975.             {
  976.                 var thisThruster = mainThrusters[i] as IMyThrust;
  977.                 if (thisThruster != null) thisThruster.ApplyAction("OnOff_Off");
  978.             }
  979.  
  980.             for (int i = 0; i < sideThrusters.Count; i++)
  981.             {
  982.                 var thisThruster = sideThrusters[i] as IMyThrust;
  983.                 if (thisThruster != null) thisThruster.ApplyAction("OnOff_Off");
  984.             }
  985.         }
  986.  
  987.         for (int i = 0; i < importantBlocks.Count; i++)
  988.         {
  989.             var thisBlock = importantBlocks[i] as IMyTerminalBlock;
  990.             if (thisBlock != null)
  991.             {
  992.                 if (!(thisBlock is IMyRemoteControl) || !(thisBlock is IMyProgrammableBlock))
  993.                     thisBlock.ApplyAction("OnOff_Off");
  994.             }
  995.         }
  996.     }
  997.  
  998.     if (angleOfDeviation < 5 && distanceOfDeviation < 1)
  999.     {
  1000.         kill_time += timeElapsed;
  1001.     }
  1002.     else {
  1003.         kill_time = 0;
  1004.     }
  1005. }
  1006.  
  1007. Vector3D VectorProjection(Vector3D a, Vector3D b) //proj a on b    
  1008. {
  1009.     Vector3D projection = a.Dot(b) / b.LengthSquared() * b;
  1010.     return projection;
  1011. }
  1012.  
  1013. Vector3D VectorReflection(Vector3D a, Vector3D b) //reflect a over b    
  1014. {
  1015.     Vector3D project_a = VectorProjection(a, b);
  1016.     Vector3D reject_a = a - project_a;
  1017.     Vector3D reflect_a = project_a - reject_a;
  1018.     return reflect_a;
  1019. }
  1020.  
  1021. double VectorAngleBetween(Vector3D a, Vector3D b) //returns radians
  1022. {
  1023.     if (a.LengthSquared() == 0 || b.LengthSquared() == 0)
  1024.         return 0;
  1025.     else
  1026.         return Math.Acos(MathHelper.Clamp(a.Dot(b) / a.Length() / b.Length(), -1, 1));
  1027. }
  1028.  
  1029. bool CheckDotPositive(Vector3D a, Vector3D b)
  1030. {
  1031.     double check = a.Dot(b);
  1032.     if (check > 0)
  1033.     {
  1034.         return true;
  1035.     }
  1036.     else {
  1037.         return false;
  1038.     }
  1039. }
  1040.  
  1041. //Whip's Get Rotation Angles Method v4
  1042. void GetRotationAngles( Vector3D v_target, Vector3D v_front, Vector3D v_left, Vector3D v_up, out double yaw, out double pitch )
  1043. {
  1044.     //Dependencies: VectorProjection() | VectorAngleBetween()
  1045.     //Keen uses a stupid left hand rule coordSystem, I dont.
  1046.     var projTargetFront = VectorProjection( v_target, v_front );  
  1047.     var projTargetLeft = VectorProjection( v_target, v_left );    
  1048.     var projTargetUp = VectorProjection( v_target, v_up );
  1049.     var projTargetFrontLeft = projTargetFront + projTargetLeft;
  1050.     var projTargetFrontUp = projTargetFront + projTargetUp;
  1051.  
  1052.     yaw = VectorAngleBetween(v_front, projTargetFrontLeft);
  1053.     pitch = VectorAngleBetween(v_front, projTargetFrontUp);
  1054.  
  1055.     //---Check if yaw angle is left or right  
  1056.     //multiplied by -1 to convert from right hand rule to left hand rule
  1057.     yaw = -1 * Math.Sign( v_left.Dot( projTargetLeft ) ) * yaw;
  1058.  
  1059.     //---Check if pitch angle is up or down    
  1060.     pitch = Math.Sign( v_up.Dot( projTargetUp )) * pitch;
  1061.  
  1062.     //---Check if target vector is pointing opposite the front vector
  1063.     if (pitch == 0 && yaw == 0 && v_target.Dot(v_front) < 0)
  1064.     {
  1065.         yaw = Math.PI;
  1066.         pitch = Math.PI;
  1067.     }
  1068. }
  1069.  
  1070. //Whip's Gyro Orientation Method
  1071. string[] gyroRelativeYaw;
  1072. string[] gyroRelativePitch;
  1073. string[] gyroRelativeRoll;
  1074. int[] gyroYawSign;
  1075. int[] gyroPitchSign;
  1076. int[] gyroRollSign;
  1077.  
  1078. void GetGyroOrientation(IMyTerminalBlock reference_block, List<IMyTerminalBlock> gyro_list)
  1079. {
  1080.     gyroRelativeYaw = new string[gyro_list.Count];
  1081.     gyroRelativePitch = new string[gyro_list.Count];
  1082.     gyroRelativeRoll = new string[gyro_list.Count];
  1083.  
  1084.     gyroYawSign = new int[gyro_list.Count];
  1085.     gyroPitchSign = new int[gyro_list.Count];
  1086.     gyroRollSign = new int[gyro_list.Count];
  1087.  
  1088.     var reference_up = reference_block.WorldMatrix.Up; //assuming rot right
  1089.     var reference_right = reference_block.WorldMatrix.Right; //assuming rot up
  1090.     var reference_forward = reference_block.WorldMatrix.Forward; //assuming rot up
  1091.  
  1092.     for (int i = 0; i < gyro_list.Count; i++)
  1093.     {
  1094.         var gyro_forward = gyro_list[i].WorldMatrix.Forward;
  1095.         var gyro_backward = gyro_list[i].WorldMatrix.Backward;
  1096.         var gyro_up = gyro_list[i].WorldMatrix.Up;
  1097.         var gyro_down = gyro_list[i].WorldMatrix.Down;
  1098.         var gyro_left = gyro_list[i].WorldMatrix.Left;
  1099.         var gyro_right = gyro_list[i].WorldMatrix.Right;
  1100.  
  1101.         /// Pitch Fields ///    
  1102.         if (reference_right == gyro_forward)
  1103.         {
  1104.             gyroRelativePitch[i] = "Roll";
  1105.             gyroPitchSign[i] = 1;
  1106.         }
  1107.         else if (reference_right == gyro_backward)
  1108.         {
  1109.             gyroRelativePitch[i] = "Roll";
  1110.             gyroPitchSign[i] = -1;
  1111.         }
  1112.         else if (reference_right == gyro_right)
  1113.         {
  1114.             gyroRelativePitch[i] = "Pitch";
  1115.             gyroPitchSign[i] = 1;
  1116.         }
  1117.         else if (reference_right == gyro_left)
  1118.         {
  1119.             gyroRelativePitch[i] = "Pitch";
  1120.             gyroPitchSign[i] = -1;
  1121.         }
  1122.         else if (reference_right == gyro_up)
  1123.         {
  1124.             gyroRelativePitch[i] = "Yaw";
  1125.             gyroPitchSign[i] = -1;
  1126.         }
  1127.         else if (reference_right == gyro_down)
  1128.         {
  1129.             gyroRelativePitch[i] = "Yaw";
  1130.             gyroPitchSign[i] = 1;
  1131.         }
  1132.  
  1133.         /// Yaw Fields ///
  1134.         if (reference_up == gyro_forward)
  1135.         {
  1136.             gyroRelativeYaw[i] = "Roll";
  1137.             gyroYawSign[i] = -1;
  1138.         }
  1139.         else if (reference_up == gyro_backward)
  1140.         {
  1141.             gyroRelativeYaw[i] = "Roll";
  1142.             gyroYawSign[i] = 1;
  1143.         }
  1144.         else if (reference_up == gyro_right)
  1145.         {
  1146.             gyroRelativeYaw[i] = "Pitch";
  1147.             gyroYawSign[i] = -1;
  1148.         }
  1149.         else if (reference_up == gyro_left)
  1150.         {
  1151.             gyroRelativeYaw[i] = "Pitch";
  1152.             gyroYawSign[i] = 1;
  1153.         }
  1154.         else if (reference_up == gyro_up)
  1155.         {
  1156.             gyroRelativeYaw[i] = "Yaw";
  1157.             gyroYawSign[i] = 1;
  1158.         }
  1159.         else if (reference_up == gyro_down)
  1160.         {
  1161.             gyroRelativeYaw[i] = "Yaw";
  1162.             gyroYawSign[i] = -1;
  1163.         }
  1164.  
  1165.         /// Roll Fields ///
  1166.         if (reference_forward == gyro_forward)
  1167.         {
  1168.             gyroRelativeRoll[i] = "Roll";
  1169.             gyroRollSign[i] = 1;
  1170.         }
  1171.         else if (reference_forward == gyro_backward)
  1172.         {
  1173.             gyroRelativeRoll[i] = "Roll";
  1174.             gyroRollSign[i] = -1;
  1175.         }
  1176.         else if (reference_forward == gyro_right)
  1177.         {
  1178.             gyroRelativeRoll[i] = "Pitch";
  1179.             gyroRollSign[i] = 1;
  1180.         }
  1181.         else if (reference_forward == gyro_left)
  1182.         {
  1183.             gyroRelativeRoll[i] = "Pitch";
  1184.             gyroRollSign[i] = -1;
  1185.         }
  1186.         else if (reference_forward == gyro_up)
  1187.         {
  1188.             gyroRelativeRoll[i] = "Yaw";
  1189.             gyroRollSign[i] = -1;
  1190.         }
  1191.         else if (reference_forward == gyro_down)
  1192.         {
  1193.             gyroRelativeRoll[i] = "Yaw";
  1194.             gyroRollSign[i] = 1;
  1195.         }
  1196.     }
  1197. }
  1198.  
  1199. void ApplyGyroOverride(double pitch_speed, double yaw_speed, double roll_speed, List<IMyTerminalBlock> gyro_list)
  1200. {
  1201.     for (int i = 0; i < gyro_list.Count; i++)
  1202.     {
  1203.         var thisGyro = gyro_list[i] as IMyGyro;
  1204.         if (thisGyro != null)
  1205.         {
  1206.             thisGyro.SetValue<float>(gyroRelativeYaw[i], (float)yaw_speed * gyroYawSign[i]);
  1207.             thisGyro.SetValue<float>(gyroRelativePitch[i], (float)pitch_speed * gyroPitchSign[i]);
  1208.             thisGyro.SetValue<float>(gyroRelativeRoll[i], (float)roll_speed * gyroRollSign[i]);
  1209.             thisGyro.SetValue("Override", true);
  1210.         }
  1211.     }
  1212. }
  1213.  
  1214. //Whip's Spiral Trajectory Method v2
  1215. double spiralRadius = Math.Tan(spiralDegrees * degToRad);
  1216. double timeSpiral = 0;
  1217.  
  1218. Vector3D SpiralTrajectory(Vector3D v_target, Vector3D v_front, Vector3D v_up)
  1219. {
  1220.     Vector3D v_targ_norm = Vector3D.Normalize(v_target);
  1221.  
  1222.     if (timeSpiral > timeMaxSpiral)
  1223.         timeSpiral = 0;
  1224.  
  1225.     double angle_theta = 2 * Math.PI * timeSpiral / timeMaxSpiral;
  1226.  
  1227.     if (v_front.Dot(v_targ_norm) > 0)
  1228.     {
  1229.         Vector3D v_x = Vector3D.Normalize(v_up.Cross(v_targ_norm));
  1230.         Vector3D v_y = Vector3D.Normalize(v_x.Cross(v_targ_norm));
  1231.         Vector3D v_target_adjusted = v_targ_norm + spiralRadius * (v_x * Math.Cos(angle_theta) + v_y * Math.Sin(angle_theta));
  1232.         return v_target_adjusted;
  1233.     }
  1234.     else
  1235.     {
  1236.         return v_targ_norm;
  1237.     }
  1238. }
  1239.  
  1240. /*
  1241. CHANGELOG:
  1242. - Redesigned pitch and yaw determination method
  1243. - Added sensor support, sensors turn on when main ignition is triggered
  1244. - Optimized math operations
  1245. - Re-added "hasPassed" boolean
  1246. - Made sure lists properly clear when setup is run for a second time
  1247. - Removed fudge number
  1248. - Added warhead support
  1249. - Fixed issue that caused missiles to spaz out.
  1250. - Clamped arccosine inputs to account for floating point errors
  1251. - Fixed missile spin being activated before main ignition fires
  1252. - Added in vector lock on launch
  1253. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement