Tutorial: Configure Smart Turret

This guide will walk you through the process of configuring your Smart Turret to determine which targets the turret should fire at according to ESC scores.

Prerequisites

This guide assumes you have a already deployed a Smart Turret and are ready to configure it. For detailed instuctions on this, visit the EVE: Frontier Smart Turret docs.

Note

Those docs assume you have git cloned the builder-examples repository. We will be extending the code in the smart-turret directory.

Step 1: Add the interface

We need to add the IESC interface above the SmartTurretSystem contract:

interface IESC {
    function isCriminal(address) external view returns (bool);

	function balanceOf(address) external view returns (uint256);
}

Step 2: Add the ESC address

Then, we need to add the ESC_ADDRESS constant inside the SmartTurretSystem contract, below the using statements and above the inProximity function:


contract SmartTurretSystem is System {
  using EntityRecordUtils for bytes14;
  using SmartDeployableUtils for bytes14;
  using SmartCharacterUtils for bytes14;

  address internal constant ESC_ADDRESS = 0x9f8370eAB367a0A3Bbad60174B8b9D026DfC24B2;

  // ...
}

Step 3: Update the inProximity function

This prioritizes shooting at players with lower ESC scores first, while completely ignoring players who aren't considered criminals.

    function inProximity(
        uint256 smartTurretId,
        uint256 characterId,
        TargetPriority[] memory priorityQueue,
        Turret memory turret,
        SmartTurretTarget memory turretTarget
    ) public returns (TargetPriority[] memory updatedPriorityQueue) {
        // Get the address of the player in proximity of the Smart Turret
        address playerAddress = address(uint160(turretTarget.characterId));

        // Check if the player is a criminal according to ESC
        bool isCriminal = IESC(ESC_ADDRESS).isCriminal(playerAddress);

        //Find if the player is already in the queue.
        bool foundInPriorityQueue = false;
        for (uint256 i = 0; i < priorityQueue.length; i++) {
            if (priorityQueue[i].target.characterId == turretTarget.characterId) {
                foundInPriorityQueue = true;
                break;
            }
        }

        // If player is not a criminal, they should not be targeted
        if (!isCriminal) {
            // If found in queue, create a new array without the character
            if (foundInPriorityQueue) {
                // Create the smaller temporary array
                TargetPriority[] memory tempArray = new TargetPriority[](priorityQueue.length - 1);
                uint256 tempIndex = 0;

                // Loop over the queue and only set if not the character
                for (uint256 i = 0; i < priorityQueue.length; i++) {
                    if (priorityQueue[i].target.characterId != turretTarget.characterId) {
                        tempArray[tempIndex] = priorityQueue[i];
                        tempIndex++;
                    }
                }

                // Sort the array
                tempArray = bubbleSortTargetPriorityArray(tempArray);

                // Return the new array
                return tempArray;
            }

            // Return the unchanged array
            return priorityQueue;
        }

        // Player is a criminal - calculate priority based on ESC score and health
        uint256 escScore = IESC(ESC_ADDRESS).balanceOf(playerAddress);

        // Prioritize ships with the lowest total health percentage and lower ESC score
        uint256 calculatedWeight = calculateWeight(turretTarget, escScore);

        // Weight is not currently used in-game as the game uses the position of elements in the array, however we set it for the bubble sort algorithm to use
        TargetPriority memory newPriority = TargetPriority({target: turretTarget, weight: calculatedWeight});

        // If already in the queue, update the weight
        if (foundInPriorityQueue) {
            // Loop through to find the index of the target for the character
            for (uint256 i = 0; i < priorityQueue.length; i++) {
                if (priorityQueue[i].target.characterId == turretTarget.characterId) {
                    priorityQueue[i] = newPriority;
                }
            }

            // Sort the array
            priorityQueue = bubbleSortTargetPriorityArray(priorityQueue);

            // Return the changed in-place queue
            return priorityQueue;
            // If not already in the queue, add to the queue
        } else {
            // Create the larger temporary array
            TargetPriority[] memory tempArray = new TargetPriority[](priorityQueue.length + 1);

            // Clone the priority queue to the temp array
            for (uint256 i = 0; i < priorityQueue.length; i++) {
                tempArray[i] = priorityQueue[i];
            }

            // Set the new target to the end of the temp array
            tempArray[priorityQueue.length] = newPriority;

            // Sort the array
            TargetPriority[] memory sortedArray = bubbleSortTargetPriorityArray(tempArray);

            // Return array to the Smart Turret
            return sortedArray;
        }
    }

Step 4: Update the calculateWeight function

As the targets are prioritized and the game selects the targets in reverse order they are returned, lower ESC scores (more criminal) will be prioritized higher.

    function calculateWeight(SmartTurretTarget memory target, uint256 escScore) public returns (uint256 weight) {
        // Base weight calculation from health
        uint256 healthWeight = 300 - (target.hpRatio + target.shieldRatio + target.armorRatio);

        // ESC score factor - the lower the ESC score, the higher the priority
        uint256 escWeight = 1000 - (escScore > 1000 ? 1000 : escScore);

        // Combine weights - give more weight to ESC score for prioritizing criminals
        weight = healthWeight + escWeight;

        return weight;
    }

Step 5: Run the script to configure the turret

Ensure your .env file is up to date with the correct values. Then run the following command to configure the turret:

pnpm configure

For each turret you want to configure, you will need to change the SMART_TURRET_ID in your .env file and re-run the command.

Conclusion

After making these changes, the turret is now configured to shoot at players that are considered criminals first, while completely ignoring players who aren't criminals.