0ad/binaries/data/mods/public/maps/random/latium.js
Spahbod bc805bd357 Adds the path placer library by historic_brunno to rmgen. Fixes #892.
Also takes all the duplicated parts of random maps including the new
player start entities and random biome system into rmgen libraries.
Tweaks nile river and snowflake random maps.

This was SVN commit r11152.
2012-02-25 15:53:43 +00:00

640 lines
16 KiB
JavaScript

RMS.LoadLibrary("rmgen");
const WATER_WIDTH = 0.1;
// terrain textures
const tOceanDepths = "medit_sea_depths";
const tOceanRockDeep = "medit_sea_coral_deep";
const tOceanRockShallow = "medit_rocks_wet";
const tOceanCoral = "medit_sea_coral_plants";
const tBeachWet = "medit_sand_wet";
const tBeachDry = "medit_sand";
const tBeachGrass = "medit_rocks_grass";
const tBeachCliff = "medit_dirt";
const tCity = "medit_city_tile";
const tGrassDry = ["medit_grass_field_brown", "medit_grass_field_dry", "medit_grass_field_b"];
const tGrass = ["medit_grass_field_dry", "medit_grass_field_brown", "medit_grass_field_b"];
const tGrassLush = ["grass_temperate_dry_tufts", "medit_grass_flowers"];
const tGrassShrubs = ["medit_grass_shrubs", "medit_grass_flowers"];
const tGrassRock = ["medit_rocks_grass"];
const tDirt = "medit_dirt";
const tDirtGrass = "medit_dirt_b";
const tDirtCliff = "medit_cliff_italia";
const tGrassCliff = "medit_cliff_italia_grass";
const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"];
const tForestFloor = "medit_grass_wild";
// gaia entities
const oBeech = "gaia/flora_tree_euro_beech";
const oBerryBush = "gaia/flora_bush_berry";
const oCarob = "gaia/flora_tree_carob";
const oCypress1 = "gaia/flora_tree_cypress";
const oCypress2 = "gaia/flora_tree_cypress";
const oLombardyPoplar = "gaia/flora_tree_poplar_lombardy";
const oOak = "gaia/flora_tree_oak";
const oPalm = "gaia/flora_tree_medit_fan_palm";
const oPine = "gaia/flora_tree_aleppo_pine";
const oPoplar = "gaia/flora_tree_poplar";
const oChicken = "gaia/fauna_chicken";
const oDeer = "gaia/fauna_deer";
const oFish = "gaia/fauna_fish";
const oSheep = "gaia/fauna_sheep";
const oStoneLarge = "gaia/geology_stonemine_medit_quarry";
const oStoneSmall = "gaia/geology_stone_mediterranean";
const oMetalLarge = "gaia/geology_metal_mediterranean_slabs";
// decorative props
const aBushLargeDry = "actor|props/flora/bush_medit_la_dry.xml";
const aBushLarge = "actor|props/flora/bush_medit_la.xml";
const aBushMedDry = "actor|props/flora/bush_medit_me_dry.xml";
const aBushMed = "actor|props/flora/bush_medit_me.xml";
const aBushSmall = "actor|props/flora/bush_medit_sm.xml";
const aBushSmallDry = "actor|props/flora/bush_medit_sm_dry.xml";
const aGrass = "actor|props/flora/grass_soft_large_tall.xml";
const aGrassDry = "actor|props/flora/grass_soft_dry_large_tall.xml";
const aRockLarge = "actor|geology/stone_granite_large.xml";
const aRockMed = "actor|geology/stone_granite_med.xml";
const aRockSmall = "actor|geology/stone_granite_small.xml";
const aWaterLog = "actor|props/flora/water_log.xml";
// terrain + entity (for painting)
var pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass];
var pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass];
var pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass];
var pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass];
const BUILDING_ANGlE = 0.75*PI;
// initialize map
log("Initializing map...");
InitMap();
var numPlayers = getNumPlayers();
var mapSize = getMapSize();
var mapArea = mapSize*mapSize;
// Create classes
var clWater = createTileClass();
var clCliff = createTileClass();
var clForest = createTileClass();
var clMetal = createTileClass();
var clStone = createTileClass();
var clFood = createTileClass();
var clPlayer = createTileClass();
var clBaseResource = createTileClass();
var clSettlement = createTileClass();
// randomize player order
var playerIDs = [];
for (var i = 0; i < numPlayers; i++)
{
playerIDs.push(i+1);
}
playerIDs = shuffleArray(playerIDs);
// Place players
log("Creating players...");
var playerX = new Array(numPlayers+1);
var playerZ = new Array(numPlayers+1);
var numLeftPlayers = ceil(numPlayers/2);
for (var i = 1; i <= numLeftPlayers; i++)
{
playerX[i] = 0.28 + randFloat(-0.01, 0.01);
playerZ[i] = (0.5+i-1)/numLeftPlayers + randFloat(-0.01, 0.01);
}
for (var i = numLeftPlayers+1; i <= numPlayers; i++)
{
playerX[i] = 0.72 + randFloat(-0.01, 0.01);
playerZ[i] = (0.5+i-numLeftPlayers-1)/numLeftPlayers + randFloat(-0.01, 0.01);
}
function distanceToPlayers(x, z)
{
var r = 10000;
for (var i = 1; i <= numPlayers; i++)
{
var dx = x - playerX[i];
var dz = z - playerZ[i];
r = min(r, dx*dx + dz*dz);
}
return sqrt(r);
}
function playerNearness(x, z)
{
var d = fractionToTiles(distanceToPlayers(x,z));
if (d < 13)
{
return 0;
}
else if (d < 19)
{
return (d-13)/(19-13);
}
else
{
return 1;
}
}
// Paint elevation
log("Painting elevation...");
var noise0 = new Noise2D(scaleByMapSize(4, 16));
var noise1 = new Noise2D(scaleByMapSize(8, 32));
var noise2 = new Noise2D(scaleByMapSize(15, 60));
var noise2a = new Noise2D(scaleByMapSize(20, 80));
var noise2b = new Noise2D(scaleByMapSize(35, 140));
var noise3 = new Noise2D(scaleByMapSize(4, 16));
var noise4 = new Noise2D(scaleByMapSize(6, 24));
var noise5 = new Noise2D(scaleByMapSize(11, 44));
for (var ix = 0; ix <= mapSize; ix++)
{
for (var iz = 0; iz <= mapSize; iz++)
{
var x = ix / (mapSize + 1.0);
var z = iz / (mapSize + 1.0);
var pn = playerNearness(x, z);
var h = 0;
var distToWater = 0;
h = 32 * (x - 0.5);
// add the rough shape of the water
if (x < WATER_WIDTH)
{
h = max(-16.0, -28.0*(WATER_WIDTH-x)/WATER_WIDTH);
}
else if (x > 1.0-WATER_WIDTH)
{
h = max(-16.0, -28.0*(x-(1.0-WATER_WIDTH))/WATER_WIDTH);
}
else
{
distToWater = (0.5 - WATER_WIDTH - abs(x-0.5));
var u = 1 - abs(x-0.5) / (0.5-WATER_WIDTH);
h = 12*u;
}
// add some base noise
var baseNoise = 16*noise0.get(x,z) + 8*noise1.get(x,z) + 4*noise2.get(x,z) - (16+8+4)/2;
if ( baseNoise < 0 )
{
baseNoise *= pn;
baseNoise *= max(0.1, distToWater / (0.5-WATER_WIDTH));
}
var oldH = h;
h += baseNoise;
// add some higher-frequency noise on land
if ( oldH > 0 )
{
h += (0.4*noise2a.get(x,z) + 0.2*noise2b.get(x,z)) * min(oldH/10.0, 1.0);
}
// create cliff noise
if ( h > -10 )
{
var cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5;
if (h < 1)
{
var u = 1 - 0.3*((h-1)/-10);
cliffNoise *= u;
}
cliffNoise += 0.05 * distToWater / (0.5 - WATER_WIDTH);
if (cliffNoise > 0.6)
{
var u = 0.8 * (cliffNoise - 0.6);
cliffNoise += u * noise5.get(x,z);
cliffNoise /= (1 + u);
}
cliffNoise -= 0.59;
cliffNoise *= pn;
if (cliffNoise > 0)
{
h += 19 * min(cliffNoise, 0.045) / 0.045;
}
}
// set the height
setHeight(ix, iz, h);
}
}
RMS.SetProgress(15);
// Paint base terrain
log("Painting terrain...");
var noise6 = new Noise2D(scaleByMapSize(10, 40));
var noise7 = new Noise2D(scaleByMapSize(20, 80));
var noise8 = new Noise2D(scaleByMapSize(13, 52));
var noise9 = new Noise2D(scaleByMapSize(26, 104));
var noise10 = new Noise2D(scaleByMapSize(50, 200));
for (var ix = 0; ix < mapSize; ix++)
{
for (var iz = 0; iz < mapSize; iz++)
{
var x = ix / (mapSize + 1.0);
var z = iz / (mapSize + 1.0);
var pn = playerNearness(x, z);
// get heights of surrounding vertices
var h00 = getHeight(ix, iz);
var h01 = getHeight(ix, iz+1);
var h10 = getHeight(ix+1, iz);
var h11 = getHeight(ix+1, iz+1);
// find min and max height
var maxH = Math.max(h00, h01, h10, h11);
var minH = Math.min(h00, h01, h10, h11);
var diffH = maxH - minH;
// figure out if we're at the top of a cliff using min adjacent height
var minAdjHeight = minH;
if (maxH > 15)
{
var maxNx = min(ix+2, mapSize);
var maxNz = min(iz+2, mapSize);
for (var nx = max(ix-1, 0); nx <= maxNx; nx++)
{
for (var nz = max(iz-1, 0); nz <= maxNz; nz++)
{
minAdjHeight = min(minAdjHeight, getHeight(nx, nz));
}
}
}
// choose a terrain based on elevation
var t = tGrass;
// water
if (maxH < -12)
{
t = tOceanDepths;
}
else if (maxH < -8.8)
{
t = tOceanRockDeep;
}
else if (maxH < -4.7)
{
t = tOceanCoral;
}
else if (maxH < -2.8)
{
t = tOceanRockShallow;
}
else if (maxH < 0.9 && minH < 0.35)
{
t = tBeachWet;
}
else if (maxH < 1.5 && minH < 0.9)
{
t = tBeachDry;
}
else if (maxH < 2.3 && minH < 1.3)
{
t = tBeachGrass;
}
if (minH < 0)
{
addToClass(ix, iz, clWater);
}
// cliffs
if (diffH > 2.9 && minH > -7)
{
t = tCliff;
addToClass(ix, iz, clCliff);
}
else if ((diffH > 2.5 && minH > -5) || ((maxH - minAdjHeight) > 2.9 && minH > 0) )
{
if (minH < -1)
t = tCliff;
else if (minH < 0.5)
t = tBeachCliff;
else
t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff];
addToClass(ix, iz, clCliff);
}
if (minH >= 7)
{
addToClass(ix, iz, clCliff);
}
// forests
if (getHeight(ix, iz) <11){
if (diffH < 2 && minH > 1)
{
var forestNoise = (noise6.get(x,z) + 0.5*noise7.get(x,z)) / 1.5 * pn - 0.59;
// Thin out trees a bit
if (forestNoise > 0 && randFloat() < 0.5)
{
if (minH < 11 && minH >= 4)
{
var typeNoise = noise10.get(x,z);
if (typeNoise < 0.43 && forestNoise < 0.05)
t = pPoplarForest;
else if (typeNoise < 0.63)
t = pMainForest;
else
t = pPineForest;
addToClass(ix, iz, clForest);
}
else if (minH < 4)
{
t = pPalmForest;
addToClass(ix, iz, clForest);
}
}
}
}
// grass variations
if (t == tGrass)
{
var grassNoise = (noise8.get(x,z) + 0.6*noise9.get(x,z)) / 1.6;
if (grassNoise < 0.3)
{
t = (diffH > 1.2) ? tDirtCliff : tDirt;
}
else if (grassNoise < 0.34)
{
t = (diffH > 1.2) ? tGrassCliff : tGrassDry;
if (diffH < 0.5 && randFloat() < 0.02)
{
placeObject(ix+randFloat(), iz+randFloat(), aGrassDry, 0, randFloat(0, TWO_PI));
}
}
else if (grassNoise > 0.61)
{
t = (diffH > 1.2 ? tGrassRock : tGrassShrubs);
}
else
{
if (diffH < 0.5 && randFloat() < 0.02)
{
placeObject(ix+randFloat(), iz+randFloat(), aGrass, 0, randFloat(0, TWO_PI));
}
}
}
placeTerrain(ix, iz, t);
}
}
RMS.SetProgress(30);
for (var i = 1; i <= numPlayers; i++)
{
var id = playerIDs[i-1];
log("Creating base for player " + id + "...");
// get fractional locations in tiles
var fx = fractionToTiles(playerX[i]);
var fz = fractionToTiles(playerZ[i]);
var ix = round(fx);
var iz = round(fz);
addToClass(ix, iz, clPlayer);
// create the city patch, flatten area under TC
var cityRadius = 11;
var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz);
var painter = new LayeredPainter([tGrass, tCity], [4]);
var elevationPainter = new SmoothElevationPainter(
ELEVATION_SET, // type
5, // elevation
2 // blend radius
);
createArea(placer, [painter, elevationPainter], null);
// get civ specific starting entities
var civEntities = getStartingEntities(id-1);
// create starting units
createStartingPlayerEntities(fx, fz, id, civEntities, BUILDING_ANGlE)
// create animals
for (var j = 0; j < 2; ++j)
{
var aAngle = randFloat(0, TWO_PI);
var aDist = 7;
var aX = round(fx + aDist * cos(aAngle));
var aZ = round(fz + aDist * sin(aAngle));
var group = new SimpleGroup(
[new SimpleObject(oChicken, 5,5, 0,3)],
true, clBaseResource, aX, aZ
);
createObjectGroup(group, 0);
}
// create starting berry bushes
var bbAngle = randFloat(0, TWO_PI);
var bbDist = 9;
var bbX = round(fx + bbDist * cos(bbAngle));
var bbZ = round(fz + bbDist * sin(bbAngle));
group = new SimpleGroup(
[new SimpleObject(oBerryBush, 5,5, 0,2)],
true, clBaseResource, bbX, bbZ
);
createObjectGroup(group, 0);
// create metal mine
var mAngle = bbAngle;
while(abs(mAngle - bbAngle) < PI/3)
{
mAngle = randFloat(0, TWO_PI);
}
var mDist = 12;
var mX = round(fx + mDist * cos(mAngle));
var mZ = round(fz + mDist * sin(mAngle));
group = new SimpleGroup(
[new SimpleObject(oMetalLarge, 1,1, 0,0)],
true, clBaseResource, mX, mZ
);
createObjectGroup(group, 0);
// create stone mines
mAngle += randFloat(PI/8, PI/4);
mX = round(fx + mDist * cos(mAngle));
mZ = round(fz + mDist * sin(mAngle));
group = new SimpleGroup(
[new SimpleObject(oStoneLarge, 1,1, 0,2)],
true, clBaseResource, mX, mZ
);
createObjectGroup(group, 0);
// create starting straggler trees
group = new SimpleGroup(
[new SimpleObject(oPalm, 3,3, 7,10)],
true, clBaseResource, ix, iz
);
createObjectGroup(group, 0, avoidClasses(clBaseResource,2));
}
RMS.SetProgress(40);
log("Creating bushes...");
// create bushes
group = new SimpleGroup(
[new SimpleObject(aBushSmall, 0,2, 0,2), new SimpleObject(aBushSmallDry, 0,2, 0,2),
new SimpleObject(aBushMed, 0,1, 0,2), new SimpleObject(aBushMedDry, 0,1, 0,2)]
);
createObjectGroups(group, 0,
avoidClasses(clWater, 4, clCliff, 2),
scaleByMapSize(9, 146), 50
);
RMS.SetProgress(45);
log("Creating rocks...");
// create rocks
group = new SimpleGroup(
[new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2),
new SimpleObject(aRockLarge, 0,1, 0,2)]
);
createObjectGroups(group, 0,
avoidClasses(clWater, 2, clCliff, 1),
scaleByMapSize(9, 146), 50
);
RMS.SetProgress(50);
log("Creating stone mines...");
// create large stone quarries
group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clStone);
createObjectGroups(group, 0,
[avoidClasses(clWater, 1, clForest, 1, clPlayer, 20, clStone, 15, clCliff, 3)],
scaleByMapSize(4,16), 100
);
// create small stone quarries
group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clStone);
createObjectGroups(group, 0,
[avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clStone, 15, clCliff, 3)],
scaleByMapSize(4,16), 100
);
log("Creating metal mines...");
// create large metal quarries
group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,2)], true, clMetal);
createObjectGroups(group, 0,
[avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clMetal, 15, clStone, 5, clCliff, 3),
borderClasses(clCliff, 0, 5)],
scaleByMapSize(4,16), 100
);
RMS.SetProgress(60);
log("Creating straggler trees...");
// create straggler trees
var trees = [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine];
for (var t in trees)
{
group = new SimpleGroup([new SimpleObject(trees[t], 1,1, 0,1)], true, clForest);
createObjectGroups(group, 0,
avoidClasses(clWater, 5, clCliff, 4, clForest, 1, clPlayer, 15, clMetal, 1, clStone, 1),
scaleByMapSize(2, 38), 50
);
}
RMS.SetProgress(70);
// create straggler cypresses
group = new SimpleGroup(
[new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)],
true
);
createObjectGroups(group, 0,
avoidClasses(clWater, 4, clCliff, 4, clForest, 1, clPlayer, 15, clMetal, 1, clStone, 1),
scaleByMapSize(5, 75), 50
);
RMS.SetProgress(80);
log("Creating sheep...");
// create sheep
group = new SimpleGroup([new SimpleObject(oSheep, 2,4, 0,2)], true, clFood);
createObjectGroups(group, 0,
avoidClasses(clWater, 5, clForest, 1, clCliff, 1, clPlayer, 20, clMetal, 2, clStone, 2, clFood, 8),
3 * numPlayers, 50
);
RMS.SetProgress(85);
log("Creating fish...");
// create fish
var num = scaleByMapSize(4, 16);
var offsetX = mapSize * WATER_WIDTH/2;
for (var i = 0; i < num; ++i)
{
var cX = round(offsetX + offsetX/2 * randFloat(-1, 1));
var cY = round((i + 0.5) * mapSize/num);
group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,1)], true, clFood, cX, cY);
createObjectGroup(group, 0);
}
for (var i = 0; i < num; ++i)
{
var cX = round(mapSize - offsetX + offsetX/2 * randFloat(-1, 1));
var cY = round((i + 0.5) * mapSize/num);
group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,1)], true, clFood, cX, cY);
createObjectGroup(group, 0);
}
RMS.SetProgress(90);
// create deer
log("Creating deer...");
group = new SimpleGroup(
[new SimpleObject(oDeer, 5,7, 0,4)],
true, clFood
);
createObjectGroups(group, 0,
avoidClasses(clWater, 5, clForest, 1, clCliff, 1, clPlayer, 20, clMetal, 2, clStone, 2, clFood, 8),
3 * numPlayers, 50
);
RMS.SetProgress(95);
log("Creating berry bushes...");
// create berry bushes
group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood);
createObjectGroups(group, 0,
avoidClasses(clWater, 5, clForest, 1, clCliff, 1, clPlayer, 20, clMetal, 2, clStone, 2, clFood, 8),
1.5 * numPlayers, 100
);
// Adjust environment
setSkySet("sunny");
setWaterMurkiness(0.626953);
setWaterShininess(0.732422);
setWaterTint(0, 0.501961, 0.501961);
setWaterReflectionTint(0.313726, 0.376471, 0.521569);
setWaterReflectionTintStrength(0.615234);
// Export map data
ExportMap();