I would like to use Survey Scanner for every even numbers of targets targetted

I would like to use Survey Scanner for every even numbers of targets targetted.

My last issue I think is I have no idea how botengine updates botmemory. I tried following the flow but without avail.

Here is my thinking:

  • Track the amounts of targets targetted the same way we track timesUnloaded in botmemory
  • Make a list of module for Survey Scanner.
  • Add a case…of or if…then to my logic tree that would activate survey scanner for every even numbers

Here is what I have so far.

List of Survey Scanner stored into memory

knownSurveyModules : BotDecisionContext -> List EveOnline.ParseUserInterface.ShipUIModuleButton
knownSurveyModules context =
    context.readingFromGameClient.shipUI
        |> Maybe.map .moduleButtons
        |> Maybe.withDefault []
        |> List.filter
            (EveOnline.AppFramework.getModuleButtonTooltipFromModuleButton context.memory.shipModules
                >> Maybe.map tooltipLooksLikeSurveyModule
                >> Maybe.withDefault False
            )

Added timesTargetted var into botmemory everywhere needed

type alias BotMemory =
    { lastDockedStationNameFromInfoPanel : Maybe String
    , timesTargeted : Int
    , timesUnloaded : Int
    , volumeUnloadedCubicMeters : Int
    , lastUsedCapacityInOreHold : Maybe Int
    , shipModules : ShipModulesMemory
    }
initState : State
initState =
    EveOnline.AppFramework.initState
        (EveOnline.AppFramework.initStateWithMemoryAndDecisionTree
            { lastDockedStationNameFromInfoPanel = Nothing
            , timesTargeted = 0
            , timesUnloaded = 0
            , volumeUnloadedCubicMeters = 0
            , lastUsedCapacityInOreHold = Nothing
            , shipModules = EveOnline.AppFramework.initShipModulesMemory
            }
        )
describeSessionPerformance =
            [ ( "times unloaded", context.memory.timesUnloaded )
            , ( "volume unloaded / m³", context.memory.volumeUnloadedCubicMeters )
            , ( "times targeted", context.memory.timesTargeted )

What should I replace WHAT TO WRITE HERE in the following snippet to store and update targets targeted?

let
        [...]

        timesTargeted =
            botMemoryBefore.timesTargeted
                + (if [WHAT T0 WRITE HERE] then
                    1

                   else
                    0
                  )
    in
    { lastDockedStationNameFromInfoPanel =
        [ currentStationNameFromInfoPanel, botMemoryBefore.lastDockedStationNameFromInfoPanel ]
            |> List.filterMap identity
            |> List.head
    , timesTargeted = timesTargeted
[...]

And what should I add in my targetting function to update this counter?
Here is my targeting function

               if overviewEntry.commonIndications.targetedByMe || overviewEntry.commonIndications.targeting then
                    describeBranch "Locking target is in progress, wait for completion." waitForProgressInGame

                else
                    describeBranch "Object is in range. Lock target."
                        (lockTargetFromOverviewEntry overviewEntry readingFromGameClient)

Could I just add increase the value in botMemoryBefore.timesTargeted in my targeting functions?

if overviewEntry.commonIndications.targetedByMe || overviewEntry.commonIndications.targeting then
                    describeBranch "Locking target is in progress, wait for completion." waitForProgressInGame

                else
                    describeBranch "Object is in range. Lock target."
                       (increaseTimesTargeted botMemoryBefore
                          |> Maybe.withDefault
                             (lockTargetFromOverviewEntry overviewEntry readingFromGameClient)
                       )

If I did something like this, what would increaseTimesTargeted function look like?
Would something like this work to increase the parameter that tracks timesTargeted in botMemory?

increaseTimesTargeted : botMemoryBefore  -> botMemoryBefore
increaseTimesTargeted : botMemoryBefore  -> botMemoryBefore

botMemoryBefore.timesTargeted = botMemoryBefore.timesTargeted + 1

You can increment the counter when a new target appears in the current reading from the game client. Thinking about it again, even better is not just to increment it, because of this scenario: You could have more than one new target appearing simultaneously.
Here is how this is usually implemented: In the function to update the memory, add the number of new targets to timesTargeted.
How do we know the number of new targets? By subtracting the number of targets in the current reading from the number of targets in the previous reading.
How do we know the number of targets in the previous reading? By storing it in the memory too. That means we add another field to store that count to the memory type:

type alias BotMemory =
    { lastDockedStationNameFromInfoPanel : Maybe String
    , lastTargetCount : Int
    , timesTargeted : Int
    , timesUnloaded : Int
    , volumeUnloadedCubicMeters : Int
    , lastUsedCapacityInOreHold : Maybe Int
    , shipModules : ShipModulesMemory
    }

And here is the implementation in the update function:

updateMemoryForNewReadingFromGame : EveOnline.AppFrameworkSeparatingMemory.UpdateMemoryContext -> BotMemory -> BotMemory
updateMemoryForNewReadingFromGame context botMemoryBefore =
    let
        [...]

        lastTargetCount =
            List.length context.readingFromGameClient.targets

        timesTargeted =
            botMemoryBefore.timesTargeted + lastTargetCount - botMemoryBefore.lastTargetCount
    in
    { lastDockedStationNameFromInfoPanel =
        [ currentStationNameFromInfoPanel, botMemoryBefore.lastDockedStationNameFromInfoPanel ]
            |> List.filterMap identity
            |> List.head
    , lastTargetCount = lastTargetCount
    , timesTargeted = timesTargeted
    , timesUnloaded = timesUnloaded
    , volumeUnloadedCubicMeters = volumeUnloadedCubicMeters
    , lastUsedCapacityInOreHold = lastUsedCapacityInOreHold
    , shipModules =
        botMemoryBefore.shipModules
            |> EveOnline.AppFramework.integrateCurrentReadingsIntoShipModulesMemory context.readingFromGameClient
    }

Besides the init, these are the only changes needed to implement the counter. There is no need to change the decision making ‘policy’ part of the app. That is, we update the counter by watching, not by acting.

You can see a commit with the changes here:

The same approach to counting is already implemented to count the amount of unloaded ore. (This is the count that you see in the overall status text) For the ore counter, the fields in the memory are lastUsedCapacityInOreHold and volumeUnloadedCubicMeters.
Have a look at volumeUnloadedSincePreviousReading to see how the update works for that counter. It was a bit more complicated for the ore: The displayed amount in the inventory can change without a change in the actual amount of ore, because the display also depends on which container is selected. The target counting is relatively simple.

Right now it only tracks the amount of targets that I have currently. It does not seem to add them.

        lastTargetCount =
            List.length currentReading.targets

        timesTargeted =
            botMemoryBefore.timesTargeted + lastTargetCount - botMemoryBefore.lastTargetCount

Clearly lastTargetCount works because I can get this value showing up on my stats.

I will try removing botmemory.lastTargetCount.

  timesTargeted =
            botMemoryBefore.timesTargeted + lastTargetCount

Actually this simply increase it by lastTargetCount every memory snapshot.

It seems like botMemoryBefore values are not updating for timesTargeted.

There was a small part missing yesterday. We need to expand this part:

That subtraction results in a negative number when a target disappears. So we add a branch not to add the difference to the counter when it is negative.

We can write the branch like this:

        targetCount =
            List.length context.readingFromGameClient.targets

        targetCountChangeSinceLastReading =
            targetCount - botMemoryBefore.lastTargetCount

        timesTargeted =
            botMemoryBefore.timesTargeted
                + (if targetCountChangeSinceLastReading < 0 then
                    0

                   else
                    targetCountChangeSinceLastReading
                  )

Again, we can look at the ore volume counter to see it also has this branch. Here is a comment from the old code:

During mining, when new ore appears in the inventory, this difference is negative.

The ore counter code uses the max 0 function to branch. That is more concise and easier to overlook. I used the if then else keywords inline this time to make it easier to see.

Yep that did the trick.

Now I’ll use this to sometimes activate Survey Scanner to make it more human-like.

The engine takes the state returned with the tuple that you return from the processEvent function and uses this as an argument when it applies that function for the next event. Here is the function type annotation where we can see both instances of the State:

When you build a bot for EVE Online, you don’t need to learn how this works because there are frameworks designed specifically for EVE Online. These frameworks take care of interfacing with the botengine and offer an interface to make it easier to understand the data flow.

To illustrate the data flow in the examples for EVE Online, I made this diagram:

data flow in bot app framework

The memory update function that you customize for your app is in the block labeled ‘update memory for new reading from game’.
The arrows in the diagram indicate the data flow in the framework included with the example apps.

As explained in the posts above, there is no data flowing from the part to decide the next action to update the memory. That is why in the diagram, we don’t have an arrow for such a flow.

In the program code, you can see the separation in this part of the app that connects the part that is closer to the botengine to the parts that you customize:

In the part of the code linked above, you find the three functions shown in the diagram again in the record.

1 Like