AoMR Random Map Scripting Guide


#Typical XS-Script Structure (with Examples)

Any map generation starts by running the generate() function. Inside that function, most scripts follow a similar structure, building the map elements from highest priority to lowest:

include "lib2/rm_core.xs";

// Main entry point for random map script.
void generate()
{
rmSetProgress(0.0);
}
  1. Set map size: Must be first! Many utility functions depend on size parameters.
    // Map size init.
    int axisTiles = getScaledAxisTiles(128);
    rmSetMapSize(axisTiles);
  2. Initialise terrain: Define base as land or water.
    // Define land terrain mix.
    int baseMixID = rmCustomMixCreate();
    rmCustomMixSetPaintParams(baseMixID, cNoiseFractalSum, 0.1, 5, 0.5);
    rmCustomMixAddPaintEntry(baseMixID, cTerrainGreekGrass2, 3.0);
    rmCustomMixAddPaintEntry(baseMixID, cTerrainGreekGrass1, 4.0);
    rmCustomMixAddPaintEntry(baseMixID, cTerrainGreekGrassDirt1, 4.0);
    rmCustomMixAddPaintEntry(baseMixID, cTerrainGreekGrassDirt2, 2.0);
    rmInitializeMix(baseMixID);
    // Global elevation.
    rmAddGlobalHeightNoise(cNoiseFractalSum, 5.0, 0.05, 2, 0.5);
    // Define water.
    rmInitializeWater(cWaterGreekSeaAegean);
  3. Place player locations: Logical placeholders used later for player towns / islands, etc.
    // Player placement [Circle].
    rmSetTeamSpacingModifier(0.8);
    rmPlacePlayersOnCircle(0.375);
    // Player placement [Square].
    rmSetTeamSpacingModifier(0.8);
    rmPlacePlayersOnSquare(0.35, 0.35);
  4. Call postPlayerPlacement(): Triggers internal state setup.
    // Finalize player placement and do post-init things.
    postPlayerPlacement();
  5. Set nature civilisation: Affects visuals (e.g. ruins near relics).
    // Mother Nature's civ [Random].
    rmSetNatureCivFromCulture(cCultureGreek);
    // Mother Nature's civ [Specific].
    rmSetNatureCiv(cCivZeus);
  6. Configure lighting: Aesthetic settings for ambient and directional light.
    // Lighting.
    rmSetLighting(cLightingSetRmMediterranean01);
  7. Create major land areas: If initialised to water or impassable terrain.
    // Single Continent.
    int continentID = rmAreaCreate("continent");
    rmAreaSetLoc(continentID, cCenterLoc);
    rmAreaSetSize(continentID, xsRandFloat(0.43, 0.5));
    rmAreaSetHeight(continentID, 0.25);
    rmAreaAddHeightBlend(continentID, cBlendEdge, cFilter5x5Gaussian, 10, 10);
    rmAreaSetHeightNoise(continentID, cNoiseFractalSum, 5.0, 0.1, 2, 0.5);
    rmAreaSetHeightNoiseBias(continentID, 1.0);
    rmAreaSetHeightNoiseEdgeFalloffDist(continentID, 20.0);
    rmAreaSetMix(continentID, baseMixID);
    rmAreaSetBlobs(continentID, 1 * cNumberPlayers, 2 * cNumberPlayers);
    rmAreaSetBlobDistance(continentID, 5.0, 20.0);
    rmAreaSetEdgeSmoothDistance(continentID, 15);
    rmAreaAddConstraint(continentID, createSymmetricBoxConstraint(0.075), 0.0, 10.0);
    rmAreaBuild(continentID);
  8. Create major water areas: If initialised to land (but optional).
    // First consolidate player base areas.
    int playerAreaClassID = rmClassCreate();
    float playerBaseAreaSize = rmRadiusToAreaFraction(48.5);
    for(int i = 1; i <= cNumberPlayers; i++)
    {
    int p = vDefaultTeamPlayerOrder[i];
    int playerBaseAreaID = rmAreaCreate("player base area " + p);
    rmAreaSetLocPlayer(playerBaseAreaID, p);
    rmAreaSetSize(playerBaseAreaID, playerBaseAreaSize);
    rmAreaSetCoherence(playerBaseAreaID, 0.25);
    rmAreaSetEdgeSmoothDistance(playerBaseAreaID, 3);
    rmAreaAddToClass(playerBaseAreaID, playerAreaClassID);
    }
    // Center Ocean.
    int seaAreaID = rmAreaCreate("sea");
    rmAreaSetWaterType(seaAreaID, cWaterGreekSeaAegean);
    rmAreaSetLoc(seaAreaID, cCenterLoc);
    rmAreaSetSize(seaAreaID, xsRandFloat(0.15, 0.24));
    if (gameIs1v1() == false)
    {
    rmAreaSetBlobDistance(seaAreaID, 1.0 * rmGetMapXTiles() / 10.0, 1.0 * rmGetMapZTiles() / 5.0);
    rmAreaSetBlobs(seaAreaID, 8, 10);
    }
    rmAreaSetCoherence(seaAreaID, 0.25);
    rmAreaSetEdgeSmoothDistance(seaAreaID, 5);
    rmAreaSetWaterHeightBlend(seaAreaID, cFilter5x5Gaussian, 25, 10);
    rmAreaAddConstraint(seaAreaID, rmCreateClassDistanceConstraint(playerAreaClassID, 1.0));
    rmAreaBuild(seaAreaID);
  9. Call placeKotHObjects(): King of the Hill only; places vault at map centre. Future placements must avoid this zone using constraints.
    // KotH Island [Water].
    if (gameIsKotH() == true)
    {
    int islandKotHID = rmAreaCreate("koth island");
    rmAreaSetSize(islandKotHID, rmRadiusToAreaFraction(15.0 * sqrt(cNumberPlayers)));
    rmAreaSetLoc(islandKotHID, cCenterLoc);
    rmAreaSetCoherence(islandKotHID, 0.95);
    rmAreaSetEdgeSmoothDistance(islandKotHID, 5);
    rmAreaSetHeight(islandKotHID, 0.0);
    rmAreaSetHeightNoise(islandKotHID, cNoiseFractalSum, 5.0, 0.05, 2, 0.25);
    rmAreaSetHeightNoiseBias(islandKotHID, 1.0); // Only grow upwards.
    rmAreaSetHeightNoiseEdgeFalloffDist(islandKotHID, 20.0);
    rmAreaAddHeightBlend(islandKotHID, cBlendEdge, cFilter5x5Box, 10.0, 5.0);
    rmAreaAddToClass(islandKotHID, vKotHClassID);
    rmAreaBuild(islandKotHID);
    }
    placeKotHObjects();	//KotH Plenty Vault.
  10. Place player starting objects: town centre, towers, etc.
    // Base beautification.
    float baseBeautificationSize = rmRadiusToAreaFraction(32.5);
    for(int i = 1; i <= cNumberPlayers; i++)
    {
    int p = vDefaultTeamPlayerOrder[i];
    int baseBeautificationAreaID = rmAreaCreate("base area beautification " + p);
    rmAreaSetLocPlayer(baseBeautificationAreaID, p);
    rmAreaSetSize(baseBeautificationAreaID, baseBeautificationSize);
    rmAreaSetTerrainType(baseBeautificationAreaID, cTerrainGreekRoad1);
    rmAreaAddTerrainLayer(baseBeautificationAreaID, cTerrainGreekGrassRocks1, 1, 2);
    rmAreaAddTerrainLayer(baseBeautificationAreaID, cTerrainGreekRoad3, 0);
    }
    rmAreaBuildAll();
    // Starting settlement.
    placeStartingTownCenters();
    // Starting towers.
    int startingTowerID = rmObjectDefCreate("starting tower");
    rmObjectDefAddItem(startingTowerID, cUnitTypeSentryTower, 1);
    addObjectLocsPerPlayer(startingTowerID, true, 4, cStartingTowerMinDist, cStartingTowerMaxDist, cStartingTowerAvoidanceMeters);
    generateLocs("starting tower locs");
  11. Place unclaimed settlements: Neutral town centres / build spots.
    // Neutral settlements.
    int firstSettlementID = rmObjectDefCreate("first settlement");
    rmObjectDefAddItem(firstSettlementID, cUnitTypeSettlement, 1);
    rmObjectDefAddConstraint(firstSettlementID, vDefaultSettlementAvoidEdge);
    rmObjectDefAddConstraint(firstSettlementID, vDefaultAvoidTowerLOS);
    rmObjectDefAddConstraint(firstSettlementID, vDefaultAvoidCorner40);
    rmObjectDefAddConstraint(firstSettlementID, vDefaultSettlementAvoidSiegeShipRange);
    int secondSettlementID = rmObjectDefCreate("second settlement");
    rmObjectDefAddItem(secondSettlementID, cUnitTypeSettlement, 1);
    rmObjectDefAddConstraint(secondSettlementID, vDefaultSettlementAvoidEdge);
    rmObjectDefAddConstraint(secondSettlementID, vDefaultAvoidTowerLOS);
    rmObjectDefAddConstraint(secondSettlementID, vDefaultAvoidCorner40);
    rmObjectDefAddConstraint(secondSettlementID, vDefaultAvoidKotH);
    rmObjectDefAddConstraint(secondSettlementID, vDefaultSettlementAvoidSiegeShipRange);
    if(gameIs1v1() == true)
    {
    addSimObjectLocsPerPlayerPair(firstSettlementID, false, 1, 60.0, 80.0, cSettlementDist1v1, cBiasBackward);
    addSimObjectLocsPerPlayerPair(secondSettlementID, false, 1, 80.0, 120.0, cSettlementDist1v1, cBiasAggressive);
    }
    else
    {
    addObjectLocsPerPlayer(firstSettlementID, false, 1, 60.0, 80.0, cCloseSettlementDist, cBiasBackward | cBiasAllyInside);
    addObjectLocsPerPlayer(secondSettlementID, false, 1, 70.0, 90.0, cFarSettlementDist, cBiasAggressive | getRandomAllyBias());
    }
    // Other map sizes settlements.
    if (cMapSizeCurrent > cMapSizeStandard)
    {
    int bonusSettlementID = rmObjectDefCreate("bonus settlement");
    rmObjectDefAddItem(bonusSettlementID, cUnitTypeSettlement, 1);
    rmObjectDefAddConstraint(bonusSettlementID, vDefaultSettlementAvoidEdge);
    rmObjectDefAddConstraint(bonusSettlementID, vDefaultAvoidTowerLOS);
    rmObjectDefAddConstraint(bonusSettlementID, vDefaultAvoidCorner40);
    rmObjectDefAddConstraint(bonusSettlementID, vDefaultAvoidKotH);
    rmObjectDefAddConstraint(bonusSettlementID, vDefaultSettlementAvoidSiegeShipRange);
    addObjectLocsPerPlayer(bonusSettlementID, false, 1 * getMapAreaSizeFactor(), 90.0, -1.0, 100.0);
    }
    generateLocs("settlement locs");
  12. Add terrain features: Cliffs, lakes, and similar topographical elements.
    TODO
    // Ponds.
    TODO
  13. Place nearby resources: Small gold mines, berries, huntables, herdables.
    TODO
  14. Create forest areas: Core strategic and visual resource zones.
    TODO
  15. Add distant resources: Larger gold deposits and additional fauna.
    TODO
  16. Place relics: Scattered based on constraints or randomness.
    // Relics.
    float avoidRelicMeters = 80.0;
    int relicID = objectDefCreateTracked("relic");
    rmObjectDefAddItem(relicID, cUnitTypeRelic, 1);
    rmObjectDefAddItem(relicID, cUnitTypeColumns, xsRandInt(2, 3), 4.0);
    rmObjectDefAddItem(relicID, cUnitTypeColumnsBroken, xsRandInt(2, 3), 4.0);
    rmObjectDefAddConstraint(relicID, vDefaultAvoidEdge);
    rmObjectDefAddConstraint(relicID, vDefaultRelicAvoidAll);
    rmObjectDefAddConstraint(relicID, vDefaultRelicAvoidImpassableLand);
    rmObjectDefAddConstraint(relicID, vDefaultAvoidTowerLOS);
    rmObjectDefAddConstraint(relicID, vDefaultAvoidSettlementRange);
    addObjectDefPlayerLocConstraint(relicID, 70.0);
    addObjectLocsPerPlayer(relicID, false, 2 * getMapAreaSizeFactor(), 70.0, -1.0, avoidRelicMeters);
    generateLocs("relic locs");
  17. Add decorative objects: Straggler trees, rocks, birds, grass, etc.
    TODO
    // Seaweed.
    int seaweedID = rmObjectDefCreate("seaweed");
    rmObjectDefAddItem(seaweedID, cUnitTypeSeaweed, 1);
    rmObjectDefAddConstraint(seaweedID, rmCreatePassabilityDistanceConstraint(cPassabilityLand, true, 2.0));
    rmObjectDefAddConstraint(seaweedID, rmCreatePassabilityMaxDistanceConstraint(cPassabilityLand, true, 6.0));
    rmObjectDefAddConstraint(seaweedID, rmCreateMinWaterDepthConstraint(2.25));
    rmObjectDefPlaceAnywhere(seaweedID, 0, 100.0 * sqrt(cNumberPlayers) * getMapAreaSizeFactor());
    // Birbs.
    int birdID = rmObjectDefCreate("bird");
    rmObjectDefAddItem(birdID, cUnitTypeHawk, 1);
    rmObjectDefPlaceAnywhere(birdID, 0, 2 * cNumberPlayers * getMapAreaSizeFactor());
  18. Call it done: Set the status bar to 100%. Makes any user happy - Me too.
    rmSetProgress(1.0);


#Biomes

Working with biomes: Biomes can help you at randomizing the appearence of your map.

Library Setup

include "lib2/rm_biomes.xs";
cBiome = getRandomBiome();	//Select a biome.

Map Basics

// Set lighting from biome.
rmSetLighting( cBiome.getRandomLighting() );
// If we force a specific civ for that biome do that, otherwise randomize.
if(cBiome.getCivID() == cInvalidID)
{
rmSetNatureCivFromCulture( cBiome.getCultureID() );
}
else
{
rmSetNatureCiv( cBiome.getCivID() );
}

Area Types

// Get mix from biome.
int defaultMixID = cBiome.getDefaultMix();
// Get water from biome.
int defaultWaterID = cBiome.getDefaultWater();
// Get cliff from biome.
int cliffTypeID1 = cBiome.getRandomCliff(cCliffInsidePassable);
int cliffTypeID2 = cBiome.getRandomCliff(cCliffInsideImpassable);
// Get random forest from biome.
int forestTypeID = cBiome.getRandomForest();

Objects

// Get random tree from biome.
int treeTypeID = cBiome.getRandomTree();
// Get random fish from biome.
int fishTypeID = cBiome.getRandomFish();
// Get all the plant embellishment.
int[] plantEmbellishments = cBiome.getPlantEmbellishments();
int numPlantEmbellishments = plantEmbellishments.size();

for(int i = 0; i < numPlantEmbellishments; i++)
{
int embellishmentTypeID = plantEmbellishments[i];
}
// Get all the rock embellishment.
int[] rockEmbellishments = cBiome.getRockEmbellishments();
int numRockEmbellishments = rockEmbellishments.size();

for(int i = 0; i < numRockEmbellishments; i++)
{
int embellishmentTypeID = rockEmbellishments[i];
}
// Get random bird from biome.
int birdTypeID = cBiome.getRandomBird();


#Core Concepts

Areas

Areas define geometric zones used for placing terrain, objects, or triggers. Defined with properties such as shape, size, and placement rules.

//Example Area.
int areaID = rmAreaCreate("center");
rmAreaSetSize(areaID, 0.3);
vector areaLoc = xsVectorCreate(rmXFractionToMeters(0.5), 0.0, rmZFractionToMeters(0.5));
rmAreaSetLoc(areaID, areaLoc);

There are two ways of restricting an area to another area:

//Adding to Parent.
int childAreaID = rmAreaCreate("only within center", areaID);
rmAreaSetParent(childAreaID, areaID);

Since areas can overlap, the order in which you paint them will highly affect the outcome.

Blobs

Painting an area as a single blob compares to painting a filled circle. With multiple blobs, instead of one, many of the same circles will form a cluster of blobs, leading to a complex shape.
(Useful for islands, forests, water bodies, or cliffs)

//Example Blobs.
rmAreaSetBlobs(areaID, 4, 5);
rmAreaSetBlobDistance(areaID, 10, 20);

Individual blobs can be shaped via coherence, with a value of 1.0 representing a perfect circle (or square). Need something wild? Try negative coherence.

//Example Coherence.
rmAreaSetCoherence(areaID, 1.0);
rmAreaSetCoherenceSquare(areaID, true);

Constraints

Constraints restrict placement of objects and areas based on relative conditions - like proximity to terrain, class, or player. They ensure logical and fair object placement.

//Example Constraints.
int nearEdgeConstraint = rmCreateAreaEdgeMaxDistanceConstraint(areaID, 15, "stay close to edge of area");
int mountainConstraint = rmCreateMaxHeightConstraint(4.0, "avoid higher altitude");
int valleyConstraint = rmCreateMinHeightConstraint(-2.0, "avoid lower altitude");
int avoidTerrainType = rmCreateTerrainTypeDistanceConstraint(cTerrainGreekRoadBurnt2, 10, "avoid burnt road 2");

Classes

Classes allow grouping of objects and areas for collective reference or exclusion.

//Example Class.
int areaClassID = rmClassCreate();
rmAreaAddToClass(areaID, areaClassID);
rmCreateClassDistanceConstraint(areaClassID, 15, "avoid class area");

Mixes

Mixes define terrain textures and their blending ratios within an area.

//Example Mix [Sand].
int sandMixID = rmCustomMixCreate();
rmCustomMixSetPaintParams(sandMixID, cNoiseFractalSum, 0.1, 5, 0.5);
rmCustomMixAddPaintEntry(sandMixID, cTerrainEgyptDirt1, 1.0);
rmCustomMixAddPaintEntry(sandMixID, cTerrainEgyptSand1, 1.0);
rmCustomMixAddPaintEntry(sandMixID, cTerrainEgyptSand2, 1.0);
rmCustomMixAddPaintEntry(sandMixID, cTerrainEgyptSand3, 1.0);
//Example Mix [Snow].
int snowMixID = rmCustomMixCreate();
rmCustomMixSetPaintParams(snowMixID, cNoiseFractalSum, 0.1, 5, 0.5);
rmCustomMixAddPaintEntry(snowMixID, cTerrainNorseSnow2, 3.0);
rmCustomMixAddPaintEntry(snowMixID, cTerrainNorseSnow1, 3.0);
rmCustomMixAddPaintEntry(snowMixID, cTerrainNorseSnowGrass1, 2.0);
rmCustomMixAddPaintEntry(snowMixID, cTerrainNorseSnowGrass2, 2.0);

Paths

Paths create linear routes or roads between areas, optionally used for trade routes or visual structure.

//Example Path.
int pathID = rmPathDefCreate("road");
TODO

ObjectDefs

Object definitions specify what and how many entities (e.g. gold mines, settlements) are placed. Essentially they make up everything in a world that isn’t terrain.

//Example ObjectDef [Snow].
int snowEffectID = rmObjectDefCreate("snowVFX");
rmObjectDefAddItem(snowEffectID, cUnitTypeVFXWeatherSnow, 1);
rmObjectDefPlaceAtLoc(snowEffectID, 0, cCenterLoc);
//Example ObjectDef [Rain].
int rainEffectID = rmObjectDefCreate("rainVFX");
rmObjectDefAddItem(rainEffectID, cUnitTypeVFXWeatherRain, 1);
rmObjectDefPlaceAtLoc(rainEffectID, 0, cCenterLoc);

AreaDefs

Area definitions act as reusable templates for building multiple areas with shared properties (commonly used for forest patches).

//Example AreaDef.
TODO


#References

RetoldFunctions, RetoldConstants | DevSetupGuide