Guest User

Mining_script_V2.4 D Plagioclase

a guest
Mar 11th, 2019
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 43.44 KB | None | 0 0
  1. //    Mining_script_V2.4 D Plagio
  2. //
  3. //  from botengine
  4. //
  5. //  This script mines ore from asteroids.
  6. //  before running this script, make sure to prepare as follows:
  7. //  +enter bookmark for mining site and bookmark for station in the configuration section below.
  8. //  +in the Overview create a preset which includes asteroids and rats and enter the name of that preset in the configuration section below at 'OverviewPreset'. The bot will make sure this preset is loaded when it needs to use the overview.
  9. //  +set Overview to sort by distance with the nearest entry at the top.
  10. //  +in the Inventory select the 'List' view.
  11. //  +set the UI language to english.
  12. //  +use a ship with an ore hold.
  13. //  +put some light drones into your ships' drone bay. The bot will make use of them to attack rats when HP are too low (configurable) or it gets jammed.
  14. //  +enable the info panel 'System info'. The bot will use the button in there to access bookmarks and a    steroid belts.
  15. //  +arrange windows to not occlude modules or info panels.
  16. //  +in the ship UI, disable "Display Passive Modules" and disable "Display Empty Slots" and enable "Display Module Tooltips". The bot uses the module tooltips to automatically identify the properties of the modules.
  17. //
  18. //  for optional features (such as warp to safe on hostile in local) see the configuration section below.
  19.  
  20. //    activate shield booster taken from Terpla (TPMiningScript-2018-06-21v2)
  21. //    cycle in the course of asteroid berries from beginners-ore-asteroid
  22.  
  23. //    other (ugly) improvements are :
  24. //        using Micro Warp Drive/Afterburner
  25. //        using Mining Crystal (optional)
  26. //        adding option to exclude Ore Type (without change overview)
  27. //        send drone in bay immediately after fight
  28.  
  29.  
  30. using BotSharp.ToScript.Extension;
  31. using MemoryStruct = Sanderling.Interface.MemoryStruct;
  32. using Parse = Sanderling.Parse;
  33.  
  34. //  begin of configuration section ->
  35.  
  36. //  The bot uses the bookmarks from the menu which is opened from the button in the 'System info' panel.
  37.  
  38. //  Should the bot use bookmarks for mining site?
  39. bool ShouldUseMiningBookmarks = true;
  40.  
  41. //  Bookmarks of places to mine. Add additional bookmarks separated by comma.
  42. string[] SetMiningSiteBookmark = new[] {
  43.     "Mining",
  44.     };
  45.  
  46. string[] BaseOre = new[] {
  47.     "Mercoxit", "Bistot", "Arkonor",
  48.     "Crokite", "Spodumain", "Ochre",
  49.     "Gneiss", "Hemorphite",
  50.     //"Jaspet", "Kernite", "Omber",
  51.     //"Pyroxeres",
  52.     "Plagioclase",
  53.    
  54.     };
  55.  
  56. //   List of excluded base ore
  57. string[] ExcludedBaseOre = new[] {
  58.     "Ice","Scordite", "Veldspar","Hedbergite",
  59.     "Omber","Pyroxeres","Kernite",
  60.     };
  61.    
  62. string[] ModifierOrePreference = new[] {
  63.     //"Concentrated Veldspar", "Dense Veldspar", "Stable Veldspar",
  64.     //"Condensed Scordite", "Massive Scordite", "Glossy Scordite",
  65.     //"Solid Pyroxeres", "Viscous Pyroxeres", "Opulent Pyroxeres",
  66.     "Azure Plagioclase", "Rich Plagioclase", "Sparkling Plagioclase",
  67.     //"Silvery Omber", "Golden Omber", "Platinoid Omber",
  68.     //"Luminous Kernite", "Fiery Kernite", "Resplendant Kernite",
  69.     //"Pure Jaspet", "Pristine Jaspet", "Immaculate Jaspet",
  70.     //"Vivid Hemorphite", "Radiant Hemorphite", "Scintillating Hemorphite",
  71.     "Vitric Hedbergite", "Glazed Hedbergite", "Lustrous Hedbergite",
  72.     "Iridescent Gneiss", "Prismatic Gneiss", "Brilliant Gneiss",
  73.     "Onyx Ochre", "Obsidian Ochre", "Jet Ochre",
  74.     "Bright Spodumain", "Gleaming Spodumain", "Dazzling Spodumain",
  75.     "Sharp Crokite", "Crystalline Crokite", "Pellucid Crokite",
  76.     "Crimson Arkonor", "Prime Arkonor", "Flawless Arkonor",
  77.     "Triclinic Bistot", "Monoclinic Bistot", "Cubic Bistot",
  78.     "Magma Mercoxit", "Vitreous Mercoxit",
  79.     };
  80.    
  81. //  Bookmark of location where ore should be unloaded.
  82. string UnloadBookmark = "Depot";
  83.  
  84. //  Name of the container to unload to as shown in inventory.
  85. string UnloadDestContainerName = "Item Hangar";
  86.  
  87. //  when this is set to true, the bot will try to unload when undocked.
  88. bool UnloadInSpace = false;
  89.  
  90. //   when this is set to true, the bot will try to use mining crystal
  91. bool UseMiningCrystal = false;
  92.  
  93. //   when this is set to true, the bot will try to use Afterburner or MicroWarp
  94. bool UseAfterburner = false;
  95.  
  96.  
  97. //  Bookmark of place to retreat to to prevent ship loss.
  98. string RetreatBookmark = UnloadBookmark;
  99.  
  100. //  The bot loads this preset to the active tab.
  101. string OverviewPreset = "AstroRats";
  102.  
  103. // activate shield hardener
  104. var ActivateHardener = false;
  105.  
  106. //  bot will start fighting (and stop mining) when hitpoints are lower.
  107. var DefenseEnterHitpointThresholdPercent = 85;
  108. var DefenseExitHitpointThresholdPercent = 90;
  109. var EmergencyWarpOutHitpointPercent = 30;
  110.  
  111. var FightAllRats = true;    //  when this is set to true, the bot will attack rats independent of shield hp.
  112.  
  113. var EnterOffloadOreHoldFillPercent = 95;    //  percentage of ore hold fill level at which to enter the offload process.
  114.  
  115. var RetreatOnNeutralOrHostileInLocal = false;   // warp to RetreatBookmark when a neutral or hostile is visible in local.
  116.  
  117. bool returnDronesToBayOnRetreat = true; // when set to true, bot will attempt to dock back the drones before retreating
  118.  
  119. //  <- end of configuration section
  120.  
  121. // ################################### Script  START ##########################################
  122.  
  123. Queue<string> visitedLocations = new Queue<string>();
  124.  
  125. Func<object> BotStopActivity = () => null;
  126.  
  127. Func<object> NextActivity = MainStep;
  128.  
  129. for(;;)
  130. {
  131.     MemoryUpdate();
  132.  
  133.     Host.Log(
  134.         "ore hold fill: " + OreHoldFillPercent + "%" +
  135.         ", mining range: " + MiningRange +
  136.         ", mining modules (inactive): " + SetModuleMiner?.Length + "(" + SetModuleMinerInactive?.Length + ")" +
  137.         ", shield.hp: " + ShieldHpPercent + "%" +
  138.         ", retreat: " + RetreatReason +
  139.         ", JLA: " + JammedLastAge +
  140.         ", Rats: " + ListRatOverviewEntry?.Length +
  141.         ", Asteroids: " + ListAsteroidOverviewEntry?.Length +
  142.         ", Wrecks: " + ListWreckOverviewEntry?.Length +
  143.         ", offload count: " + OffloadCount +
  144.         ", Drones (Bay): " +    DronesInSpaceCount + "(" + DronesInBayCount + ")" +
  145.         ", nextAct: " + NextActivity?.Method?.Name);
  146.  
  147.     CloseModalUIElement();
  148.  
  149.     if(0 < RetreatReason?.Length && !(Measurement?.IsDocked ?? false))
  150.     {
  151.         if (returnDronesToBayOnRetreat) {
  152.             DroneEnsureInBay();
  153.             InitiateDockToOrWarpToBookmark(RetreatBookmark);
  154.         }
  155.  
  156.         if (!returnDronesToBayOnRetreat || (returnDronesToBayOnRetreat && 0 == DronesInSpaceCount)) {
  157.             InitiateDockToOrWarpToBookmark(RetreatBookmark);
  158.         }
  159.         continue;
  160.     }
  161.  
  162.     NextActivity = NextActivity?.Invoke() as Func<object>;
  163.  
  164.     if(BotStopActivity == NextActivity)
  165.     {
  166.         Host.Log("BotStop, no Next Activity?");
  167.         break;
  168.     }
  169.    
  170.     if(null == NextActivity)
  171.     {
  172.         NextActivity = MainStep;
  173.     }
  174.    
  175.     Host.Delay(1111);
  176. }
  177.  
  178. //  seconds since ship was jammed.
  179. long? JammedLastAge => Jammed ? 0 : (Host.GetTimeContinuousMilli() - JammedLastTime) / 1000;
  180.  
  181. int?     ShieldHpPercent => ShipUi?.HitpointsAndEnergy?.Shield / 10;
  182.  
  183. int? CapacitorPercent => ShipUi?.HitpointsAndEnergy?.Capacitor / 10;
  184.  
  185. bool    DefenseExit =>
  186.     (Measurement?.IsDocked ?? false) ||
  187.     !(0 < ListRatOverviewEntry?.Length) ||
  188.     (DefenseExitHitpointThresholdPercent < ShieldHpPercent && !(JammedLastAge < 40) &&
  189.     !(FightAllRats && 0 < ListRatOverviewEntry?.Length));
  190.  
  191. bool    DefenseEnter =>
  192.     !DefenseExit    ||
  193.     !(DefenseEnterHitpointThresholdPercent < ShieldHpPercent) || JammedLastAge < 10 || ListRatOverviewEntry?.Length < 0;
  194.  
  195. bool OreHoldFilledForOffload => Math.Max(0, Math.Min(100, EnterOffloadOreHoldFillPercent)) <= OreHoldFillPercent;
  196.  
  197. Int64?  JammedLastTime = null;
  198. string RetreatReasonTemporary = null;
  199. string RetreatReasonPermanent = null;
  200. string RetreatReason => RetreatReasonPermanent ?? RetreatReasonTemporary;
  201. int? LastCheckOreHoldFillPercent = null;
  202.  
  203. int OffloadCount = 0;
  204.  
  205. int RandomInt() => new Random((int)Host.GetTimeContinuousMilli()).Next();
  206.  
  207. T RandomElement<T>(IEnumerable<T> sequence)
  208. {
  209.     var array = (sequence as T[]) ?? sequence?.ToArray();
  210.  
  211.     if (!(0 < array?.Length))
  212.         return default(T);
  213.  
  214.     return array[RandomInt() % array.Length];
  215. }
  216.  
  217. Func<object>    MainStep()
  218. {
  219.     if(Measurement?.IsDocked ?? false)
  220.     {
  221.         InInventoryUnloadItems();
  222.  
  223.         if (0 < RetreatReasonPermanent?.Length)
  224.             return BotStopActivity;
  225.  
  226.         if (0 < RetreatReason?.Length)
  227.             return MainStep;
  228.  
  229.         Undock();
  230.     }
  231.    
  232.     ToggleShieldBooster(ShieldHpPercent <90);
  233.    
  234.     if(DefenseEnter)
  235.     {
  236.         Host.Log("enter defense.");
  237.         return DefenseStep;
  238.     }
  239.  
  240.     EnsureOverviewTypeSelectionLoaded();
  241.  
  242.     EnsureWindowInventoryOpenOreHold();
  243.  
  244.     if(ReadyForManeuver)
  245.     {  
  246.    
  247.         if(OreHoldFilledForOffload){
  248.             DroneEnsureInBay();
  249.         }
  250.        
  251.         if(OreHoldFilledForOffload && 0 == DronesInSpaceCount){
  252.             if(ReadyForManeuver)
  253.                 Host.Log("InitiateDockToOrWarpToBookmark(UnloadBookmark), Ore-Hold Full");
  254.                 InitiateDockToOrWarpToBookmark(UnloadBookmark);
  255.  
  256.             if (UnloadInSpace)
  257.             {
  258.                 Host.Delay(4000);
  259.                 InInventoryUnloadItems();
  260.             }
  261.  
  262.             return MainStep;
  263.         }
  264.        
  265.         if(!(0 < ListAsteroidOverviewEntry?.Length))
  266.             if(ShouldUseMiningBookmarks){
  267.                 Host.Log("InitiateWarpToRandomMiningBookmark()");
  268.                 InitiateWarpToRandomMiningBookmark();
  269.             }else{
  270.                 Host.Log("InitiateWarpToMiningSite()");
  271.                 InitiateWarpToMiningSite();
  272.             }
  273.             //InitiateWarpToRandomMiningSite();
  274.             //InitiateWarpToMiningSite();
  275.     }
  276.  
  277.     ModuleMeasureAllTooltip();
  278.  
  279.     return InBeltMineStep;
  280. }
  281.  
  282. void CloseModalUIElement()
  283. {
  284.     var ButtonClose =
  285.         ModalUIElement?.ButtonText?.FirstOrDefault(button => (button?.Text).RegexMatchSuccessIgnoreCase("close|no|ok"));
  286.        
  287.     Sanderling.MouseClickLeft(ButtonClose);
  288. }
  289.  
  290. void DroneLaunch()
  291. {  
  292.     var ManeuverType = Measurement?.ShipUi?.Indication?.ManeuverType;
  293.     if(!(ShipManeuverTypeEnum.Warp == ManeuverType  || ShipManeuverTypeEnum.Jump == ManeuverType)){
  294.         if (!(3 < DronesInSpaceCount)){
  295.             Host.Log("launch drones.");
  296.             Sanderling.MouseClickRight(DronesInBayListEntry);
  297.             Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("launch", RegexOptions.IgnoreCase));
  298.         }
  299.     }
  300. }
  301.  
  302. void DroneEnsureInBay()
  303. {
  304.     if(0 == DronesInSpaceCount)
  305.         return;
  306.    
  307.     DroneReturnToBay();
  308.  
  309.     Host.Delay(3000);
  310. }
  311.  
  312. void DroneReturnToBay()
  313. {
  314.     Host.Log("return drones to bay.");
  315.     Sanderling.MouseClickRight(DronesInSpaceListEntry);
  316.     Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("return.*bay", RegexOptions.IgnoreCase));
  317.     //Sanderling.KeyboardPressCombined(new[]{ VirtualKeyCode.SHIFT, VirtualKeyCode.VK_F});
  318. }
  319.  
  320. Func<object>    DefenseStep()
  321. {
  322.     if(DefenseExit)
  323.     {
  324.         Host.Log("exit defense.");
  325.         //DroneEnsureInBay();
  326.         ToggelHardener(false);
  327.         return null;
  328.     }
  329.    
  330.     if(ActivateHardener)
  331.         //ActivateHardenerExecute();
  332.         ToggelHardener(true);
  333.    
  334.     DroneLaunch();
  335.  
  336.     EnsureOverviewTypeSelectionLoaded();
  337.  
  338.     var SetRatName =
  339.         ListRatOverviewEntry?.Select(entry => Regex.Split(entry?.Name ?? "", @"\s+")?.FirstOrDefault())
  340.         ?.Distinct()
  341.         ?.ToArray();
  342.    
  343.     var SetRatTarget = Measurement?.Target?.Where(target =>
  344.         SetRatName?.Any(ratName => target?.TextRow?.Any(row => row.RegexMatchSuccessIgnoreCase(ratName)) ?? false) ?? false);
  345.    
  346.     var RatTargetNext = SetRatTarget?.OrderBy(target => target?.DistanceMax ?? int.MaxValue)?.FirstOrDefault();
  347.    
  348.     if(null == RatTargetNext)
  349.     {
  350.         Host.Log("targeting rat!");
  351.         Sanderling.MouseClickRight(ListRatOverviewEntry?.FirstOrDefault());
  352.         Sanderling.MouseClickLeft(MenuEntryLockTarget);
  353.     }
  354.     else
  355.     {
  356.         Host.Log("rat targeted. sending drones.");
  357.         Sanderling.MouseClickLeft(RatTargetNext);
  358.         Sanderling.MouseClickRight(DronesInSpaceListEntry);
  359.         //Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("engage", RegexOptions.IgnoreCase));
  360.         Sanderling.KeyboardPress(VirtualKeyCode.VK_F);
  361.     }
  362.    
  363.     return DefenseStep;
  364. }
  365.  
  366. Func<object> InBeltMineStep()
  367. {
  368.     var ConnectionLost = Measurement?.WindowOther?.FirstOrDefault()?.LabelText?.FirstOrDefault(text => (text?.Text.RegexMatchSuccessIgnoreCase("Connection") ?? false));
  369.     if (ConnectionLost != null){
  370.             Host.Log(" ***              Lost connection at : " + DateTime.Now.ToString(" HH:mm")+ " ***   " );
  371.             Console.Beep(1047,150);
  372.             Host.Delay(150);
  373.             return BotStopActivity;
  374.     } else {
  375.         // Host.Log(" ***              Online: " + DateTime.Now.ToString(" HH:mm")+ " ***   " );
  376.     }
  377.    
  378.     if (DefenseEnter){
  379.         Host.Log("enter defense.");
  380.         return DefenseStep;
  381.     }
  382.  
  383.     EnsureWindowInventoryOpenOreHold();
  384.  
  385.     EnsureOverviewTypeSelectionLoaded();
  386.    
  387.     if(OreHoldFilledForOffload)
  388.         return null;
  389.  
  390.     var moduleMinerInactive = SetModuleMinerInactive?.FirstOrDefault();
  391.  
  392.     // wenn die Miner -Laser arbeiten dann
  393.     if (null == moduleMinerInactive)   
  394.     {
  395.          // Wenn keine Drohnen gestartet
  396.         if (!(0 < DronesInSpaceCount))
  397.         {
  398.             Host.Log("launch drones.");
  399.             Sanderling.MouseClickRight(DronesInBayListEntry);
  400.             Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("launch", RegexOptions.IgnoreCase));
  401.             Host.Delay(2000);
  402.             Sanderling.MouseClickRight(DronesInSpaceListEntry);
  403.             Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("mine", RegexOptions.IgnoreCase));
  404.         }
  405.        
  406.         var Speed = Sanderling?.MemoryMeasurementParsed?.Value?.ShipUi?.SpeedMilli;
  407.         var asteroidOverviewEntryNextA = ListAsteroidOverviewEntry?.FirstOrDefault();
  408.         if ( asteroidOverviewEntryNextA.DistanceMax < 8000 && Speed > 50000)
  409.         {
  410.             Sanderling.KeyboardPressCombined(new[]{ VirtualKeyCode.CONTROL, VirtualKeyCode.SPACE});
  411.                 Host.Log("STOP Ship 8000");
  412.             }
  413.         else
  414.         {  
  415.             //Host.Log("Ship to Target "+ asteroidOverviewEntryNextA.DistanceMax);  
  416.         }
  417.        
  418.         //try to unlock drone targets
  419.         var targetDroneInputFocus   =
  420.             SetTargetDrone?.FirstOrDefault(target => target?.IsSelected ?? false);
  421.        
  422.         /*
  423.         if(null == targetDroneInputFocus){
  424.             Sanderling.MouseClickLeft(SetTargetDrone?.FirstOrDefault());
  425.            
  426.             //irgendwie so
  427.             Sanderling.MouseClickRight(DronesInSpaceListEntry);
  428.             Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("Mine", RegexOptions.IgnoreCase));
  429.        
  430.            
  431.            
  432.         }
  433.         */
  434.        
  435.         /* // Try Salvage Wrecks
  436.         if(0<ListWreckOverviewEntry?.Length){ //Wenn Wracks gefunden
  437.             var WreckOverviewEntryNext = ListWreckOverviewEntry?.FirstOrDefault();
  438.             Host.Log("next Wreck: (" + WreckOverviewEntryNext?.Name + " , distance: " + WreckOverviewEntryNext?.DistanceMax + ")");
  439.             var WreckMaxDistance = 10000;
  440.             var setTargetWreckInRange = SetWreck?.Where(target => target?.DistanceMax <= WreckMaxDistance)?.ToArray();
  441.             Host.Log("targeted asteroids in range (without assignment): " + setTargetWreckInRange?.Length + ")");
  442.             //Sanderling.MouseClickRight(DronesInSpaceListEntry);
  443.             //Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("salvage", RegexOptions.IgnoreCase));
  444.         }
  445.         */
  446.                
  447.         Host.Delay(7000);
  448.        
  449.         return InBeltMineStep;
  450.     }
  451.    
  452.     var setTargetAsteroidInRange    =
  453.         SetTargetAsteroid?.Where(target => target?.DistanceMax <= MiningRange)?.ToArray();
  454.    
  455.     var setTargetAsteroidInRangeNotAssigned =
  456.         setTargetAsteroidInRange?.Where(target => !(0 < target?.Assigned?.Length))?.ToArray();
  457.    
  458.     Host.Log("targeted asteroids in range (without assignment): " + setTargetAsteroidInRange?.Length + " (" + setTargetAsteroidInRangeNotAssigned?.Length + ")");
  459.  
  460.     if(0 < setTargetAsteroidInRangeNotAssigned?.Length)
  461.     {
  462.         if(UseAfterburner)
  463.         {
  464.             ToggleMicroWarpDrive(false);
  465.             ToggleAfterBurner(false);
  466.         }
  467.         var targetAsteroidInputFocus    =
  468.             setTargetAsteroidInRangeNotAssigned?.FirstOrDefault(target => target?.IsSelected ?? false);
  469.  
  470.         if(null == targetAsteroidInputFocus)
  471.             Sanderling.MouseClickLeft(setTargetAsteroidInRangeNotAssigned?.FirstOrDefault());
  472.  
  473.         /*
  474.         foreach (var moduleMinerIna in SetModuleMinerInactive)
  475.         {
  476.             if (UseMiningCrystal) {
  477.                 LoadMiningCrystalForTarget(moduleMinerIna, setTargetAsteroidInRangeNotAssigned?.FirstOrDefault());
  478.                 /*
  479.                 string[] targetTextRow = setTargetAsteroidInRangeNotAssigned?.FirstOrDefault()?.TextRow;
  480.                 if (targetTextRow != null && targetTextRow.Length > 0) {
  481.                     string baseOre = BaseOreFromAsteroidName(String.Join(" ", targetTextRow));
  482.                     if (!String.IsNullOrEmpty(baseOre)) {
  483.                             LoadMiningCrystal(moduleMinerIna, baseOre);
  484.                             Sanderling.MouseClickLeft(setTargetAsteroidInRangeNotAssigned?.FirstOrDefault());
  485.                             Sanderling.MouseMove(moduleMinerIna);
  486.                             Sanderling.WaitForMeasurement();   
  487.                     }
  488.                 }
  489.                
  490.             }
  491.            
  492.             ModuleToggle(moduleMinerIna);
  493.         }
  494.         */
  495.        
  496.         ModuleToggle(moduleMinerInactive);
  497.        
  498.         DroneLaunch();
  499.         Host.Delay(5000);
  500.        
  501.         Sanderling.MouseClickRight(DronesInSpaceListEntry);
  502.         Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("Mine", RegexOptions.IgnoreCase));
  503.        
  504.         //Stop ship if under 10000 meter from target
  505.         var asteroidOverviewEntryNextA = ListAsteroidOverviewEntry?.FirstOrDefault();
  506.         if(!(8000 < asteroidOverviewEntryNextA?.DistanceMin)){
  507.             Sanderling.KeyboardPressCombined(new[]{ VirtualKeyCode.CONTROL, VirtualKeyCode.SPACE});
  508.             Host.Log("STOP Ship  Approach 8000");
  509.         }
  510.        
  511.         return InBeltMineStep;
  512.     }
  513.  
  514.     var asteroidOverviewEntryNext = ListAsteroidOverviewEntry?.FirstOrDefault();
  515.     var asteroidOverviewEntryNextNotTargeted = ListAsteroidOverviewEntry?.FirstOrDefault(entry => !((entry?.MeTargeted ?? false) || (entry?.MeTargeting ?? false)));
  516.  
  517.     Host.Log("next asteroid: (" + asteroidOverviewEntryNext?.Name + " , distance: " + asteroidOverviewEntryNext?.DistanceMax + ")" +
  518.         ", next asteroid not targeted: (" + asteroidOverviewEntryNext?.Name + " , distance: " + asteroidOverviewEntryNext?.DistanceMax + ")");
  519.  
  520.     if(null == asteroidOverviewEntryNext)
  521.     {
  522.         Host.Log("no asteroid available");
  523.         return null;
  524.     }
  525.  
  526.     if(null == asteroidOverviewEntryNextNotTargeted)
  527.     {
  528.         Host.Log("all asteroids targeted");
  529.         return null;
  530.     }
  531.  
  532.     if (!(asteroidOverviewEntryNextNotTargeted.DistanceMax < MiningRange))
  533.     {
  534.         if(!(1000 < asteroidOverviewEntryNext?.DistanceMin))
  535.         {
  536.             Host.Log("distance between asteroids too large");
  537.             return null;
  538.         }
  539.  
  540.         Host.Log("out of range, approaching");
  541.         Random rnd = new Random();
  542.         if (!ApproachSomething || RandomInt() % 8 == 1)
  543.             ClickMenuEntryOnMenuRoot(asteroidOverviewEntryNext, "approach");
  544.            
  545.         if (SetModuleMinerActive?.FirstOrDefault() == null && CapacitorPercent > 50 && UseAfterburner)
  546.         {
  547.             ToggleMicroWarpDrive(true);
  548.             ToggleAfterBurner(true);
  549.         }  
  550.     }
  551.     else
  552.     {
  553.         Host.Log("initiate lock asteroid");
  554.         ClickMenuEntryOnMenuRoot(asteroidOverviewEntryNextNotTargeted, "^lock");
  555.     }
  556.    
  557.     return InBeltMineStep;
  558. }
  559.  
  560.  
  561. Sanderling.Parse.IMemoryMeasurement Measurement =>
  562.     Sanderling?.MemoryMeasurementParsed?.Value;
  563.  
  564. IWindow ModalUIElement =>
  565.     Measurement?.EnumerateReferencedUIElementTransitive()?.OfType<IWindow>()?.Where(window => window?.isModal ?? false)
  566.     ?.OrderByDescending(window => window?.InTreeIndex ?? int.MinValue)
  567.     ?.FirstOrDefault();
  568.  
  569. IEnumerable<Parse.IMenu> Menu => Measurement?.Menu;
  570.  
  571. Parse.IShipUi ShipUi => Measurement?.ShipUi;
  572.  
  573. bool Jammed => ShipUi?.EWarElement?.Any(EwarElement => (EwarElement?.EWarType).RegexMatchSuccess("electronic")) ?? false;
  574.  
  575. Sanderling.Interface.MemoryStruct.IMenuEntry MenuEntryLockTarget =>
  576.     Menu?.FirstOrDefault()?.Entry?.FirstOrDefault(entry => entry.Text.RegexMatchSuccessIgnoreCase("^lock"));
  577.  
  578. Sanderling.Parse.IWindowOverview    WindowOverview  =>
  579.     Measurement?.WindowOverview?.FirstOrDefault();
  580.  
  581. Sanderling.Parse.IWindowInventory   WindowInventory =>
  582.     Measurement?.WindowInventory?.FirstOrDefault();
  583.  
  584. IWindowDroneView    WindowDrones    =>
  585.     Measurement?.WindowDroneView?.FirstOrDefault();
  586.  
  587. ITreeViewEntry InventoryActiveShipOreHold =>
  588.     WindowInventory?.ActiveShipEntry?.TreeEntryFromCargoSpaceType(ShipCargoSpaceTypeEnum.OreHold);
  589.  
  590. IInventoryCapacityGauge OreHoldCapacityMilli =>
  591.     (InventoryActiveShipOreHold?.IsSelected ?? false) ? WindowInventory?.SelectedRightInventoryCapacityMilli : null;
  592.  
  593. int? OreHoldFillPercent => (int?)((OreHoldCapacityMilli?.Used * 100) / OreHoldCapacityMilli?.Max);
  594.  
  595. Tab OverviewPresetTabActive =>
  596.     WindowOverview?.PresetTab
  597.     ?.OrderByDescending(tab => tab?.LabelColorOpacityMilli ?? 0)
  598.     ?.FirstOrDefault();
  599.  
  600. string OverviewTypeSelectionName =>
  601.     WindowOverview?.Caption?.RegexMatchIfSuccess(@"\(([^\)]*)\)")?.Groups?[1]?.Value;
  602.  
  603. Parse.IOverviewEntry[] ListRatOverviewEntry => WindowOverview?.ListView?.Entry?.Where(entry =>
  604.         (entry?.MainIconIsRed ?? false) && (entry?.IsAttackingMe ?? false))
  605.         ?.OrderBy(entry => entry?.DistanceMax ?? int.MaxValue)
  606.         ?.ToArray();
  607.  
  608. Parse.IOverviewEntry[] ListAsteroidOverviewEntry =>
  609.     WindowOverview?.ListView?.Entry
  610.     ?.Where(entry => null != OreTypeFromAsteroidName(entry?.Name) && !IsExcludedBaseOre(entry?.Name))
  611.     ?.OrderBy(entry => entry.DistanceMax ?? int.MaxValue)
  612.     ?.ToArray();
  613.    
  614. Parse.IOverviewEntry[] ListWreckOverviewEntry =>
  615.     WindowOverview?.ListView?.Entry
  616.     ?.Where(entry => null != WreckName(entry?.Name))
  617.     ?.OrderBy(entry => entry.DistanceMax ?? int.MaxValue)
  618.     ?.ToArray();       
  619.  
  620. DroneViewEntryGroup DronesInBayListEntry =>
  621.     WindowDrones?.ListView?.Entry?.OfType<DroneViewEntryGroup>()?.FirstOrDefault(Entry => null != Entry?.Caption?.Text?.RegexMatchIfSuccess(@"Drones in bay", RegexOptions.IgnoreCase));
  622.  
  623. DroneViewEntryGroup DronesInSpaceListEntry =>
  624.     WindowDrones?.ListView?.Entry?.OfType<DroneViewEntryGroup>()?.FirstOrDefault(Entry => null != Entry?.Caption?.Text?.RegexMatchIfSuccess(@"Drones in Local Space", RegexOptions.IgnoreCase));
  625.  
  626. int?    DronesInSpaceCount => DronesInSpaceListEntry?.Caption?.Text?.AsDroneLabel()?.Status?.TryParseInt();
  627. int?    DronesInBayCount => DronesInBayListEntry?.Caption?.Text?.AsDroneLabel()?.Status?.TryParseInt();
  628.  
  629. bool ReadyForManeuverNot =>
  630.     Measurement?.ShipUi?.Indication?.LabelText?.Any(indicationLabel =>
  631.         (indicationLabel?.Text).RegexMatchSuccessIgnoreCase("warp|docking")) ?? false;
  632.  
  633. bool ApproachSomething =>
  634.     Measurement?.ShipUi?.Indication?.LabelText?.Any(indicationLabel =>
  635.         (indicationLabel?.Text).RegexMatchSuccessIgnoreCase("approaching")) ?? false;
  636.  
  637. bool ReadyForManeuver => !ReadyForManeuverNot && !(Measurement?.IsDocked ?? true);
  638.  
  639. //check if target is Asteroid
  640. Sanderling.Parse.IShipUiTarget[] SetTargetAsteroid =>
  641.     Measurement?.Target?.Where(target =>
  642.         target?.TextRow?.Any(textRow => textRow.RegexMatchSuccessIgnoreCase("asteroid")) ?? false)?.ToArray();
  643.        
  644. //check if target is Wreck     
  645. Sanderling.Parse.IShipUiTarget[] SetWreck =>
  646.     Measurement?.Target?.Where(target =>
  647.         target?.TextRow?.Any(textRow => textRow.RegexMatchSuccessIgnoreCase("wreck")) ?? false)?.ToArray();
  648.        
  649. //check if target is own drone     
  650. Sanderling.Parse.IShipUiTarget[] SetTargetDrone =>
  651.     Measurement?.Target?.Where(target =>
  652.         target?.TextRow?.Any(textRow => textRow.RegexMatchSuccessIgnoreCase("hornet|hobgoblin|wasp|vespa")) ?? false)?.ToArray();      
  653.  
  654. Sanderling.Interface.MemoryStruct.IListEntry    WindowInventoryItem =>
  655.     WindowInventory?.SelectedRightInventory?.ListView?.Entry?.FirstOrDefault();
  656.  
  657. Sanderling.Accumulation.IShipUiModule[] SetModuleMiner =>
  658.     Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.Where(module => module?.TooltipLast?.Value?.IsMiner ?? false)?.ToArray();
  659.  
  660. Sanderling.Accumulation.IShipUiModule[] SetModuleMinerInactive   =>
  661.     SetModuleMiner?.Where(module => !(module?.RampActive ?? false))?.ToArray();
  662.    
  663. Sanderling.Accumulation.IShipUiModule[] SetModuleMinerActive     =>
  664.     SetModuleMiner?.Where(module => (module?.RampActive ?? false))?.ToArray();
  665.  
  666. int?    MiningRange => SetModuleMiner?.Select(module =>
  667.     module?.TooltipLast?.Value?.RangeOptimal ?? module?.TooltipLast?.Value?.RangeMax ?? module?.TooltipLast?.Value?.RangeWithin ?? 0)?.DefaultIfEmpty(0)?.Min();;
  668.  
  669. WindowChatChannel chatLocal =>
  670.      Sanderling.MemoryMeasurementParsed?.Value?.WindowChatChannel
  671.      ?.FirstOrDefault(windowChat => windowChat?.Caption?.RegexMatchSuccessIgnoreCase("local") ?? false);
  672.  
  673. //    assuming that own character is always visible in local
  674. bool hostileOrNeutralsInLocal => 1 != chatLocal?.ParticipantView?.Entry?.Count(IsNeutralOrEnemy);
  675.  
  676. //  extract the ore type from the name as seen in overview. "Asteroid (Plagioclase)"
  677. string OreTypeFromAsteroidName(string AsteroidName) =>
  678.     AsteroidName.ValueFromRegexMatchGroupAtIndex(@"Asteroid \(([^\)]+)", 0);
  679.    
  680. //  extract Name of Wreck as seen in Overview
  681. string WreckName(string Name)   =>
  682.     Name.ValueFromRegexMatchGroupAtIndex(@"((Wreck))", 0); 
  683.  
  684. string BaseOreFromAsteroidName(string asteroidName)
  685. {
  686.     return Array.Find<string>(BaseOre, (Predicate<string>)delegate (string s)
  687.     {
  688.         return asteroidName.IndexOf(s, StringComparison.OrdinalIgnoreCase) > -1;
  689.     });
  690. }
  691.  
  692. bool IsExcludedBaseOre(string asteroidName) {
  693.     return Array.Exists<string>(ExcludedBaseOre, (Predicate<string>)delegate (string s)
  694.     {
  695.         return asteroidName.IndexOf(s, StringComparison.OrdinalIgnoreCase) > -1;
  696.     });
  697. }
  698.  
  699. void ClickMenuEntryOnMenuRoot(IUIElement MenuRoot, string MenuEntryRegexPattern)
  700. {
  701.     Sanderling.MouseClickRight(MenuRoot);
  702.    
  703.     var Menu = Measurement?.Menu?.FirstOrDefault();
  704.    
  705.     var MenuEntry = Menu?.EntryFirstMatchingRegexPattern(MenuEntryRegexPattern, RegexOptions.IgnoreCase);
  706.    
  707.     Sanderling.MouseClickLeft(MenuEntry);
  708. }
  709.  
  710. void EnsureWindowInventoryOpen()
  711. {
  712.     if (null != WindowInventory)
  713.         return;
  714.  
  715.     Host.Log("open Inventory.");
  716.     Sanderling.MouseClickLeft(Measurement?.Neocom?.InventoryButton);
  717. }
  718.  
  719. void EnsureWindowInventoryOpenOreHold()
  720. {
  721.     EnsureWindowInventoryOpen();
  722.  
  723.     var inventoryActiveShip = WindowInventory?.ActiveShipEntry;
  724.  
  725.     if(InventoryActiveShipOreHold == null && !(inventoryActiveShip?.IsExpanded ?? false))
  726.         Sanderling.MouseClickLeft(inventoryActiveShip?.ExpandToggleButton);
  727.  
  728.     if(!(InventoryActiveShipOreHold?.IsSelected ?? false))
  729.         Sanderling.MouseClickLeft(InventoryActiveShipOreHold);
  730. }
  731.  
  732. //  sample label text: Intensive Reprocessing Array <color=#66FFFFFF>1,123 m</color>
  733. string InventoryContainerLabelRegexPatternFromContainerName(string containerName) =>
  734.     @"^\s*" + Regex.Escape(containerName) + @"\s*($|\<)";
  735.  
  736. void InInventoryUnloadItems() => InInventoryUnloadItemsTo(UnloadDestContainerName);
  737.  
  738. void InInventoryUnloadItemsTo(string DestinationContainerName)
  739. {
  740.     Host.Log("unload items to '" + DestinationContainerName + "'.");
  741.  
  742.     EnsureWindowInventoryOpenOreHold();
  743.  
  744.     for (;;)
  745.     {
  746.         var oreHoldListItem = WindowInventory?.SelectedRightInventory?.ListView?.Entry?.ToArray();
  747.  
  748.         var oreHoldItem = oreHoldListItem?.FirstOrDefault();
  749.  
  750.         if(null == oreHoldItem)
  751.         {  
  752.             Host.Log("done unload items");
  753.             break;    //    0 items in OreHold
  754.         }
  755.        
  756.         if(1 < oreHoldListItem?.Length)
  757.             ClickMenuEntryOnMenuRoot(oreHoldItem, @"select\s*all");
  758.  
  759.         var DestinationContainerLabelRegexPattern =
  760.             InventoryContainerLabelRegexPatternFromContainerName(DestinationContainerName);
  761.  
  762.         var DestinationContainer =
  763.             WindowInventory?.LeftTreeListEntry?.SelectMany(entry => new[] { entry }.Concat(entry.EnumerateChildNodeTransitive()))
  764.             ?.FirstOrDefault(entry => entry?.Text?.RegexMatchSuccessIgnoreCase(DestinationContainerLabelRegexPattern) ?? false);
  765.  
  766.         if (null == DestinationContainer)
  767.             Host.Log("error: Inventory entry labeled '" + DestinationContainerName + "' not found");
  768.  
  769.         Sanderling.MouseDragAndDrop(oreHoldItem, DestinationContainer);
  770.     }
  771. }
  772.  
  773. var ConnectionLost = Measurement?.WindowOther?.FirstOrDefault()?.LabelText?.FirstOrDefault(text => (text?.Text.RegexMatchSuccessIgnoreCase("Connection") ?? false));
  774. if (ConnectionLost != null)
  775. {
  776.         Host.Log("               Lost connection at : " + DateTime.Now.ToString(" HH:mm")+ "" );
  777.         Console.Beep(1047,150);
  778.         Host.Delay(150);
  779.         Console.Beep(1047,150);
  780.         Host.Delay(150);
  781.         return BotStopActivity;
  782. }
  783. bool InitiateWarpToRandomMiningSite()   =>
  784.     InitiateDockToOrWarpToBookmark(RandomElement(SetMiningSiteBookmark));
  785.  
  786. bool InitiateWarpToRandomMiningBookmark() =>
  787.     InitiateDockToOrWarpToLocationInSolarSystemMenu(RandomElement(SetMiningSiteBookmark));
  788.  
  789. bool InitiateWarpToMiningSite() =>
  790.     InitiateDockToOrWarpToLocationInSolarSystemMenu("Asteroid Belts", PickNextMiningSiteFromSystemMenu);
  791.  
  792. bool InitiateDockToOffload()    =>
  793.     InitiateDockToOrWarpToLocationInSolarSystemMenu(UnloadBookmark, PickPlaceToOffloadfFromSystemMenu);
  794.  
  795. //bool InitiateWarpToRetreat()  =>  InitiateDockToOrWarpToLocationInSolarSystemMenu("stations");
  796.  
  797. MemoryStruct.IMenuEntry PickNextMiningSiteFromSystemMenu(IReadOnlyList<MemoryStruct.IMenuEntry> availableMenuEntries)
  798. {
  799.     Host.Log("I am seeing " + availableMenuEntries?.Count.ToString() + " mining sites to choose from.");
  800.  
  801.     var nextSite =
  802.         availableMenuEntries
  803.         ?.OrderBy(menuEntry => visitedLocations.ToList().IndexOf(menuEntry?.Text))
  804.         ?.FirstOrDefault();
  805.  
  806.     Host.Log("I pick '" + nextSite?.Text + "' as next mining site, based on the intent to rotate through the mining sites and recorded previous locations.");
  807.     return nextSite;
  808. }
  809.  
  810. MemoryStruct.IMenuEntry PickPlaceToOffloadfFromSystemMenu(IReadOnlyList<MemoryStruct.IMenuEntry> availableMenuEntries)
  811. {
  812.     Host.Log("I am seeing " + availableMenuEntries?.Count.ToString() + " stations to choose from for offloading ore.");
  813.  
  814.     var availableMenuEntriesTexts =
  815.         availableMenuEntries
  816.         ?.Select(menuEntry => menuEntry.Text)
  817.         ?.ToList();
  818.  
  819.     foreach(var visitedLocation in visitedLocations.Reverse())
  820.     {
  821.         var visitedLocationMenuEntry =
  822.             availableMenuEntries?.FirstOrDefault(menuEntry =>
  823.                 StationFromSystemInfoPanelEqualsStationFromSystemMenu(visitedLocation, menuEntry?.Text));
  824.  
  825.         if(visitedLocationMenuEntry == null)
  826.             continue;
  827.  
  828.         Host.Log("I pick '" + visitedLocationMenuEntry?.Text + "' as destination, because this is the last one visited.");
  829.         return visitedLocationMenuEntry;
  830.     }
  831.  
  832.     var dockMenuEntry = availableMenuEntries?.Where(x => x?.Text?.Contains("Dock") ?? false)?.FirstOrDefault();
  833.     var destination = dockMenuEntry ?? availableMenuEntries?.FirstOrDefault();
  834.  
  835.     Host.Log("I pick '" + destination?.Text + "' as destination, because I do not remember having visited any of the available stations.");
  836.     return destination;
  837. }
  838.  
  839. bool InitiateDockToOrWarpToLocationInSolarSystemMenu(
  840.     string submenuLabel,
  841.     Func<IReadOnlyList<MemoryStruct.IMenuEntry>, MemoryStruct.IMenuEntry> pickPreferredDestination = null)
  842. {  
  843.     Host.Log("Attempt to initiate dock to or warp to menu entry in submenu '" + submenuLabel + "'");
  844.    
  845.     DroneEnsureInBay();
  846.    
  847.     var listSurroundingsButton = Measurement?.InfoPanelCurrentSystem?.ListSurroundingsButton;
  848.    
  849.     Sanderling.MouseClickRight(listSurroundingsButton);
  850.  
  851.     var submenuEntry = Measurement?.Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("^" + submenuLabel + "$", RegexOptions.IgnoreCase);
  852.  
  853.     if(null == submenuEntry)
  854.     {
  855.         Host.Log("Submenu '" + submenuLabel + "' not found in the solar system menu.");
  856.         return true;
  857.     }
  858.  
  859.     Sanderling.MouseClickLeft(submenuEntry);
  860.  
  861.     var submenu = Measurement?.Menu?.ElementAtOrDefault(1);
  862.  
  863.     var destinationMenuEntry = pickPreferredDestination?.Invoke(submenu?.Entry?.ToList()) ?? submenu?.Entry?.FirstOrDefault();
  864.  
  865.     if(destinationMenuEntry == null)
  866.     {
  867.         Host.Log("Failed to open submenu '" + submenuLabel + "' in the solar system menu.");
  868.         return true;
  869.     }
  870.  
  871.     Sanderling.MouseClickLeft(destinationMenuEntry);
  872.  
  873.     var actionsMenu = Measurement?.Menu?.ElementAtOrDefault(2);
  874.  
  875.     if(destinationMenuEntry == null)
  876.     {
  877.         Host.Log("Failed to open actions menu for '" + destinationMenuEntry.Text + "' in the solar system menu.");
  878.         return true;
  879.     }
  880.  
  881.     var dockMenuEntry = actionsMenu?.EntryFirstMatchingRegexPattern("dock", RegexOptions.IgnoreCase);
  882.     var warpMenuEntry = actionsMenu?.EntryFirstMatchingRegexPattern(@"warp.*within.*m", RegexOptions.IgnoreCase);
  883.     var approachEntry = actionsMenu?.EntryFirstMatchingRegexPattern(@"approach", RegexOptions.IgnoreCase);
  884.  
  885.     var maneuverMenuEntry = dockMenuEntry ?? warpMenuEntry;
  886.  
  887.     if (null != maneuverMenuEntry)
  888.     {
  889.         Host.Log("initiating '" + maneuverMenuEntry.Text + "' on '" + destinationMenuEntry?.Text + "'");
  890.         Sanderling.MouseClickLeft(maneuverMenuEntry);
  891.         return false;
  892.     }
  893.  
  894.     if (null != approachEntry)
  895.     {
  896.         Host.Log("found menu entry '" + approachEntry.Text + "'. Assuming we are already there.");
  897.         return false;
  898.     }
  899.  
  900.     Host.Log("no suitable menu entry found on '" + destinationMenuEntry?.Text + "'");
  901.     return true;
  902. }
  903.  
  904. bool InitiateDockToOrWarpToBookmark(string bookmarkOrFolder)
  905. {
  906.     Host.Log("dock to or warp to bookmark or random bookmark in folder: '" + bookmarkOrFolder + "'");
  907.    
  908.     DroneEnsureInBay();
  909.    
  910.     var listSurroundingsButton = Measurement?.InfoPanelCurrentSystem?.ListSurroundingsButton;
  911.    
  912.     Sanderling.MouseClickRight(listSurroundingsButton);
  913.    
  914.     var bookmarkMenuEntry = Measurement?.Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("^" + bookmarkOrFolder + "$", RegexOptions.IgnoreCase);
  915.  
  916.     if(null == bookmarkMenuEntry)
  917.     {
  918.         Host.Log("menu entry not found for bookmark or folder: '" + bookmarkOrFolder + "'");
  919.         return true;
  920.     }
  921.  
  922.     var currentLevelMenuEntry = bookmarkMenuEntry;
  923.  
  924.     for (var menuLevel = 1; ; ++menuLevel)
  925.     {
  926.         Sanderling.MouseClickLeft(currentLevelMenuEntry);
  927.  
  928.         var menu = Measurement?.Menu?.ElementAtOrDefault(menuLevel);
  929.         var dockMenuEntry = menu?.EntryFirstMatchingRegexPattern("dock", RegexOptions.IgnoreCase);
  930.         var warpMenuEntry = menu?.EntryFirstMatchingRegexPattern(@"warp.*within\s*0", RegexOptions.IgnoreCase);
  931.         var approachEntry = menu?.EntryFirstMatchingRegexPattern(@"approach", RegexOptions.IgnoreCase);
  932.  
  933.         var maneuverMenuEntry = dockMenuEntry ?? warpMenuEntry;
  934.  
  935.         if (null != maneuverMenuEntry)
  936.         {
  937.             Host.Log("initiating '" + maneuverMenuEntry.Text + "' on entry '" + currentLevelMenuEntry?.Text + "'");
  938.             Sanderling.MouseClickLeft(maneuverMenuEntry);
  939.             return false;
  940.         }
  941.  
  942.         if (null != approachEntry)
  943.         {
  944.             Host.Log("found menu entry '" + approachEntry.Text + "'. Assuming we are already there.");
  945.             return false;
  946.         }
  947.  
  948.         var setBookmarkOrFolderMenuEntry =
  949.             menu?.Entry;    //  assume that each entry on the current menu level is a bookmark or a bookmark folder.
  950.  
  951.         var nextLevelMenuEntry = RandomElement(setBookmarkOrFolderMenuEntry);
  952.  
  953.         if(null == nextLevelMenuEntry)
  954.         {
  955.             Host.Log("no suitable menu entry found");
  956.             return true;
  957.         }
  958.  
  959.         currentLevelMenuEntry = nextLevelMenuEntry;
  960.     }
  961. }
  962.  
  963. void Undock()
  964. {
  965.     while(Measurement?.IsDocked ?? true)
  966.     {
  967.         Sanderling.MouseClickLeft(Measurement?.WindowStation?.FirstOrDefault()?.UndockButton);
  968.         Host.Log("waiting for undocking to complete.");
  969.         Host.Delay(7000);
  970.     }
  971.  
  972.     Host.Delay(1000);
  973.     Sanderling.InvalidateMeasurement();
  974. }
  975.  
  976. void ModuleMeasureAllTooltip()
  977. {
  978.     Host.Log("measure tooltips of all modules.");
  979.  
  980.     for (;;)
  981.     {
  982.         var NextModule = Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.FirstOrDefault(m => null == m?.TooltipLast);
  983.  
  984.         if(null == NextModule)
  985.         {
  986.             Host.Log("found all Moduls.");
  987.             break;
  988.         }
  989.        
  990.         Host.Log("measure module."+ NextModule);
  991.         //  take multiple measurements of module tooltip to reduce risk to keep bad read tooltip.
  992.         Sanderling.MouseMove(NextModule);
  993.         Sanderling.WaitForMeasurement();
  994.         Sanderling.MouseMove(NextModule);
  995.         Sanderling.WaitForMeasurement();
  996.     }
  997. }
  998.  
  999. /*
  1000. void ActivateHardenerExecute()
  1001. {
  1002.     var SubsetModuleHardener =
  1003.         Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.Where(module => module?.TooltipLast?.Value?.IsHardener ?? false);
  1004.        
  1005.     var SubsetModuleToToggle =
  1006.         SubsetModuleHardener?.Where(module => !(module?.RampActive ?? false));
  1007.  
  1008.     foreach (var Module in SubsetModuleToToggle.EmptyIfNull())
  1009.         ModuleToggle(Module);
  1010. }
  1011. */
  1012.  
  1013. // Hardener
  1014. Sanderling.Accumulation.IShipUiModule[] SetModuleHardener =>
  1015.     Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.Where(module => module?.TooltipLast?.Value?.IsHardener ?? false)?.ToArray();
  1016.  
  1017. void ToggelHardener(bool turnOn = true){
  1018.     var Hardener = SetModuleHardener?.FirstOrDefault();
  1019.  
  1020.     if((Hardener?.RampActive ?? false) !=turnOn)
  1021.     {      
  1022.         Host.Log("toggle Hardener "+ turnOn);
  1023.         ModuleToggle(Hardener);
  1024.     }
  1025. }
  1026.  
  1027. // get all shield boosters in one array
  1028. Sanderling.Accumulation.IShipUiModule[] SetModuleShieldBoosters => Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.Where(module => module?.TooltipLast?.Value?.IsShieldBooster ?? false)?.ToArray();
  1029.  
  1030. // if true then we should turn on shield booster if false - turn off
  1031. void ToggleShieldBooster(bool turnOn = true)
  1032. {
  1033.     var shieldBooster = SetModuleShieldBoosters?.FirstOrDefault();
  1034.     if((shieldBooster?.RampActive ?? false) !=turnOn)
  1035.     {      
  1036.         Host.Log("toggle Shield Booster "+ turnOn);
  1037.         ModuleToggle(shieldBooster);
  1038.     }
  1039. }
  1040. // get all micro warp drive in one array
  1041. Sanderling.Accumulation.IShipUiModule[] SetModuleMicroWarpDrive => Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.Where(module => module?.TooltipLast?.Value?.IsMicroWarpDrive ?? false)?.ToArray();
  1042.    
  1043. // if true then we should turn on MicorBurn; if false - turn off
  1044. void ToggleMicroWarpDrive(bool turnOn = true)
  1045. {
  1046.     var microWarp = SetModuleMicroWarpDrive?.FirstOrDefault();
  1047.     if((microWarp?.RampActive ?? false) !=turnOn)
  1048.     {      
  1049.         Host.Log("toggle Micro Warp Drive "+ turnOn);
  1050.         ModuleToggle(microWarp);
  1051.     }
  1052. }
  1053.  
  1054. // afterburner
  1055. Sanderling.Accumulation.IShipUiModule[] SetModuleAfterBurnerDrive =>Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.Where(module => module?.TooltipLast?.Value?.IsAfterburner ?? false)?.ToArray(); 
  1056.  
  1057. void ToggleAfterBurner(bool turnOn = true)
  1058. {
  1059.     var afterBurner = SetModuleAfterBurnerDrive?.FirstOrDefault();
  1060.     if((afterBurner?.RampActive ?? false) !=turnOn)
  1061.     {      
  1062.         Host.Log("toggle AfterBurner "+ turnOn);
  1063.         ModuleToggle(afterBurner);
  1064.     }
  1065. }
  1066.  
  1067. // Mining Crystal
  1068. void LoadMiningCrystal(Sanderling.Accumulation.IShipUiModule Module, string baseOre)
  1069. {
  1070.     Sanderling.MouseClickRight(Module);
  1071.     var menuCrystal = Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern(baseOre +".*mining.*crystal", RegexOptions.IgnoreCase);
  1072.     if (menuCrystal != null)
  1073.         Sanderling.MouseClickLeft(menuCrystal);
  1074. }
  1075.  
  1076. void LoadMiningCrystalForTarget(Sanderling.Accumulation.IShipUiModule module, Sanderling.Parse.IShipUiTarget target)
  1077. {
  1078.     string[] targetTextRow = target?.TextRow;
  1079.     if (targetTextRow != null && targetTextRow.Length > 0) {
  1080.         string baseOre = BaseOreFromAsteroidName(String.Join(" ", targetTextRow));
  1081.         if (!String.IsNullOrEmpty(baseOre)) {
  1082.             Sanderling.MouseMove(module);
  1083.             Sanderling.WaitForMeasurement();
  1084.             var foundCrystal = module?.TooltipLast?.Value?.LabelText?.FirstOrDefault(entry => entry.Text.RegexMatchSuccessIgnoreCase("Mining Crystal"));
  1085.             //IEnumerable<Sanderling.Interface.MemoryStruct.UIElementText> foundLabels = module?.TooltipLast?.Value?.LabelText?.Text.Where(lbl => lbl.Text.Contains("Mining Crystal"));
  1086.            
  1087.             if (foundCrystal != null && foundCrystal.Text.Contains(baseOre))
  1088.                 return;
  1089.            
  1090.             Sanderling.MouseClickRight(module);
  1091.             var menuCrystal = Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern(baseOre +".*mining.*crystal", RegexOptions.IgnoreCase);
  1092.            
  1093.             if (menuCrystal != null)
  1094.                 Sanderling.MouseClickLeft(menuCrystal);
  1095.             else if (foundCrystal != null)
  1096.                 Sanderling.MouseClickLeft( Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("unload to cargo", RegexOptions.IgnoreCase));
  1097.             else
  1098.                 Sanderling.MouseClickLeft(target);
  1099.         }
  1100.     }
  1101. }
  1102.  
  1103. void ModuleToggle(Sanderling.Accumulation.IShipUiModule Module)
  1104. {
  1105.     var ToggleKey = Module?.TooltipLast?.Value?.ToggleKey;
  1106.  
  1107.     Host.Log("toggle module using " + (null == ToggleKey ? "mouse" : Module?.TooltipLast?.Value?.ToggleKeyTextLabel?.Text));
  1108.  
  1109.     if(null == ToggleKey)
  1110.         Sanderling.MouseClickLeft(Module);
  1111.     else
  1112.         Sanderling.KeyboardPressCombined(ToggleKey);
  1113. }
  1114.  
  1115. void EnsureOverviewTypeSelectionLoaded()
  1116. {
  1117.     if(null == OverviewPresetTabActive || null == WindowOverview || null == OverviewPreset)
  1118.         return;
  1119.  
  1120.     if(string.Equals(OverviewTypeSelectionName, OverviewPreset, StringComparison.OrdinalIgnoreCase))
  1121.         return;
  1122.  
  1123.     Host.Log("loading preset '" + OverviewPreset + "' to overview (current selection is '" + OverviewTypeSelectionName + "').");
  1124.     Sanderling.MouseClickRight(OverviewPresetTabActive);
  1125.     Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("load.*preset", RegexOptions.IgnoreCase));
  1126.     var PresetMenuEntry = Menu?.ElementAtOrDefault(1)?.EntryFirstMatchingRegexPattern(@"^\s*" + Regex.Escape(OverviewPreset) + @"\s*$", RegexOptions.IgnoreCase);
  1127.  
  1128.     if(null == PresetMenuEntry)
  1129.     {
  1130.         Host.Log("error: menu entry '" + OverviewPreset + "' not found");
  1131.         return;
  1132.     }
  1133.  
  1134.     Sanderling.MouseClickLeft(PresetMenuEntry);
  1135. }
  1136.  
  1137. void MemoryUpdate()
  1138. {
  1139.     RetreatUpdate();
  1140.     JammedLastTimeUpdate();
  1141.     UpdateLocationRecord();
  1142.     OffloadCountUpdate();
  1143. }
  1144.  
  1145. /*
  1146. 2018-03 Observation: Station name containing reference to moon appears different between system menu and system info panel.
  1147. In the info panel 'Moon 17' was used while in the system menu it was 'M17'.
  1148. */
  1149. public bool StationFromSystemInfoPanelEqualsStationFromSystemMenu(
  1150.     string stationNameInCurrentSystemInfoPanel,
  1151.     string stationNameInSystemMenu)
  1152. {
  1153.     //  Copied from https://github.com/botengine-de/Optimat.EO/blob/6c19e8f36e30d5468e94d627eb16dcb78bb47d12/src/Optimat.EveOnline.Bot/Sonst/AgentUndMission.Aktualisiire.cs#L1888-L1893
  1154.  
  1155.     var representationPattern =
  1156.         Regex.Replace(
  1157.         stationNameInCurrentSystemInfoPanel,
  1158.         "Moon\\s*",
  1159.         "M([\\w]*\\s*)",
  1160.         RegexOptions.IgnoreCase);
  1161.  
  1162.     return
  1163.         stationNameInSystemMenu.RegexMatchSuccessIgnoreCase(representationPattern);
  1164. }
  1165.  
  1166. void JammedLastTimeUpdate()
  1167. {
  1168.     if(Jammed)
  1169.         JammedLastTime  = Host.GetTimeContinuousMilli();
  1170. }
  1171.  
  1172. bool MeasurementEmergencyWarpOutEnter =>
  1173.     !(Measurement?.IsDocked ?? false) && !(EmergencyWarpOutHitpointPercent < ShieldHpPercent);
  1174.  
  1175. void RetreatUpdate()
  1176. {
  1177.     RetreatReasonTemporary = (RetreatOnNeutralOrHostileInLocal && hostileOrNeutralsInLocal) ? "hostile or neutral in local" : null;
  1178.  
  1179.     if (!MeasurementEmergencyWarpOutEnter)
  1180.         return;
  1181.  
  1182.     //  measure multiple times to avoid being scared off by noise from a single measurement.
  1183.     Sanderling.InvalidateMeasurement();
  1184.  
  1185.     if (!MeasurementEmergencyWarpOutEnter)
  1186.         return;
  1187.  
  1188.     RetreatReasonPermanent = "shield hp";
  1189. }
  1190.  
  1191. void OffloadCountUpdate()
  1192. {
  1193.     var OreHoldFillPercentSynced    = OreHoldFillPercent;
  1194.  
  1195.     if(!OreHoldFillPercentSynced.HasValue)
  1196.         return;
  1197.  
  1198.     if(0 == OreHoldFillPercentSynced && OreHoldFillPercentSynced < LastCheckOreHoldFillPercent)
  1199.         ++OffloadCount;
  1200.  
  1201.     LastCheckOreHoldFillPercent = OreHoldFillPercentSynced;
  1202. }
  1203.  
  1204. void UpdateLocationRecord()
  1205. {
  1206.     //  I am not interested in locations which are only close during warp.
  1207.     if (Measurement?.ShipUi?.Indication?.ManeuverType == ShipManeuverTypeEnum.Warp)
  1208.         return;
  1209.  
  1210.     // Purpose of recording locations is to prioritize our next destination when warping to mining site or docking to station.
  1211.     // For this purpose, I will compare the recorded locations with the menu entries in the system menu.
  1212.     // Therefore I want the format of the recorded location to be the same as it appears in the menu entries in the system menu.
  1213.  
  1214.     var currentSystemLocationLabelText =
  1215.         Measurement?.InfoPanelCurrentSystem?.ExpandedContent?.LabelText
  1216.         ?.OrderByCenterVerticalDown()?.FirstOrDefault()?.Text;
  1217.  
  1218.     if (currentSystemLocationLabelText == null)
  1219.         return;
  1220.  
  1221.     // 2018-03 observed label text: <url=showinfo:15//40088644 alt='Nearest'>Amsen V - Asteroid Belt 1</url>
  1222.  
  1223.     var currentLocationName = RegexExtension.RemoveXmlTag(currentSystemLocationLabelText)?.Trim();
  1224.  
  1225.     var lastRecordedLocation = visitedLocations.LastOrDefault();
  1226.  
  1227.     if (lastRecordedLocation == currentLocationName)
  1228.         return;
  1229.  
  1230.     visitedLocations.Enqueue(currentLocationName);
  1231.     Host.Log("Recorded transition from location '" + lastRecordedLocation + "' to location '" + currentLocationName + "'");
  1232.  
  1233.     if (100 < visitedLocations.Count)
  1234.         visitedLocations.Dequeue();
  1235. }
  1236.  
  1237. bool IsNeutralOrEnemy(IChatParticipantEntry participantEntry) =>
  1238.    !(participantEntry?.FlagIcon?.Any(flagIcon =>
  1239.      new[] { "good standing", "excellent standing", "Pilot is in your (fleet|corporation)", }
  1240.      .Any(goodStandingText =>
  1241.         flagIcon?.HintText?.RegexMatchSuccessIgnoreCase(goodStandingText) ?? false)) ?? false);
Advertisement
Add Comment
Please, Sign In to add comment