Some basic drone management functions

Here is a set of basic drone management function that I want to share. Maybe you can poke around and tailor it to your needs or just learn from it.

This function will recall drones if a specific drone type is matched.

For example to return your mining drone it could be used like this:

returnDronesTypeToBay context.readingFromGameClient "mining"

Or for your hobgoblins

returnDronesTypeToBay context.readingFromGameClient "hobgoblin"
returnDronesTypeToBay : ReadingFromGameClient -> String -> Maybe DecisionPathNode
returnDronesTypeToBay readingFromGameClient droneTypeName =
    readingFromGameClient.dronesWindow
        |> Maybe.andThen
            (\dronesWindow ->
                case dronesWindow.droneGroupInLocalSpace of
                    Just droneGroupInLocalSpace ->
                        let
                            dronesInLocalSpaceQuantity =
                                droneGroupInLocalSpace.header.quantityFromTitle |> Maybe.withDefault 0

                            returningDrones =
                                droneGroupInLocalSpace.drones
                                    |> List.filter (.uiNode >> .uiNode >> EveOnline.ParseUserInterface.getAllContainedDisplayTexts >> List.any (String.toLower >> String.contains "returning"))

                            droneType =
                                droneGroupInLocalSpace.drones
                                    |> List.filter (.uiNode >> .uiNode >> EveOnline.ParseUserInterface.getAllContainedDisplayTexts >> List.any (String.toLower >> String.contains droneTypeName))
                        in
                        if dronesInLocalSpaceQuantity < 1 then
                            Nothing

                        else if (returningDrones |> List.length) > 0 then
                            Just
                                waitForProgressInGame

                        else if (droneType |> List.length) > 0 then
                            Just
                                (describeBranch ("I see there are " ++ droneTypeName ++ " drones in local space. Return those to bay.")
                                    (useContextMenuCascade
                                        ( "drones group", droneGroupInLocalSpace.header.uiNode )
                                        (useMenuEntryWithTextContaining "Return to drone bay" menuCascadeCompleted)
                                        readingFromGameClient
                                    )
                                )

                        else
                            Nothing

                    _ ->
                        Nothing
            )

This function will deploy a group that contain a certain name. Be careful if many of them share the used string it will use the first group.

This will deploy a group with string “Mining” in it.

launchAndEngageGroupNameDrones context.readingFromGameClient "Mining"

This will deploy a group with string “Combat” in it.

launchAndEngageGroupNameDrones context.readingFromGameClient "Combat"
launchAndEngageGroupNameDrones : ReadingFromGameClient -> String -> Maybe DecisionPathNode
launchAndEngageGroupNameDrones readingFromGameClient groupName =
    readingFromGameClient.dronesWindow
        |> Maybe.andThen
            (\dronesWindow ->
                case ( dronesWindow.droneGroupInBay, dronesWindow.droneGroupInLocalSpace ) of
                    ( Just droneGroupInBay, Just droneGroupInLocalSpace ) ->
                        let
                            idlingDrones =
                                droneGroupInLocalSpace.drones
                                    |> List.filter (.uiNode >> .uiNode >> EveOnline.ParseUserInterface.getAllContainedDisplayTexts >> List.any (String.toLower >> String.contains "idle"))

                            dronesInBayQuantity =
                                droneGroupInBay.header.quantityFromTitle |> Maybe.withDefault 0

                            dronesInLocalSpaceQuantity =
                                droneGroupInLocalSpace.header.quantityFromTitle |> Maybe.withDefault 0

                            droneGroupExpectedDisplayText =
                                groupName
                        in
                        if 1 < (idlingDrones |> List.length) then
                            Just
                                (endDecisionPath
                                    (actWithoutFurtherReadings
                                        ( "Engaging " ++ groupName ++ " drones."
                                        , [ EffectOnWindow.KeyDown EffectOnWindow.vkey_F
                                          , EffectOnWindow.KeyUp EffectOnWindow.vkey_F
                                          ]
                                        )
                                    )
                                )

                        else if 0 < dronesInBayQuantity && dronesInLocalSpaceQuantity < 1 then
                            Just
                                (describeBranch
                                    ("Launch "
                                        ++ groupName
                                        ++ " drones"
                                    )
                                    (case getDescendantWithDisplayTextContain droneGroupExpectedDisplayText dronesWindow.uiNode of
                                        Nothing ->
                                            describeBranch
                                                ("Did not find the node with display text '" ++ droneGroupExpectedDisplayText ++ "'")
                                                askForHelpToGetUnstuck

                                        Just droneGroupUiNode ->
                                            useContextMenuCascade
                                                ( "drones group", droneGroupUiNode )
                                                (useMenuEntryWithTextContaining "Launch drones" menuCascadeCompleted)
                                                readingFromGameClient
                                    )
                                )

                        else
                            Nothing

                    _ ->
                        Nothing
            )

Here are some support functions to make them work.

getDescendantWithDisplayTextContain : String -> UIElement -> Maybe UIElement
getDescendantWithDisplayTextContain displayText parent =
    parent
        |> EveOnline.ParseUserInterface.listDescendantsWithDisplayRegion
        |> List.filter (.uiNode >> EveOnline.ParseUserInterface.getDisplayText >> Maybe.map (String.contains displayText) >> Maybe.withDefault False)
        |> List.head


getDescendantWithDisplayText : String -> UIElement -> Maybe UIElement
getDescendantWithDisplayText displayText parent =
    parent
        |> EveOnline.ParseUserInterface.listDescendantsWithDisplayRegion
        |> List.filter (.uiNode >> EveOnline.ParseUserInterface.getDisplayText >> (==) (Just displayText))
        |> List.head

The possibilities are limitless with botengine. The more advanced versions of these functions will recall any drones who take damage and relaunch, choose the perfect group of drones to launch for the target distance and type etc…

I have learned a lot so far on how to automate my gameplay the way I want it too.

Quick edit: I don’t think these are compatible with the latest version of botengine. Maybe someone can pitch in but I did not take the time to update my scripts yet.

2 Likes

Awesome! Thank you for sharing this!

Do you see any incompatibility? The latest version of botengine is 2021-02-20. Do you see a problem when using version 2021-02-20?
What updates would be needed in scripts?

I think you simplified a few things and there are a few parameters that have a different way to be used or dont need to be used anymore.

I just remember not upgrading to the latest update because of these little things. Nothing major.

sorry for my ignorance, but where do i have to put this lines. in the option window of the selected script? (for example, in the miner bot script)

edit: I find this usefull to have combat and miner drones and change one or other in each situation: no rats, then i store combat drones, and release minig drones. I see rats, then store mining drones and release combat drones to defend.

These functions are for custom scripts.

Here is a guide to get you started.

Developing for EVE Online

1 Like

Nice way to control drones. I use this way:

type alias DronesWindow =
    { uiNode : UITreeNodeWithDisplayRegion
    , droneGroups : List DronesWindowEntryGroupStructure
    , droneGroupInBay : Maybe DronesWindowEntryGroupStructure
    , miningDroneGroupInBay : Maybe DronesWindowEntryGroupStructure
    , miningDroneGroupInLocalSpace : Maybe DronesWindowEntryGroupStructure
    , droneGroupInLocalSpace : Maybe DronesWindowEntryGroupStructure
    , combatDroneGroupInBay : Maybe DronesWindowEntryGroupStructure
    , combatDroneGroupInLocalSpace : Maybe DronesWindowEntryGroupStructure
    }
parseDronesWindowFromUITreeRoot : UITreeNodeWithDisplayRegion -> Maybe DronesWindow
parseDronesWindowFromUITreeRoot uiTreeRoot =
    case
        uiTreeRoot
            |> listDescendantsWithDisplayRegion
            |> List.filter (.uiNode >> .pythonObjectTypeName >> (==) "DroneView")
            |> List.head
    of
        Nothing ->
            Nothing

        Just windowNode ->
            let
                {-
                   scrollNode =
                       windowNode
                           |> listDescendantsWithDisplayRegion
                           |> List.filter (.uiNode >> .pythonObjectTypeName >> String.toLower >> String.contains "scroll")
                           |> List.head
                -}
                droneGroupHeaders =
                    windowNode
                        |> listDescendantsWithDisplayRegion
                        |> List.filter (.uiNode >> .pythonObjectTypeName >> String.contains "Group")
                        |> List.filterMap parseDronesWindowDroneGroupHeader

                droneEntries =
                    windowNode
                        |> listDescendantsWithDisplayRegion
                        |> List.filter (.uiNode >> .pythonObjectTypeName >> (==) "DroneEntry")
                        |> List.map parseDronesWindowDroneEntry

                droneGroups =
                    [ droneEntries |> List.map DronesWindowEntryDrone
                    , droneGroupHeaders
                        |> List.map (\header -> { header = header, children = [] })
                        |> List.map DronesWindowEntryGroup
                    ]
                        |> List.concat
                        |> dronesGroupTreesFromFlatListOfEntries

                droneGroupFromHeaderTextPart headerTextPart =
                    droneGroups
                        |> List.filter (.header >> .mainText >> Maybe.withDefault "" >> String.toLower >> String.contains (headerTextPart |> String.toLower))
                        |> List.sortBy (.header >> .mainText >> Maybe.map String.length >> Maybe.withDefault 999)
                        |> List.head
                droneSubGroupFromHeaderTextPart headerTextPart headerTextPart2 =
                    droneGroups
                        |> List.filter (.header >> .mainText >> Maybe.withDefault "" >> String.toLower >> String.contains (headerTextPart |> String.toLower))
                        |> List.filter (.header >> .mainText >> Maybe.withDefault "" >> String.toLower >> String.contains (headerTextPart2 |> String.toLower))
                        |> List.sortBy (.header >> .mainText >> Maybe.map String.length >> Maybe.withDefault 999)
                        |> List.head
            in
            Just
                { uiNode = windowNode
                , droneGroups = droneGroups
                , droneGroupInBay = droneGroupFromHeaderTextPart "in Bay"
                , miningDroneGroupInBay = droneSubGroupFromHeaderTextPart "in Bay" "Mining"
                , combatDroneGroupInBay = droneSubGroupFromHeaderTextPart "in Bay" "Combat"
                , droneGroupInLocalSpace = droneGroupFromHeaderTextPart "in local space"
                , miningDroneGroupInLocalSpace = droneSubGroupFromHeaderTextPart "in local space" "Mining"
                , combatDroneGroupInLocalSpace = droneSubGroupFromHeaderTextPart "in local space" "Combat"
                }

Im trying to make bot recall any drones who take damage and relaunch another one in bay which have full of shield. Can you share it? @Mohano

1 Like