Advertisement
Guest User

Orca Drones minig script v1.1

a guest
Aug 26th, 2018
641
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 27.44 KB | None | 0 0
  1. /* Ver: 1.1 ORCA DRONES: SPACE 1.0-0.8
  2. This bot mines ore only with drones. It using a bookmark folder for chosen belts and take them in order. It unload the ore in "home" station.
  3. Before running this bot, prepare the EVE online client as follows:
  4. + Set the UI language to english.
  5. + Move your mining ship to a solar system which has asteroid belts and at least one station in which you can dock.
  6. + 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.
  7. + Set Overview to sort by distance with the nearest entry at the top.
  8. + In the Inventory, select the 'List' view.
  9. + Enable the info panel 'System info'. The bot needs this to find asteroid belts and stations.
  10. + Arrange windows to not occlude ship modules or info panels.
  11. + Create your own bookmark "home"
  12. + Create your own Folder for mining Belts
  13.  ( for now is named asteroid belts. If you change him, change also in script settings)
  14. + Only if you change the folder name for bookmarks, create your own bookmarks for mining and put them INSIDE of folder
  15. Preparations of bot:
  16. + fill/change the MiningRange
  17. + DroneNumber
  18. + Change the name on folder for bookmarks (if you need)
  19. + At what lvl of ore hold you go to unload
  20. This script is based on Terpla && Viir scripts and adapted
  21. */
  22.  
  23. using BotSharp.ToScript.Extension;
  24. using MemoryStruct = Sanderling.Interface.MemoryStruct;
  25. using Parse = Sanderling.Parse;
  26.  
  27. //  Begin of configuration section ->
  28.  
  29. //  The bot loads this preset to the active tab in the Overview window.
  30. string OverviewPreset = null;
  31.  
  32. //  Activate shield hardener.
  33. var ActivateHardener = true;
  34.  
  35. //mining range (in metric)
  36. int MiningRange = 8000;
  37. // drones
  38. int DroneNumber = 5;
  39.  
  40. //the name of folder of bookmarks for mining
  41. string FolderBeltsMining = "Orca";
  42.  
  43. //  Name of the container to unload to as shown in inventory.
  44. string UnloadDestContainerName = "Item Hangar";
  45.  
  46. //  Bookmark of location where ore should be unloaded.
  47. string UnloadBookmark = "Unload";
  48.  
  49. //  Percentage of fill level at which to enter the offload process.
  50. var EnterOffloadOreContainerFillPercent = 98;
  51.  
  52. //  Bot will switch mining site when rats are visible and shield hitpoints are lower than this value.
  53. var SwitchMiningSiteHitpointThresholdPercent = 95;
  54.  
  55. var EmergencyWarpOutHitpointPercent = 90;
  56.  
  57.  
  58.  
  59.  
  60.  
  61. //  Bookmark of place to retreat to to prevent ship loss.
  62. string RetreatBookmark = UnloadBookmark;
  63.  
  64. const string StatusStringFromDroneEntryTextRegexPattern = @"\((.*)\)";
  65. static public string StatusStringFromDroneEntryText(this string droneEntryText) => droneEntryText?.RegexMatchIfSuccess(StatusStringFromDroneEntryTextRegexPattern)?.Groups[1]?.Value?.RemoveXmlTag()?.Trim();
  66.  
  67.  
  68. bool returnDronesToBayOnRetreat = true;
  69. //  <- End of configuration section
  70.  
  71.  
  72. Func<object> BotStopActivity = () => null;
  73.  
  74. Func<object> NextActivity = MainStep;
  75.  
  76. Queue<string> visitedLocations = new Queue<string>();
  77.  
  78.  
  79.  
  80. for(;;)
  81. {
  82.     var stepBeginTimeMilli = Host.GetTimeContinuousMilli();
  83.  
  84.     MemoryUpdate();
  85.  
  86.     Host.Log(
  87.         "Stats: ore container fill: " + OreContainerFillPercent + "%" +
  88.         ", mining range from settings: " + MiningRange +
  89.         ", shield.hp: " + ShieldHpPercent + "%" +
  90.         ", retreat: " + RetreatReason +
  91.         ", JLA: " + JammedLastAge +
  92.         ", overview.roids: " + ListAsteroidOverviewEntry?.Length +
  93.         ", offload count: " + OffloadCount +
  94.         ", nextAct: " + NextActivity?.Method?.Name);
  95.  
  96.     CloseModalUIElement();
  97.  
  98.     if(0 < RetreatReason?.Length && !(Measurement?.IsDocked ?? false))
  99.     {
  100.     Host.Log("1 ");
  101.         if ((returnDronesToBayOnRetreat)  && (0 != DronesInSpaceCount))
  102.          DroneEnsureInBay();
  103.          
  104.     if (!returnDronesToBayOnRetreat || (returnDronesToBayOnRetreat && 0 == DronesInSpaceCount))
  105.     {
  106.     Host.Log("2 ");
  107.         ClickMenuEntryOnPatternMenuRoot(Measurement?.InfoPanelCurrentSystem?.ListSurroundingsButton, RetreatBookmark, "Dock");
  108.     }
  109.         continue;
  110.     }
  111.  
  112.     NextActivity = NextActivity?.Invoke() as Func<object>;
  113.  
  114.     if(BotStopActivity == NextActivity)
  115.         break;
  116.  
  117.     if(null == NextActivity)
  118.         NextActivity = MainStep;
  119.  
  120.     Host.Delay((int)Math.Max(0, 1000 - (Host.GetTimeContinuousMilli() - stepBeginTimeMilli)));
  121. }
  122.  
  123. bool? ShipHasOreHold
  124. {
  125.     get
  126.     {
  127.         var inventoryActiveShipEntry = WindowInventory?.ActiveShipEntry;
  128.  
  129.         //  If the tree entry for the ship is not expanded....
  130.         if(!(IsExpanded(inventoryActiveShipEntry) ?? false))
  131.             return null;    // Then I do not know if there is an ore hold.
  132.  
  133.         return inventoryActiveShipEntry?.TreeEntryFromCargoSpaceType(ShipCargoSpaceTypeEnum.OreHold) != null;
  134.     }
  135. }
  136.    
  137.  
  138. //  seconds since ship was jammed.
  139. long? JammedLastAge => Jammed ? 0 : (Host.GetTimeContinuousMilli() - JammedLastTime) / 1000;
  140.  
  141. int?    ShieldHpPercent => ShipUi?.HitpointsAndEnergy?.Shield / 10;
  142.  
  143. bool    ShouldSwitchMiningSite =>
  144.     !(Measurement?.IsDocked ?? false) &&
  145.     !(SwitchMiningSiteHitpointThresholdPercent < ShieldHpPercent) || JammedLastAge < 10;
  146.  
  147. bool    OreContainerFilledForOffload => Math.Max(0, Math.Min(100, EnterOffloadOreContainerFillPercent)) <= OreContainerFillPercent;
  148.  
  149. Int64?  JammedLastTime = null;
  150. string RetreatReasonTemporary = null;
  151. string RetreatReasonPermanent = null;
  152. string RetreatReason => RetreatReasonPermanent ?? RetreatReasonTemporary;
  153. int? LastCheckOreContainerFillPercent = null;
  154.  
  155. int OffloadCount = 0;
  156.  
  157. Func<object>    MainStep()
  158. {
  159.     if(Measurement?.IsDocked ?? false)
  160.     {
  161.         InInventoryUnloadItems();
  162. Host.Log("cargo hold unloaded ");
  163.         if (0 < RetreatReasonPermanent?.Length)
  164.             return BotStopActivity;
  165.  
  166.         if (0 < RetreatReason?.Length)
  167.         {Host.Log("return to mainstep ");
  168.             return MainStep;
  169. }
  170.         Undock();
  171.     }
  172.  
  173.     EnsureOverviewTypeSelectionLoaded();
  174.  
  175.     EnsureWindowInventoryOreContainerIsOpen();
  176.  
  177.     if(ReadyForManeuver)
  178.     {
  179.         DroneEnsureInBay();
  180.         Host.Log("ready");
  181.         if(OreContainerFilledForOffload)
  182.         {
  183.             Host.Log("I'm full, go to unload");
  184.             DroneEnsureInBay();
  185.             if(ReadyForManeuver)
  186.                 ClickMenuEntryOnPatternMenuRoot(Measurement?.InfoPanelCurrentSystem?.ListSurroundingsButton, RetreatBookmark, "Dock");
  187.             return MainStep;
  188.         }
  189.  
  190.         if(!(0 < ListAsteroidOverviewEntry?.Length) || ShouldSwitchMiningSite)
  191.         {Host.Log("warping ");
  192.         InitiateWarpToMiningSite();
  193.         }
  194.  
  195.         ModuleMeasureAllTooltip();
  196.  
  197.         if(ActivateHardener)
  198.         ActivateHardenerExecute();
  199.  
  200.     }
  201.     return InBeltMineStep;
  202. }
  203.  
  204. void CloseModalUIElement()
  205. {
  206.     var ButtonClose =
  207.         ModalUIElement?.ButtonText?.FirstOrDefault(button => (button?.Text).RegexMatchSuccessIgnoreCase("close|no|ok"));
  208.  
  209.     Sanderling.MouseClickLeft(ButtonClose);
  210. }
  211. void DroneLaunch()
  212. {
  213.     Host.Log("launch drones.");
  214.     Sanderling.MouseClickRight(DronesInBayListEntry);
  215.     Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("launch", RegexOptions.IgnoreCase));
  216. }
  217.  
  218. void DroneEnsureInBay()
  219. {
  220.     if (0 == DronesInSpaceCount)
  221.         return;
  222.     DroneReturnToBay();
  223.     Host.Delay(4444);
  224. }
  225.  
  226. void DroneReturnToBay()
  227. {
  228.     Host.Log("return drones to bay.");
  229.     Sanderling.MouseClickRight(DronesInSpaceListEntry);
  230.     Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("return.*bay", RegexOptions.IgnoreCase));
  231.     // Sanderling.KeyboardPressCombined(new[]{ targetLockedKeyCode, VirtualKeyCode.VK_R });//if you like
  232. }
  233.  
  234. Func<object> InBeltMineStep()
  235. {
  236.     var droneListView = Measurement?.WindowDroneView?.FirstOrDefault()?.ListView;
  237.  
  238.     var droneGroupWithNameMatchingPattern = new Func<string, DroneViewEntryGroup>(namePattern =>
  239.         droneListView?.Entry?.OfType<DroneViewEntryGroup>()?.FirstOrDefault(group => group?.LabelTextLargest()?.Text?.RegexMatchSuccessIgnoreCase(namePattern) ?? false));
  240.  
  241.  
  242.     var droneGroupInLocalSpace = droneGroupWithNameMatchingPattern("local space");
  243.  
  244.     var setDroneInLocalSpace = droneListView?.Entry?.OfType<DroneViewEntryItem>()
  245.         ?.Where(drone => droneGroupInLocalSpace?.RegionCenter()?.B < drone?.RegionCenter()?.B)
  246.         ?.ToArray();
  247.     var droneInLocalSpaceSetStatus =
  248.         setDroneInLocalSpace?.Select(drone => drone?.LabelText?.Select(label => label?.Text?.StatusStringFromDroneEntryText()))?.ConcatNullable()?.WhereNotDefault()?.Distinct()?.ToArray();
  249.  
  250.     var droneInLocalSpaceIdle =
  251.         droneInLocalSpaceSetStatus?.Any(droneStatus => droneStatus.RegexMatchSuccessIgnoreCase("idle")) ?? false;
  252.  
  253.     var droneGroupInBay = droneGroupWithNameMatchingPattern("bay");
  254.  
  255.     if(ShouldSwitchMiningSite)
  256.         return MainStep;
  257.     EnsureWindowInventoryOreContainerIsOpen();
  258.  
  259.     EnsureOverviewTypeSelectionLoaded();
  260.  
  261.     if(OreContainerFilledForOffload)
  262.         return null;
  263.        
  264.     var setTargetAsteroidInRange    =
  265.         SetTargetAsteroid?.Where(target => target?.DistanceMax <= MiningRange)?.ToArray();
  266.  
  267.     var setTargetAsteroidInRangeNotAssigned =
  268.         setTargetAsteroidInRange?.Where(target => !(0 < target?.Assigned?.Length))?.ToArray();
  269.  
  270.     Host.Log("targeted asteroids in range (without assignment): " + setTargetAsteroidInRange?.Length + " (" + setTargetAsteroidInRangeNotAssigned?.Length + ")");
  271.  
  272.     if(0 < setTargetAsteroidInRangeNotAssigned?.Length)
  273.     {
  274.         var targetAsteroidInputFocus    =
  275.             setTargetAsteroidInRangeNotAssigned?.FirstOrDefault(target => target?.IsSelected ?? false);
  276.  
  277.         if(null == targetAsteroidInputFocus)
  278.             Sanderling.MouseClickLeft(setTargetAsteroidInRangeNotAssigned?.FirstOrDefault());
  279.         if (0 < DronesInBayCount && DronesInSpaceCount < DroneNumber)
  280.         DroneLaunch();
  281.  
  282.         if (!(0 < DronesInSpaceCount))
  283.         DroneLaunch();
  284.         //MineTarget();
  285.     //   Sanderling.KeyboardPress(VirtualKeyCode.VK_F);
  286.         if (droneInLocalSpaceIdle && (Measurement?.Target?.Length > 0))
  287.         {      
  288.             Host.Log("drones idle");
  289.             //MineTarget();
  290.             Sanderling.KeyboardPress(VirtualKeyCode.VK_F);
  291.             Host.Log("mining a new asteroid");
  292.         }
  293.         return InBeltMineStep;
  294.     }
  295.  
  296.     var asteroidOverviewEntryNext = ListAsteroidOverviewEntry?.FirstOrDefault();
  297.     var asteroidOverviewEntryNextNotTargeted = ListAsteroidOverviewEntry?.FirstOrDefault(entry => !((entry?.MeTargeted ?? false) || (entry?.MeTargeting ?? false)));
  298.  
  299.     Host.Log("next asteroid: (" + asteroidOverviewEntryNext?.Name + " , distance: " + asteroidOverviewEntryNext?.DistanceMax + ")" +
  300.         ", next asteroid not targeted: (" + asteroidOverviewEntryNext?.Name + " , distance: " + asteroidOverviewEntryNext?.DistanceMax + ")");
  301.  
  302.     if(null == asteroidOverviewEntryNext)
  303.     {
  304.         Host.Log("no asteroid available");
  305.         return null;
  306.     }
  307.  
  308.     if(null == asteroidOverviewEntryNextNotTargeted)
  309.     {
  310.         Host.Log("all asteroids targeted");
  311.         return null;
  312.     }
  313.  
  314.     if (!(asteroidOverviewEntryNextNotTargeted.DistanceMax < MiningRange))
  315.     {
  316.         if(!(1111 < asteroidOverviewEntryNext?.DistanceMin))
  317.         {
  318.             Host.Log("distance between asteroids too large");
  319.             return null;
  320.         }
  321.  
  322.         Host.Log("out of range, approaching");
  323.         ClickMenuEntryOnMenuRoot(asteroidOverviewEntryNext, "approach");
  324.     }
  325.     else
  326.     {
  327.         Host.Log("initiate lock asteroid");
  328.         ClickMenuEntryOnMenuRoot(asteroidOverviewEntryNextNotTargeted, "^lock");
  329.     }
  330.    
  331.     return InBeltMineStep;
  332. }
  333.  
  334.  
  335. Sanderling.Parse.IMemoryMeasurement Measurement =>
  336.     Sanderling?.MemoryMeasurementParsed?.Value;
  337.  
  338. IWindow ModalUIElement =>
  339.     Measurement?.EnumerateReferencedUIElementTransitive()?.OfType<IWindow>()?.Where(window => window?.isModal ?? false)
  340.     ?.OrderByDescending(window => window?.InTreeIndex ?? int.MinValue)
  341.     ?.FirstOrDefault();
  342.  
  343. IEnumerable<Parse.IMenu> Menu => Measurement?.Menu;
  344.  
  345. Parse.IShipUi ShipUi => Measurement?.ShipUi;
  346.  
  347. bool Jammed => ShipUi?.EWarElement?.Any(EwarElement => (EwarElement?.EWarType).RegexMatchSuccess("electronic")) ?? false;
  348.  
  349. Sanderling.Interface.MemoryStruct.IMenuEntry MenuEntryLockTarget =>
  350.     Menu?.FirstOrDefault()?.Entry?.FirstOrDefault(entry => entry.Text.RegexMatchSuccessIgnoreCase("^lock"));
  351.  
  352. Sanderling.Parse.IWindowOverview    WindowOverview  =>
  353.     Measurement?.WindowOverview?.FirstOrDefault();
  354.  
  355. Sanderling.Parse.IWindowInventory   WindowInventory =>
  356.     Measurement?.WindowInventory?.FirstOrDefault();
  357. IWindowDroneView WindowDrones =>
  358.     Measurement?.WindowDroneView?.FirstOrDefault();
  359.  
  360. DroneViewEntryGroup DronesInBayListEntry =>
  361.     WindowDrones?.ListView?.Entry?.OfType<DroneViewEntryGroup>()?.FirstOrDefault(Entry => null != Entry?.Caption?.Text?.RegexMatchIfSuccess(@"Drones in bay", RegexOptions.IgnoreCase));
  362.  
  363. DroneViewEntryGroup DronesInSpaceListEntry =>
  364.     WindowDrones?.ListView?.Entry?.OfType<DroneViewEntryGroup>()?.FirstOrDefault(Entry => null != Entry?.Caption?.Text?.RegexMatchIfSuccess(@"Drones in Local Space", RegexOptions.IgnoreCase));
  365.  
  366. int? DronesInSpaceCount => DronesInSpaceListEntry?.Caption?.Text?.AsDroneLabel()?.Status?.TryParseInt();
  367. int? DronesInBayCount => DronesInBayListEntry?.Caption?.Text?.AsDroneLabel()?.Status?.TryParseInt();
  368.  
  369. ITreeViewEntry InventoryActiveShipOreContainer
  370. {
  371.     get
  372.     {
  373.         var hasOreHold = ShipHasOreHold;
  374.  
  375.         if(hasOreHold == null)
  376.             return null;
  377.  
  378.         return
  379.             WindowInventory?.ActiveShipEntry?.TreeEntryFromCargoSpaceType(
  380.                 hasOreHold.Value ? ShipCargoSpaceTypeEnum.OreHold : ShipCargoSpaceTypeEnum.General);
  381.     }
  382. }
  383.  
  384. IInventoryCapacityGauge OreContainerCapacityMilli =>
  385.     (InventoryActiveShipOreContainer?.IsSelected ?? false) ? WindowInventory?.SelectedRightInventoryCapacityMilli : null;
  386.  
  387. int? OreContainerFillPercent => (int?)((OreContainerCapacityMilli?.Used * 100) / OreContainerCapacityMilli?.Max);
  388.  
  389. Tab OverviewPresetTabActive =>
  390.     WindowOverview?.PresetTab
  391.     ?.OrderByDescending(tab => tab?.LabelColorOpacityMilli ?? 0)
  392.     ?.FirstOrDefault();
  393.  
  394. string OverviewTypeSelectionName =>
  395.     WindowOverview?.Caption?.RegexMatchIfSuccess(@"\(([^\)]*)\)")?.Groups?[1]?.Value;
  396.  
  397. Parse.IOverviewEntry[] ListAsteroidOverviewEntry =>
  398.     WindowOverview?.ListView?.Entry
  399.     ?.Where(entry => null != OreTypeFromAsteroidName(entry?.Name))
  400.     ?.OrderBy(entry => entry.DistanceMax ?? int.MaxValue)
  401.     ?.ToArray();
  402.    
  403.  
  404. bool ReadyForManeuverNot =>
  405.     Measurement?.ShipUi?.Indication?.LabelText?.Any(indicationLabel =>
  406.         (indicationLabel?.Text).RegexMatchSuccessIgnoreCase("warp|docking")) ?? false;
  407.  
  408. bool ReadyForManeuver => !ReadyForManeuverNot && !(Measurement?.IsDocked ?? true);
  409.  
  410. Sanderling.Parse.IShipUiTarget[] SetTargetAsteroid =>
  411.     Measurement?.Target?.Where(target =>
  412.         target?.TextRow?.Any(textRow => textRow.RegexMatchSuccessIgnoreCase("asteroid")) ?? false)?.ToArray();
  413.  
  414. Sanderling.Interface.MemoryStruct.IListEntry    WindowInventoryItem =>
  415.     WindowInventory?.SelectedRightInventory?.ListView?.Entry?.FirstOrDefault();
  416.  
  417. //  extract the ore type from the name as seen in overview. "Asteroid (Plagioclase)"
  418. string OreTypeFromAsteroidName(string AsteroidName) =>
  419.     AsteroidName.ValueFromRegexMatchGroupAtIndex(@"Asteroid \(([^\)]+)", 0);
  420.  
  421. void ClickMenuEntryOnMenuRoot(IUIElement MenuRoot, string MenuEntryRegexPattern)
  422. {
  423.     Sanderling.MouseClickRight(MenuRoot);
  424.    
  425.     var Menu = Measurement?.Menu?.FirstOrDefault();
  426.    
  427.     var MenuEntry = Menu?.EntryFirstMatchingRegexPattern(MenuEntryRegexPattern, RegexOptions.IgnoreCase);
  428.    
  429.     Sanderling.MouseClickLeft(MenuEntry);
  430. }
  431.  
  432. void ClickMenuEntryOnPatternMenuRoot(IUIElement MenuRoot, string MenuEntryRegexPattern, string SubMenuEntryRegexPattern = null)
  433. {
  434.     Sanderling.MouseClickRight(MenuRoot);
  435.     var Menu = Sanderling?.MemoryMeasurementParsed?.Value?.Menu?.FirstOrDefault();
  436.     var MenuEntry = Menu?.EntryFirstMatchingRegexPattern(MenuEntryRegexPattern, RegexOptions.IgnoreCase);
  437.     Sanderling.MouseClickLeft(MenuEntry);
  438.     if (SubMenuEntryRegexPattern != null)
  439.     {
  440.         // Using the API explorer when we click on the top menu we get another menu that has more options
  441.         // So skip the MenuRoot and click on Submenu
  442.       // var subMenu = Sanderling?.MemoryMeasurementParsed?.Value?.Menu?.Skip(1).First();
  443.       var subMenu = Sanderling?.MemoryMeasurementParsed?.Value?.Menu?.ElementAtOrDefault(1);
  444.       var subMenuEntry = subMenu?.EntryFirstMatchingRegexPattern(SubMenuEntryRegexPattern, RegexOptions.IgnoreCase);
  445.     Host.Log("initiate warp to '" + MenuEntryRegexPattern + "'");
  446.        Sanderling.MouseClickLeft(subMenuEntry);
  447.     }
  448. }
  449.  
  450. void ModuleMeasureAllTooltip()
  451. {
  452.     Host.Log("measure tooltips of all modules.");
  453.  
  454.     for (;;)
  455.     {
  456.         var NextModule = Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule?.FirstOrDefault(m => null == m?.TooltipLast);
  457.  
  458.         if(null == NextModule)
  459.             break;
  460.  
  461.         Host.Log("measure module.");
  462.         //  take multiple measurements of module tooltip to reduce risk to keep bad read tooltip.
  463.         Sanderling.MouseMove(NextModule);
  464.         Sanderling.WaitForMeasurement();
  465.         Sanderling.MouseMove(NextModule);
  466.     }
  467. }
  468.  
  469. void ActivateHardenerExecute()
  470. {
  471.     var SubsetModuleHardener =
  472.         Sanderling.MemoryMeasurementAccu?.Value?.ShipUiModule
  473.         ?.Where(module => module?.TooltipLast?.Value?.IsHardener ?? false);
  474.  
  475.     var SubsetModuleToToggle =
  476.         SubsetModuleHardener
  477.         ?.Where(module => !(module?.RampActive ?? false));
  478.  
  479.     foreach (var Module in SubsetModuleToToggle.EmptyIfNull())
  480.         ModuleToggle(Module);
  481. }
  482.  
  483. void ModuleToggle(Sanderling.Accumulation.IShipUiModule Module)
  484. {
  485.     var ToggleKey = Module?.TooltipLast?.Value?.ToggleKey;
  486.  
  487.     Host.Log("toggle module using " + (null == ToggleKey ? "mouse" : Module?.TooltipLast?.Value?.ToggleKeyTextLabel?.Text));
  488.  
  489.     if(null == ToggleKey)
  490.         Sanderling.MouseClickLeft(Module);
  491.     else
  492.         Sanderling.KeyboardPressCombined(ToggleKey);
  493. }
  494.  
  495. void EnsureWindowInventoryOpen()
  496. {
  497.     if (null != WindowInventory)
  498.         return;
  499.  
  500.     Host.Log("open Inventory.");
  501.     Sanderling.MouseClickLeft(Measurement?.Neocom?.InventoryButton);
  502. }
  503.  
  504. void EnsureWindowInventoryOreContainerIsOpen()
  505. {
  506.     EnsureWindowInventoryOpen();
  507.  
  508.     var inventoryActiveShip = WindowInventory?.ActiveShipEntry;
  509.  
  510.     if(InventoryActiveShipOreContainer == null && !(IsExpanded(inventoryActiveShip) ?? false))
  511.     {
  512.         Host.Log("It looks like the active ships entry in the inventory is not expanded. I try to expand it to see if the ship has an ore hold.");
  513.         Sanderling.MouseClickLeft(inventoryActiveShip?.ExpandToggleButton);
  514.     }
  515.  
  516.     if(!(InventoryActiveShipOreContainer?.IsSelected ?? false))
  517.         Sanderling.MouseClickLeft(InventoryActiveShipOreContainer);
  518. }
  519.  
  520. //  sample label text: Intensive Reprocessing Array <color=#66FFFFFF>1,123 m</color>
  521. string InventoryContainerLabelRegexPatternFromContainerName(string containerName) =>
  522.     @"^\s*" + Regex.Escape(containerName) + @"\s*($|\<)";
  523.  
  524. void InInventoryUnloadItems() => InInventoryUnloadItemsTo(UnloadDestContainerName);
  525.  
  526. void InInventoryUnloadItemsTo(string DestinationContainerName)
  527. {
  528.     Host.Log("unload items to '" + DestinationContainerName + "'.");
  529.  
  530.     EnsureWindowInventoryOreContainerIsOpen();
  531.  
  532.     for (;;)
  533.     {
  534.         var oreContainerListItem = WindowInventory?.SelectedRightInventory?.ListView?.Entry?.ToArray();
  535.  
  536.         var oreContainerItem = oreContainerListItem?.FirstOrDefault();
  537.  
  538.         if(null == oreContainerItem)
  539.             break;    //    0 items in the container which holds the ore.
  540.  
  541.         if(1 < oreContainerListItem?.Length)
  542.             ClickMenuEntryOnMenuRoot(oreContainerItem, @"select\s*all");
  543.  
  544.         var DestinationContainerLabelRegexPattern =
  545.             InventoryContainerLabelRegexPatternFromContainerName(DestinationContainerName);
  546.  
  547.         var DestinationContainer =
  548.             WindowInventory?.LeftTreeListEntry?.SelectMany(entry => new[] { entry }.Concat(entry.EnumerateChildNodeTransitive()))
  549.             ?.FirstOrDefault(entry => entry?.Text?.RegexMatchSuccessIgnoreCase(DestinationContainerLabelRegexPattern) ?? false);
  550.  
  551.         if (null == DestinationContainer)
  552.             Host.Log("error: Inventory entry labeled '" + DestinationContainerName + "' not found");
  553.  
  554.         Sanderling.MouseDragAndDrop(oreContainerItem, DestinationContainer);
  555.     }
  556. }
  557.  
  558. bool InitiateWarpToMiningSite() =>
  559.     InitiateDockToOrWarpToLocationInSolarSystemMenu(FolderBeltsMining, PickNextMiningSiteFromSystemMenu);
  560.  
  561. MemoryStruct.IMenuEntry PickNextMiningSiteFromSystemMenu(IReadOnlyList<MemoryStruct.IMenuEntry> availableMenuEntries)
  562. {
  563.     Host.Log("I am seeing " + availableMenuEntries?.Count.ToString() + " mining sites to choose from.");
  564.  
  565.     var nextSite =
  566.         availableMenuEntries
  567.         ?.OrderBy(menuEntry => visitedLocations.ToList().IndexOf(menuEntry?.Text))
  568.         ?.FirstOrDefault();
  569.  
  570.     Host.Log("I pick '" + nextSite?.Text + "' as next mining site, based on the intent to rotate through the mining sites and recorded previous locations.");
  571.     return nextSite;
  572. }
  573.  
  574. bool InitiateDockToOrWarpToLocationInSolarSystemMenu(
  575.     string submenuLabel,
  576.     Func<IReadOnlyList<MemoryStruct.IMenuEntry>, MemoryStruct.IMenuEntry> pickPreferredDestination = null)
  577. {
  578.     Host.Log("Attempt to initiate dock to or warp to menu entry in submenu '" + submenuLabel + "'");
  579.    
  580.     var listSurroundingsButton = Measurement?.InfoPanelCurrentSystem?.ListSurroundingsButton;
  581.    
  582.     Sanderling.MouseClickRight(listSurroundingsButton);
  583.  
  584.     var submenuEntry = Measurement?.Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("^" + submenuLabel + "$", RegexOptions.IgnoreCase);
  585.  
  586.     if(null == submenuEntry)
  587.     {
  588.         Host.Log("Submenu '" + submenuLabel + "' not found in the solar system menu.");
  589.         return true;
  590.     }
  591.  
  592.     Sanderling.MouseClickLeft(submenuEntry);
  593.  
  594.     var submenu = Measurement?.Menu?.ElementAtOrDefault(1);
  595.  
  596.     var destinationMenuEntry = pickPreferredDestination?.Invoke(submenu?.Entry?.ToList()) ?? submenu?.Entry?.FirstOrDefault();
  597.  
  598.     if(destinationMenuEntry == null)
  599.     {
  600.         Host.Log("Failed to open submenu '" + submenuLabel + "' in the solar system menu.");
  601.         return true;
  602.     }
  603.  
  604.     Sanderling.MouseClickLeft(destinationMenuEntry);
  605.  
  606.     var actionsMenu = Measurement?.Menu?.ElementAtOrDefault(2);
  607.  
  608.     if(destinationMenuEntry == null)
  609.     {
  610.         Host.Log("Failed to open actions menu for '" + destinationMenuEntry.Text + "' in the solar system menu.");
  611.         return true;
  612.     }
  613.  
  614.     var dockMenuEntry = actionsMenu?.EntryFirstMatchingRegexPattern("dock", RegexOptions.IgnoreCase);
  615.     var warpMenuEntry = actionsMenu?.EntryFirstMatchingRegexPattern(@"warp.*within.*m", RegexOptions.IgnoreCase);
  616.     var approachEntry = actionsMenu?.EntryFirstMatchingRegexPattern(@"approach", RegexOptions.IgnoreCase);
  617.  
  618.     var maneuverMenuEntry = dockMenuEntry ?? warpMenuEntry;
  619.  
  620.     if (null != maneuverMenuEntry)
  621.     {
  622.         Host.Log("initiating '" + maneuverMenuEntry.Text + "' on '" + destinationMenuEntry?.Text + "'");
  623.         Sanderling.MouseClickLeft(maneuverMenuEntry);
  624.         return false;
  625.     }
  626.  
  627.     if (null != approachEntry)
  628.     {
  629.         Host.Log("found menu entry '" + approachEntry.Text + "'. Assuming we are already there.");
  630.         return false;
  631.     }
  632.  
  633.     Host.Log("no suitable menu entry found on '" + destinationMenuEntry?.Text + "'");
  634.     return true;
  635. }
  636.  
  637. void Undock()
  638. {
  639.     while(Measurement?.IsDocked ?? true)
  640.     {
  641.         Sanderling.MouseClickLeft(Measurement?.WindowStation?.FirstOrDefault()?.UndockButton);
  642.         Host.Log("waiting for undocking to complete.");
  643.         Host.Delay(8000);
  644.     }
  645.  
  646.     Host.Delay(4444);
  647.     Sanderling.InvalidateMeasurement();
  648. }
  649.  
  650.  
  651.  
  652. void EnsureOverviewTypeSelectionLoaded()
  653. {
  654.     if(null == OverviewPresetTabActive || null == WindowOverview || null == OverviewPreset)
  655.         return;
  656.  
  657.     if(string.Equals(OverviewTypeSelectionName, OverviewPreset, StringComparison.OrdinalIgnoreCase))
  658.         return;
  659.  
  660.     Host.Log("loading preset '" + OverviewPreset + "' to overview (current selection is '" + OverviewTypeSelectionName + "').");
  661.     Sanderling.MouseClickRight(OverviewPresetTabActive);
  662.     Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("load.*preset", RegexOptions.IgnoreCase));
  663.     var PresetMenuEntry = Menu?.ElementAtOrDefault(1)?.EntryFirstMatchingRegexPattern(@"^\s*" + Regex.Escape(OverviewPreset) + @"\s*$", RegexOptions.IgnoreCase);
  664.  
  665.     if(null == PresetMenuEntry)
  666.     {
  667.         Host.Log("error: menu entry '" + OverviewPreset + "' not found");
  668.         return;
  669.     }
  670.  
  671.     Sanderling.MouseClickLeft(PresetMenuEntry);
  672. }
  673.  
  674. void DelayWhileUpdatingMemory(int delayAmountMilli)
  675. {
  676.     var beginTimeMilli = Host.GetTimeContinuousMilli();
  677.  
  678.     while(true)
  679.     {
  680.         var remainingTimeMilli = beginTimeMilli + delayAmountMilli - Host.GetTimeContinuousMilli();
  681.         if(remainingTimeMilli < 0)
  682.             break;
  683.  
  684.         Host.Delay(Math.Min(1000, (int)remainingTimeMilli));
  685.         Sanderling.InvalidateMeasurement();
  686.         MemoryUpdate();
  687.     }
  688. }
  689.  
  690. void MemoryUpdate()
  691. {
  692.     RetreatUpdate();
  693.     JammedLastTimeUpdate();
  694.     OffloadCountUpdate();
  695.     UpdateLocationRecord();
  696. }
  697.  
  698. void UpdateLocationRecord()
  699. {
  700.     //  I am not interested in locations which are only close during warp.
  701.     if(Measurement?.ShipUi?.Indication?.ManeuverType == ShipManeuverTypeEnum.Warp)
  702.         return;
  703.  
  704.     // Purpose of recording locations is to prioritize our next destination when warping to mining site or docking to station.
  705.     // For this purpose, I will compare the recorded locations with the menu entries in the system menu.
  706.     // Therefore I want the format of the recorded location to be the same as it appears in the menu entries in the system menu.
  707.  
  708.     var currentSystemLocationLabelText =
  709.         Measurement?.InfoPanelCurrentSystem?.ExpandedContent?.LabelText
  710.         ?.OrderByCenterVerticalDown()?.FirstOrDefault()?.Text;
  711.  
  712.     if(currentSystemLocationLabelText == null)
  713.         return;
  714.  
  715.     // 2018-03 observed label text: <url=showinfo:15//40088644 alt='Nearest'>Amsen V - Asteroid Belt 1</url>
  716.  
  717.     var currentLocationName = RegexExtension.RemoveXmlTag(currentSystemLocationLabelText)?.Trim();
  718.  
  719.     var lastRecordedLocation = visitedLocations.LastOrDefault();
  720.  
  721.     if(lastRecordedLocation == currentLocationName)
  722.         return;
  723.  
  724.     visitedLocations.Enqueue(currentLocationName);
  725.     Host.Log("Recorded transition from location '" + lastRecordedLocation + "' to location '" + currentLocationName + "'");
  726.  
  727.     if(100 < visitedLocations.Count)
  728.         visitedLocations.Dequeue();
  729. }
  730.  
  731. /*
  732. 2018-03 Observation: Station name containing reference to moon appears different between system menu and system info panel.
  733. In the info panel 'Moon 17' was used while in the system menu it was 'M17'.
  734. */
  735. public bool StationFromSystemInfoPanelEqualsStationFromSystemMenu(
  736.     string stationNameInCurrentSystemInfoPanel,
  737.     string stationNameInSystemMenu)
  738. {
  739.     //  Copied from https://github.com/botengine-de/Optimat.EO/blob/6c19e8f36e30d5468e94d627eb16dcb78bb47d12/src/Optimat.EveOnline.Bot/Sonst/AgentUndMission.Aktualisiire.cs#L1888-L1893
  740.  
  741.     var representationPattern =
  742.         Regex.Replace(
  743.         stationNameInCurrentSystemInfoPanel,
  744.         "Moon\\s*",
  745.         "M([\\w]*\\s*)",
  746.         RegexOptions.IgnoreCase);
  747.  
  748.     return
  749.         stationNameInSystemMenu.RegexMatchSuccessIgnoreCase(representationPattern);
  750. }
  751.  
  752. void JammedLastTimeUpdate()
  753. {
  754.     if(Jammed)
  755.         JammedLastTime  = Host.GetTimeContinuousMilli();
  756. }
  757.  
  758. bool MeasurementEmergencyWarpOutEnter =>
  759.     !(Measurement?.IsDocked ?? false) && !(EmergencyWarpOutHitpointPercent < ShieldHpPercent);
  760.  
  761. void RetreatUpdate()
  762. {
  763.     //RetreatReasonTemporary = (RetreatOnNeutralOrHostileInLocal && hostileOrNeutralsInLocal)   ? "hostile or neutral in local" : null;
  764.     //RetreatReasonTemporary = "shield hp";
  765.     if (!MeasurementEmergencyWarpOutEnter)
  766.         return;
  767.  
  768.     //  measure multiple times to avoid being scared off by noise from a single measurement.
  769.     Sanderling.InvalidateMeasurement();
  770.  
  771.     if (!MeasurementEmergencyWarpOutEnter)
  772.         return;
  773.  
  774.     RetreatReasonPermanent = "shield hp";
  775. }
  776.  
  777. void OffloadCountUpdate()
  778. {
  779.     var OreContainerFillPercentSynced   = OreContainerFillPercent;
  780.  
  781.     if(!OreContainerFillPercentSynced.HasValue)
  782.         return;
  783.  
  784.     if(0 == OreContainerFillPercentSynced && OreContainerFillPercentSynced < LastCheckOreContainerFillPercent)
  785.         ++OffloadCount;
  786.  
  787.     LastCheckOreContainerFillPercent = OreContainerFillPercentSynced;
  788. }
  789.  
  790. void MineTarget()
  791. {
  792.         Sanderling.MouseClickRight(DronesInSpaceListEntry);
  793.         Sanderling.MouseClickLeft(Menu?.FirstOrDefault()?.EntryFirstMatchingRegexPattern("^Mine Repeatedly", RegexOptions.IgnoreCase));
  794. }
  795. bool? IsExpanded(IInventoryTreeViewEntryShip shipEntryInInventory) =>
  796.     shipEntryInInventory == null ? null :
  797.     (bool?)((shipEntryInInventory.IsExpanded ?? false) || 0 < (shipEntryInInventory.Child?.Count() ?? 0));
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement