Eve Mining Bot - amendment to let it use mining drones (among other things)

I am trying to finesse the existing mining bot to handle running a Porpoise. The first thing I wanted to add was the ability for it to use mining drones. I thought that this would be very straightforward but it seems .. not.

I was thinking I could replace the code block between line 862 and 892 with code to send drones to the selected asteroid. Basically I should just be able to rip the code from 1680 to 1709 but change the context menu paramter from ‘Return’ to ‘Mine’.

However when I try to compile I get

This `case` expression produces:

    Maybe (Common.DecisionPath.DecisionPathNode EndDecisionPathStructure)

But all the previous branches result in:

    Common.DecisionPath.DecisionPathNode EndDecisionPathStructure

Clearly, my lack of Elm skill is hindering me here but I don’t see why this is occuring or how to go about fixing it.

Obviously this is just a hack as it will continually try to send the drones on every cycle but its good enough for now until I figure out how to set a state variable for “drones assigned” and have it reference that.


ie this code block

                                                            case
                                                                knownMiningModules
                                                                    |> List.filter (.isActive >> Maybe.withDefault False >> not)
                                                                    |> List.head
                                                            of
                                                                Nothing ->
                                                                    describeBranch
                                                                        (if knownMiningModules == [] then
                                                                            "Found no mining modules so far."

                                                                         else
                                                                            "All known mining modules found so far are active."
                                                                        )
                                                                        (case readShipUIModuleButtonTooltips context of
                                                                            Just readAction ->
                                                                                readAction

                                                                            Nothing ->
                                                                                case deactivateAfterburner context of
                                                                                    Just deactivateAfterburnerAction ->
                                                                                        describeBranch "Deactivate afterburner."
                                                                                            deactivateAfterburnerAction

                                                                                    Nothing ->
                                                                                        waitForProgressInGame
                                                                        )

                                                                Just inactiveModule ->
                                                                    describeBranch "I see an inactive mining module. Activate it."
                                                                        (clickModuleButtonButWaitIfClickedInPreviousStep context inactiveModule)

Replaced with

    case context.readingFromGameClient.dronesWindow of
        Nothing ->
            Nothing

        Just dronesWindow ->
            case dronesWindow.droneGroupInSpace of
                Nothing ->
                    Nothing

                Just droneGroupInLocalSpace ->
                    if
                        (droneGroupInLocalSpace.header.quantityFromTitle
                            |> Maybe.map .current
                            |> Maybe.withDefault 0
                        )
                            < 1
                    then
                        Nothing

                    else
                        Just
                            (describeBranch "I see there are drones in space. Set them mining."
                                (useContextMenuCascade
                                    ( "drones group", droneGroupInLocalSpace.header.uiNode )
                                    (useMenuEntryWithTextContaining "Mine" menuCascadeCompleted)
                                    context
                                )
                            )

Any insights or pointers gratefully received.

1 Like

That error message indicates the exporession you inserted returns an instance of Maybe var. That means that inserted part of the code is only returning a final result for the step in some cases. For other cases, the surrounding code needs to fill in the default.

type Maybe a
    = Just a
    | Nothing

Explanation on use of the Maybe type: https://guide.elm-lang.org/error_handling/maybe

There are multiple ways to align your inserted code with the surrounding code:

  1. Wrap the inserted code in an expression that supplies the default value, for cases where the inner expression returns the Nothing value.
    (You can see the program doing that in multiple places using the Maybe.withDefault function: https://package.elm-lang.org/packages/elm/core/latest/Maybe#withDefault)
  2. Change each branch in the expression to return a value of type Common.DecisionPath.DecisionPathNode EndDecisionPathStructure directly.

I have adapted the code you posted above to implement the second solution:

    case context.readingFromGameClient.dronesWindow of
        Nothing ->
            waitForProgressInGame

        Just dronesWindow ->
            case dronesWindow.droneGroupInSpace of
                Nothing ->
                    waitForProgressInGame

                Just droneGroupInLocalSpace ->
                    if
                        (droneGroupInLocalSpace.header.quantityFromTitle
                            |> Maybe.map .current
                            |> Maybe.withDefault 0
                        )
                            < 1
                    then
                        waitForProgressInGame

                    else
                            -- Note the 'Just' tag is gone

                            (describeBranch "I see there are drones in space. Set them mining."
                                (useContextMenuCascade
                                    ( "drones group", droneGroupInLocalSpace.header.uiNode )
                                    (useMenuEntryWithTextContaining "Mine" menuCascadeCompleted)
                                    context
                                )
                            )

In this case, I replaced all retuning Nothing with waitForProgressInGame. For the branches using the Just tag, its enough to remove the Just tag.

I think adding state will not be necessary in this case, because the game client already displays if drones are idle. Some bots use this indication already. Here is an example:

Much appreciated. I made the suggested change and ripped the code for checking if the drones were idle. Seems to work fine in game.

Next up, monitoring and emptying the Fleet Hangar, with the final amendment being to compress when Mining Hold close to full based on an input parm.

Then for the ‘other’ type of miner, a ‘Fleet Leader’ input parameter which it stays within range of to use the Fleet Hangar.

Looks like that was implemented here:

Looks like you can control the threshold in percent using the miningHoldFillPercent parameter.

Another question if I may (and you have time to answer). If I Shift-Click the Fleet Hangar this will open a new window with a fill gauge. If I do that before I launch the bot it should be readable, no?
If so, how do I address it as per .

capacityGaugeUsedPercent : EveOnline.ParseUserInterface.InventoryWindow -> Maybe Int

It also seems that the compression code implemented is for compressing while docked at a structure that allows it. I can’t see any clicking of the two modules that are required to enable compression while in space.
Unless, the assumption is you just put those in as ‘modules to activate always’. That will work but is kind of inefficient as you will be burning heavy water and you are locked stationary. Thus, the bot can never move the ship.

Using the List EveOnline.ParseUserInterface.InventoryWindow you get at the root of the reading from the game client, you can select that one like this:


firstInventoryWithFillGauge :
    List EveOnline.ParseUserInterface.InventoryWindow
    -> Maybe ( EveOnline.ParseUserInterface.InventoryWindow, Int )
firstInventoryWithFillGauge inventoryWindows =
    List.Extra.findMap
        (\inventoryWindow ->
            case capacityGaugeUsedPercent inventoryWindow of
                Just percent ->
                    Just ( inventoryWindow, percent )

                Nothing ->
                    Nothing
        )
        inventoryWindows

Yes, so far people directly opened the compression window via the context menu entry. They did not use modules for the compression part.
What is your approach to compression?