Empires Scripting

From Archon Wiki
Jump to navigation Jump to search

See My Games\<Game Name>\AUTODOCS\BATTLESCRIPT.TXT for definitive script command descriptions.

Also output to the AUTODOCS folder is ARCHON.XML, a language definition compatible with Notepad++ (note that if the language definition is updated, the defined language must be removed and re-imported into Np++, it will not reload it automatically).

Pathfinding

GetRoute

The main entry point is GetRoute(startRegion, destRegion, workArray, groupID, ...). It returns the total cost of the route and the route itself is stored in the temporary work array. The steps in the route are accessed using GetArray(step). For example to get the route from current to destination into the array route:

   int route[32];
   int i;
   cost = GetRoute(current, destination, 0, group);
   if (cost >= 0)
   {
       for (i = 0; i < 32; i++)
       {
           route[i] = GetArray(i);
           if (route[i] == -1)
           {
               i = 32; // done
           }
       }
   }

Internally, there are a number of callbacks during pathfinding so that the costs can be dynamically determined by scripts. The sequence is something like this:

/- GetRoute(startRegion, targetRegion, workArray, groupID, ...) BATTLESCRIPT command
|    / | \
|   v  v  v
|  PathfindingData(region, neighbour, groupID, ...)                Map.BSF function
|      |
|      v
|  SetPathfindingData(region, neighbour, cost, [speed])                  BATTLESCRIPT command
|
\-> GetRoute returns total cost

PathfindingData is a function implemented in Map.BSF that tells the engine the cost of moving from one region to its neighbour them. Simple calculations based on region and group properties can be used to determine the cost. PathfindingData calls SetPathfindingData to return the cost and, optionally the speed used to take the step, if it is valid in the situation. The base connection graph is determined internally based on the $REGION_CONNECTIONS attribute and assuming that legal movement costs are always > 0. It is possible to pass additional parameters to the PathfindingData callback by adding more parameters to the function, and then padding them as additional parameters to GetRoute after the groupID.

Internally, data is cached so that if you make consecutive calls to GetRoute for the same startRegion and groupID within the same frame, the result will be found much faster. A loop with one group evaluating N destinations will be much faster than N groups evaluating one destination.

If non-zero speeds are provided to SetPathfindingData, the engine will include the calculation of unused movement points not carried over between turns in the cost. The speed expected is the speed used if a turn starts in 'region', pathfinding internally will determine whether to use that speed or continue with the previous speed.

There is an alternate version of the command, GetRouteWithLimit, that takes a maximum cost which can be more efficient when long routes are not of interest.

GetRegionsInRange

Pathfinding can also be used to find a list of regions in range of another. The entry point for this is GetRegionsInRange(sourceRegion, maxCost, dynArrayHandle, [callback], [data...]).

Similar to GetRoute, evaluating a GetRegionsInRange request will result in a number of calls to a callback function which must call SetPathfindingData to provide costs to the engine. The difference is that the name of the callback function can be provided to GetRegionsInRange. The first parameter to the callback function will always be the region ID that data is requested for, all additional integer parameters will be passed through from the GetRegionsInRange call to the callback.

For example, to get all regions within a cost of 12 of startID using the same callback as GetRoute uses:

handle = CreateDyamicArray();
GetRegionsInRange(startID, 12, handle, "PathfindingData", groupID);
...
DestroyDynamicArray(handle);

To use a callback that uses different criteria or a different calculation, define another callback function:

FUNCTION PathfindingDataByKind(regionID, neighbourID, kind, faction)
{
    int cost;
    
    cost = myCost(neighbourID, kind, faction);
    SetPathfindingData(regionID, neighbourID, cost);
}

And then provide the name and expected parameters to the search:

GetRegionsInRange(startID, 12, handle, "PathfindingDataByKind", kind, factionID);

If the callback name and parameters are omitted, the search will be done without script callbacks based on the Connections attribute of the regions with a fixed cost of 1 for each step.