#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);
}
-
Set map size: Must be first! Many utility functions depend on size parameters.
// Map size init.
int axisTiles = getScaledAxisTiles(128);
rmSetMapSize(axisTiles); -
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); -
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); -
Call
postPlayerPlacement(): Triggers internal state setup.// Finalize player placement and do post-init things.
postPlayerPlacement(); -
Set nature civilisation: Affects visuals (e.g. ruins near relics).
// Mother Nature's civ [Random].
rmSetNatureCivFromCulture(cCultureGreek);// Mother Nature's civ [Specific].
rmSetNatureCiv(cCivZeus); -
Configure lighting: Aesthetic settings for ambient and directional light.
// Lighting.
rmSetLighting(cLightingSetRmMediterranean01); -
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); -
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); -
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. -
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"); -
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"); -
Add terrain features: Cliffs, lakes, and similar topographical elements.
TODO// Ponds.
TODO -
Place nearby resources: Small gold mines, berries, huntables, herdables.
TODO -
Create forest areas: Core strategic and visual resource zones.
TODO -
Add distant resources: Larger gold deposits and additional fauna.
TODO -
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"); -
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()); -
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