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.