copy badosu maps into community mod, need to check feldmap compatibibility.

This commit is contained in:
rca 2024-06-12 10:14:16 -07:00 committed by rts
parent bcc27a8564
commit ae94c04bac
26 changed files with 3937 additions and 0 deletions

View File

@ -0,0 +1,403 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("balancedHelpers");
const tPrimary = "temp_grass_long";
const tGrass = ["temp_grass_clovers"];
const tGrassPForest = "temp_plants_bog";
const tGrassDForest = "alpine_dirt_grass_50";
const tCliff = ["temp_cliff_a", "temp_cliff_b"];
const tGrassA = "temp_grass_d";
const tGrassB = "temp_grass_c";
const tGrassC = "temp_grass_clovers_2";
const tHill = ["temp_highlands", "temp_grass_long_b"];
const tRoad = "temp_road";
const tRoadWild = "temp_road_overgrown";
const tGrassPatch = "temp_grass_plants";
const tShore = "medit_sand_wet";
const tWater = "medit_sand_wet";
const oPoplar = "gaia/tree/poplar";
const oPalm = "gaia/tree/cretan_date_palm_short";
const oApple = "gaia/fruit/apple";
const oOak = "gaia/tree/oak";
const oBerryBush = "gaia/fruit/berry_01";
const oDeer = "gaia/fauna_deer";
const oFish = "gaia/fish/generic";
const oGoat = "gaia/fauna_goat";
const oBoar = "gaia/fauna_boar";
const oStoneLarge = "gaia/rock/temperate_large";
const oStoneSmall = "gaia/rock/temperate_small";
const oMetalLarge = "gaia/ore/temperate_large";
const oFruitBush = oBerryBush;
const oMainHuntableAnimal = oDeer;
const oSecondaryHuntableAnimal = oGoat;
const aGrass = "actor|props/flora/grass_soft_large_tall.xml";
const aGrassShort = "actor|props/flora/grass_soft_large.xml";
const aRockLarge = "actor|geology/stone_granite_large.xml";
const aRockMedium = "actor|geology/stone_granite_med.xml";
const aBushMedium = "actor|props/flora/bush_medit_me_lush.xml";
const aBushSmall = "actor|props/flora/bush_medit_sm_lush.xml";
const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oPoplar, tGrassDForest];
const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest];
const heightSeaGround1 = -3;
const heightShore1 = -1.5;
const heightShore2 = 0;
const heightLand = 1;
const heightOffsetBump = 4;
const heightHill = 15;
var g_Map = new RandomMap(heightLand, tPrimary);
const mapCenter = g_Map.getCenter();
const mapBounds = g_Map.getBounds();
const numPlayers = getNumPlayers();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clWater = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
const clHighlands = g_Map.createTileClass();
const waterPosition = fractionToTiles(0.25)
const highlandsPosition = fractionToTiles(0.75);
const startAngle = randomAngle();
const playerPlacements = placeOpposingTeams(fractionToTiles(0.25), -startAngle, mapCenter)
const [playerIDs, playerPositions] = playerPlacements;
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oBerryBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oOak,
"count": 2
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(10);
paintRiver({
"parallel": true,
"start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle, mapCenter),
"end": new Vector2D(mapBounds.right, mapBounds.top).rotateAround(startAngle, mapCenter),
"width": (numPlayers === 2 ? 2.5 : 2) * waterPosition,
"fadeDist": scaleByMapSize(6, 25),
"deviation": 0,
"heightRiverbed": heightSeaGround1,
"heightLand": heightLand,
"meanderShort": 20,
"meanderLong": 0,
"waterFunc": (position, height, riverFraction) => {
if (height < heightShore2)
clWater.add(position);
createTerrain(height < heightShore1 ? tWater : tShore).place(position);
}
});
Engine.SetProgress(20);
for (let i = 0; i < numPlayers; ++i)
{
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oFish, 3, 3, 0, 4)], true, clFood),
0,
stayClasses(clWater, 3),
1, 400,
[new Area(new DiskPlacer(3, Vector2D.add(playerPositions[i], new Vector2D(scaleByMapSize(46, 90)).rotate(startAngle - Math.PI / 2))).place(new NullConstraint()))]
);
Engine.SetProgress(20 + i);
}
const mineralConstraints = avoidClasses(clWater, 3);
placeBalancedMinerals(playerPositions, mineralConstraints);
Engine.SetProgress(30);
placeBalancedFood(playerPlacements, avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10));
Engine.SetProgress(40);
g_Map.log("Marking highlands area");
createArea(
new ConvexPolygonPlacer(
[
new Vector2D(mapBounds.left, mapBounds.top - highlandsPosition),
new Vector2D(mapBounds.right, mapBounds.top - highlandsPosition),
new Vector2D(mapBounds.left, mapBounds.bottom),
new Vector2D(mapBounds.right, mapBounds.bottom)
].map(pos => pos.rotateAround(startAngle, mapCenter)),
Infinity),
new TileClassPainter(clHighlands));
Engine.SetProgress(43);
g_Map.log("Creating fish");
for (let i = 0; i < scaleByMapSize(50, 80); ++i)
createObjectGroupsDeprecated(
new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood),
0,
[stayClasses(clWater, 8), avoidClasses(clFood, 10)],
numPlayers,
50);
Engine.SetProgress(46);
g_Map.log("Creating bumps");
createAreas(
new ClumpPlacer(scaleByMapSize(10, 60), 0.3, 0.06, Infinity),
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3),
stayClasses(clHighlands, 1),
scaleByMapSize(300, 600));
Engine.SetProgress(49);
g_Map.log("Creating hills");
createAreas(
new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity),
[
new LayeredPainter([tCliff, tHill], [2]),
new SmoothElevationPainter(ELEVATION_SET, heightHill, 2),
new TileClassPainter(clHill)
],
avoidClasses(clPlayer, 20, clWater, 5, clHill, 15, clHighlands, 5, clRock, 6, clMetal, 6, clFood, 2),
scaleByMapSize(1, 4) * numPlayers);
Engine.SetProgress(52);
g_Map.log("Creating mainland forests");
var [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7);
var types = [
[[tGrassDForest, tGrass, pForestD], [tGrassDForest, pForestD]]
];
var size = forestTrees * 1.3 / (scaleByMapSize(2,8) * numPlayers);
var num = Math.floor(0.7 * size / types.length);
for (let type of types)
createAreas(
new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity),
[
new LayeredPainter(type, [2]),
new TileClassPainter(clForest)
],
avoidClasses(clPlayer, 20, clWater, 3, clForest, 10, clHill, 0, clBaseResource, 3, clRock, 2, clMetal, 2),
num);
Engine.SetProgress(55);
g_Map.log("Creating highland forests");
var types = [
[[tGrassDForest, tGrass, pForestP], [tGrassDForest, pForestP]]
];
var size = forestTrees / (scaleByMapSize(2,8) * numPlayers);
var num = Math.floor(size / types.length);
for (let type of types)
createAreas(
new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity),
[
new LayeredPainter(type, [2]),
new TileClassPainter(clForest)
],
avoidClasses(clPlayer, 20, clWater, 3, clForest, 2, clHill, 0, clMetal, 2, clRock, 2),
num);
Engine.SetProgress(60);
g_Map.log("Creating dirt patches");
for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)])
createAreas(
new ClumpPlacer(size, 0.3, 0.06, 0.5),
[
new LayeredPainter([[tGrass, tGrassA], [tGrassA, tGrassB], [tGrassB, tGrassC]], [1, 1]),
new TileClassPainter(clDirt)
],
avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4),
scaleByMapSize(15, 45));
Engine.SetProgress(63);
g_Map.log("Creating grass patches");
for (let size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)])
createAreas(
new ClumpPlacer(size, 0.3, 0.06, 0.5),
new LayeredPainter([tGrassC, tGrassPatch], [2]),
avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6, clBaseResource, 6),
scaleByMapSize(15, 45));
Engine.SetProgress(66);
var group;
g_Map.log("Creating stone mines");
var group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock);
createObjectGroupsDeprecated(group, 0,
[avoidClasses(clWater, 0, clForest, 1, clPlayer, 60, clRock, 10, clHill, 2)],
scaleByMapSize(4,16), 100
);
Engine.SetProgress(69);
g_Map.log("Creating small stone quarries");
group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock);
createObjectGroupsDeprecated(group, 0,
[avoidClasses(clWater, 0, clForest, 1, clPlayer, 60, clRock, 10, clHill, 2)],
scaleByMapSize(4,16), 100
);
Engine.SetProgress(73);
g_Map.log("Creating metal mines");
group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal);
createObjectGroupsDeprecated(group, 0,
[avoidClasses(clWater, 0, clForest, 1, clPlayer, 60, clMetal, 10, clRock, 5, clHill, 2)],
scaleByMapSize(4,16), 100
);
Engine.SetProgress(76);
g_Map.log("Creating small decorative rocks");
group = new SimpleGroup(
[new SimpleObject(aRockMedium, 1,3, 0,1)],
true
);
createObjectGroupsDeprecated(
group, 0,
avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0),
scaleByMapSize(16, 262), 50
);
Engine.SetProgress(79);
g_Map.log("Creating large decorative rocks");
group = new SimpleGroup(
[new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)],
true
);
createObjectGroupsDeprecated(
group, 0,
avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0),
scaleByMapSize(8, 131), 50
);
Engine.SetProgress(82);
g_Map.log("Creating deer");
group = new SimpleGroup(
[new SimpleObject(oDeer, 5,7, 0,4)],
true, clFood
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clWater, 0, clForest, 0, clPlayer, 50, clHill, 0, clFood, 5),
6 * numPlayers, 50
);
Engine.SetProgress(85);
g_Map.log("Creating sheep");
group = new SimpleGroup(
[new SimpleObject(oGoat, 2,3, 0,2)],
true, clFood
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clWater, 0, clForest, 0, clPlayer, 50, clHill, 0, clFood, 20),
3 * numPlayers, 50
);
Engine.SetProgress(88);
g_Map.log("Creating berry bush");
group = new SimpleGroup(
[new SimpleObject(oBerryBush, 5,7, 0,4)],
true, clFood
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clWater, 6, clForest, 0, clPlayer, 45, clHill, 1, clFood, 10),
randIntInclusive(1, 4) * numPlayers + 2, 50
);
Engine.SetProgress(92);
g_Map.log("Creating boar");
group = new SimpleGroup(
[new SimpleObject(oBoar, 2,3, 0,2)],
true, clFood
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clWater, 0, clForest, 0, clPlayer, 50, clHill, 0, clFood, 20),
2 * numPlayers, 50
);
createStragglerTrees(
[oPoplar, oPalm, oApple],
avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 38, clMetal, 6, clRock, 6),
clForest,
stragglerTrees);
for (let playerPosition of playerPositions) {
const playerArea = new Area(new DiskPlacer(40, playerPosition).place(avoidClasses(clWater, 1, clForest, 1, clHill, 1, clMetal, 6, clRock, 6, clPlayer, 15, clFood, 4)));
for (let templateName of [oPoplar, oPalm]) {
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(templateName, 1, 1, 0, 3)], true, clForest),
0,
new NullConstraint(),
25, 400,
[playerArea]
);
}
}
g_Map.log("Creating small grass tufts");
group = new SimpleGroup(
[new SimpleObject(aGrassShort, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)]
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0),
scaleByMapSize(13, 200)
);
g_Map.log("Creating large grass tufts");
group = new SimpleGroup(
[new SimpleObject(aGrass, 2,4, 0,1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -Math.PI / 8, Math.PI / 8)]
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0),
scaleByMapSize(13, 200)
);
Engine.SetProgress(95);
g_Map.log("Creating bushes");
group = new SimpleGroup(
[new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)]
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1),
scaleByMapSize(13, 200), 50
);
placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2));
setSkySet("cirrus");
setWaterColor(0.114, 0.192, 0.463);
setWaterTint(0.255, 0.361, 0.651);
setWaterWaviness(2.0);
setWaterType("ocean");
setWaterMurkiness(0.83);
g_Map.ExportMap();

View File

@ -0,0 +1,10 @@
{
"settings" : {
"Name" : "Balanced Hyrcanian Shores",
"Script" : "bad_hyrcanian_shores.js",
"Description" : "Each player starts in a coastal area between forested hills and the Caspian Sea. Resources are distributed evenly to players.",
"Preview" : "badhyrcanian.png",
"Keywords": ["badmod"],
"CircularMap" : true
}
}

View File

@ -0,0 +1,285 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("rmbiome");
Engine.LoadLibrary("balancedHelpers");
setSelectedBiome();
const tMainTerrain = g_Terrains.mainTerrain;
const tForestFloor1 = g_Terrains.forestFloor1;
const tForestFloor2 = g_Terrains.forestFloor2;
const tCliff = g_Terrains.cliff;
const tTier1Terrain = g_Terrains.tier1Terrain;
const tTier2Terrain = g_Terrains.tier2Terrain;
const tTier3Terrain = g_Terrains.tier3Terrain;
const tHill = g_Terrains.hill;
const tRoad = g_Terrains.road;
const tRoadWild = g_Terrains.roadWild;
const tTier4Terrain = g_Terrains.tier4Terrain;
const tShore = g_Terrains.shore;
const tWater = g_Terrains.water;
const oTree1 = g_Gaia.tree1;
const oTree2 = g_Gaia.tree2;
const oTree3 = g_Gaia.tree3;
const oTree4 = g_Gaia.tree4;
const oTree5 = g_Gaia.tree5;
const oFruitBush = g_Gaia.fruitBush;
const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
const oFish = g_Gaia.fish;
const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
const oStoneLarge = g_Gaia.stoneLarge;
const oStoneSmall = g_Gaia.stoneSmall;
const oMetalLarge = g_Gaia.metalLarge;
const aGrass = g_Decoratives.grass;
const aGrassShort = g_Decoratives.grassShort;
const aRockLarge = g_Decoratives.rockLarge;
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const heightSeaGround = -5;
const heightLand = 3;
var g_Map = new RandomMap(heightSeaGround, tWater);
const numPlayers = getNumPlayers();
const mapSize = g_Map.getSize();
const mapCenter = g_Map.getCenter();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
const clLand = g_Map.createTileClass();
g_Map.log("Creating continent");
createArea(
new ChainPlacer(
2,
Math.floor(scaleByMapSize(5, 12)),
Math.floor(scaleByMapSize(60, 700)),
Infinity,
mapCenter,
0,
[Math.floor(fractionToTiles(0.33))]),
[
new SmoothElevationPainter(ELEVATION_SET, heightLand, 4),
new TileClassPainter(clLand)
]);
const playerPlacements = playerPlacementCircle(fractionToTiles(0.25));
const [playerIDs, playerPositions] = playerPlacements;
g_Map.log("Ensuring initial player land");
for (let i = 0; i < numPlayers; ++i)
createArea(
new ChainPlacer(
2,
Math.floor(scaleByMapSize(5, 9)),
Math.floor(scaleByMapSize(5, 20)),
Infinity,
playerPositions[i],
0,
[Math.floor(scaleByMapSize(23, 50))]),
[
new SmoothElevationPainter(ELEVATION_SET, heightLand, 4),
new TileClassPainter(clLand)
]);
Engine.SetProgress(20);
paintTerrainBasedOnHeight(3, 4, 3, tMainTerrain);
paintTerrainBasedOnHeight(1, 3, 0, tShore);
paintTerrainBasedOnHeight(-8, 1, 2, tWater);
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oFruitBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oTree1,
"count": 2
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(30);
createBumps([avoidClasses(clPlayer, 10), stayClasses(clLand, 5)]);
Engine.SetProgress(35);
placeBalancedMinerals(playerPositions, stayClasses(clLand, 5));
Engine.SetProgress(40);
placeBalancedFood(playerPlacements,
new AndConstraint([avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10), stayClasses(clLand, 5)])
);
Engine.SetProgress(45);
if (currentBiome() != "generic/savanna") {
createBalancedPlayerForests(
playerPositions,
new AndConstraint([avoidClasses(clForest, 18, clHill, 1, clMetal, 4, clRock, 4, clFood, 4), stayClasses(clLand, 5)]),
clForest);
}
Engine.SetProgress(50);
if (randBool())
createHills([tMainTerrain, tCliff, tHill], [avoidClasses(clPlayer, 20, clHill, 15, clBaseResource, 3), stayClasses(clLand, 5)], clHill, scaleByMapSize(1, 4) * numPlayers);
else
createMountains(tCliff, [avoidClasses(clPlayer, 20, clHill, 15, clBaseResource, 3), stayClasses(clLand, 5)], clHill, scaleByMapSize(1, 4) * numPlayers);
Engine.SetProgress(55);
var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1));
createForests(
[tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2],
[avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clBaseResource,2), stayClasses(clLand, 4)],
clForest,
forestTrees);
Engine.SetProgress(60);
g_Map.log("Creating dirt patches");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1,1],
[avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)],
scaleByMapSize(15, 45),
clDirt);
g_Map.log("Creating grass patches");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
[avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)],
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(65);
g_Map.log("Creating stone mines");
createMines(
[
[new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)],
[new SimpleObject(oStoneSmall, 2,5, 1,3)]
],
[avoidClasses(clForest, 1, clPlayer, 60, clRock, 10, clHill, 1), stayClasses(clLand, 6)],
clRock);
g_Map.log("Creating metal mines");
createMines(
[
[new SimpleObject(oMetalLarge, 1,1, 0,4)]
],
[avoidClasses(clForest, 1, clPlayer, 60, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 6)],
clMetal
);
Engine.SetProgress(70);
// create decoration
var planetm = 1;
if (currentBiome() == "generic/tropic")
planetm = 8;
createDecoration(
[
[new SimpleObject(aRockMedium, 1, 3, 0, 1)],
[new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
[new SimpleObject(aGrassShort, 1, 2, 0, 1)],
[new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5)],
[new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
[avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)]);
Engine.SetProgress(75);
createBadFood(new AndConstraint([avoidClasses(clForest, 0, clHill, 1, clMetal, 4, clRock, 4, clFood, 20), stayClasses(clLand, 5)]), 3);
createFood(
[
[new SimpleObject(oFruitBush, 5, 7, 0, 4)]
],
[
3 * numPlayers
],
[avoidClasses(clForest, 0, clPlayer, 45, clHill, 1, clFood, 10, clMetal, 4, clRock, 4), stayClasses(clLand, 5)],
clFood);
createFood(
[
[new SimpleObject(oFish, 2, 3, 0, 2)]
],
[
scaleByMapSize(50, 500)
],
avoidClasses(clLand, 2, clFood, 10),
clFood);
Engine.SetProgress(85);
createStragglerTrees(
[oTree1, oTree2, oTree4, oTree3],
[avoidClasses(
clForest, 7, clHill, 1, clPlayer,
(currentBiome() == "generic/savanna") ? 12 : 38,
clMetal, 6, clRock, 6, clFood, 1, clBaseResource, 2
), stayClasses(clLand, 7)],
clForest,
stragglerTrees);
createBalancedPlayerStragglerTrees(
playerPositions,
[oTree1, oTree2, oTree4, oTree3],
[avoidClasses(clForest, 8, clHill, 1, clMetal, 6, clRock, 6, clFood, 1, clBaseResource, 2), stayClasses(clLand, 7)],
25,
clForest
)
placePlayersNomad(
clPlayer,
[stayClasses(clLand, 4), avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)]);
setWaterWaviness(1.0);
setWaterType("ocean");
g_Map.ExportMap();

View File

@ -0,0 +1,11 @@
{
"settings" : {
"Name" : "Balanced Continent",
"Script" : "badcontinent.js",
"Description" : "All players starts on a continent surrounded by water. Resources are distributed evenly between players.",
"Preview" : "continent.png",
"SupportedBiomes": "generic/",
"Keywords": ["badmod"],
"CircularMap" : true
}
}

View File

@ -0,0 +1,252 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("rmbiome");
Engine.LoadLibrary("balancedHelpers");
setSelectedBiome();
const tMainTerrain = g_Terrains.mainTerrain;
const tForestFloor1 = g_Terrains.forestFloor1;
const tForestFloor2 = g_Terrains.forestFloor2;
const tCliff = g_Terrains.cliff;
const tTier1Terrain = g_Terrains.tier1Terrain;
const tTier2Terrain = g_Terrains.tier2Terrain;
const tTier3Terrain = g_Terrains.tier3Terrain;
const tHill = g_Terrains.hill;
const tRoad = g_Terrains.road;
const tRoadWild = g_Terrains.roadWild;
const tTier4Terrain = g_Terrains.tier4Terrain;
const oTree1 = g_Gaia.tree1;
const oTree2 = g_Gaia.tree2;
const oTree3 = g_Gaia.tree3;
const oTree4 = g_Gaia.tree4;
const oTree5 = g_Gaia.tree5;
const oFruitBush = g_Gaia.fruitBush;
const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
const oStoneLarge = g_Gaia.stoneLarge;
const oStoneSmall = g_Gaia.stoneSmall;
const oMetalLarge = g_Gaia.metalLarge;
const aGrass = g_Decoratives.grass;
const aGrassShort = g_Decoratives.grassShort;
const aRockLarge = g_Decoratives.rockLarge;
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const heightLand = 3;
var g_Map = new RandomMap(heightLand, tMainTerrain);
const numPlayers = getNumPlayers();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
let playerDistanceFraction;
switch(g_Map.getSize()) {
case 128: // tiny
playerDistanceFraction = 0.32;
break;
case 192: // small
playerDistanceFraction = 0.31;
break;
case 256: // medium
playerDistanceFraction = 0.28;
break;
case 320: // normal
playerDistanceFraction = 0.27;
break;
default:
playerDistanceFraction = 0.26;
}
const playerPlacements = playerPlacementCircle(fractionToTiles(playerDistanceFraction + numPlayers * 0.007));
const [playerIDs, playerPositions] = playerPlacements;
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oFruitBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oTree1,
"count": 5
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(20);
createBumps(avoidClasses(clPlayer, 20));
Engine.SetProgress(25);
placeBalancedMinerals(playerPositions);
Engine.SetProgress(30);
placeBalancedFood(playerPlacements,
avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10)
);
Engine.SetProgress(35);
if (currentBiome() != "generic/savanna") {
createBalancedPlayerForests(
playerPositions,
avoidClasses(clForest, 18, clHill, 1, clMetal, 4, clRock, 4, clFood, 4),
clForest);
}
Engine.SetProgress(40);
if (randBool())
createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 35, clHill, 15, clForest, 6, clMetal, 6, clRock, 6, clFood, 6), clHill, scaleByMapSize(2, 11));
else
createMountains(tCliff, avoidClasses(clPlayer, 35, clHill, 15, clForest, 6, clMetal, 6, clRock, 6, clFood, 6), clHill, scaleByMapSize(2, 11));
Engine.SetProgress(45);
var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1));
createForests(
[tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2],
avoidClasses(clPlayer, 30, clForest, 18, clHill, 1, clMetal, 4, clRock, 4, clFood, 4),
clForest,
forestTrees);
Engine.SetProgress(50);
g_Map.log("Creating dirt patches");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1, 1],
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12),
scaleByMapSize(15, 45),
clDirt);
g_Map.log("Creating grass patches");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(55);
g_Map.log("Creating stone mines");
createMines(
[
[new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)]
],
avoidClasses(clForest, 1, clPlayer, 60, clRock, 22, clHill, 1),
clRock,
scaleByMapSize(4, 16) - 1
);
Engine.SetProgress(60);
g_Map.log("Creating metal mines");
createMines(
[
[new SimpleObject(oMetalLarge, 1, 1, 0, 4)]
],
avoidClasses(clForest, 1, clPlayer, 60, clMetal, 22, clRock, 5, clHill, 1),
clMetal,
scaleByMapSize(4, 16) - 1
);
Engine.SetProgress(65);
var planetm = 1;
if (currentBiome() == "generic/tropic")
planetm = 8;
createDecoration(
[
[new SimpleObject(aRockMedium, 1, 3, 0, 1)],
[new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
[new SimpleObject(aGrassShort, 1, 2, 0, 1)],
[new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3,6, 1.2, 2.5)],
[new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0));
Engine.SetProgress(70);
createBadFood(avoidClasses(clForest, 0, clHill, 1, clMetal, 4, clRock, 4, clFood, 20));
Engine.SetProgress(75);
createFood(
[
[new SimpleObject(oFruitBush, 5, 7, 0, 4)]
],
[
2 * numPlayers
],
avoidClasses(clForest, 0, clPlayer, 45, clHill, 1, clMetal, 4, clRock, 4, clFood, 10),
clFood);
Engine.SetProgress(85);
createStragglerTrees(
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(
clForest, 8, clHill, 1, clPlayer,
(currentBiome() == "generic/savanna") ? 12 : 38,
clMetal, 6, clRock, 6, clFood, 1, clBaseResource, 2
),
clForest,
stragglerTrees);
createBalancedPlayerStragglerTrees(
playerPositions,
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(clForest, 8, clHill, 1, clMetal, 6, clRock, 6, clFood, 1, clBaseResource, 2),
25,
clForest
)
Engine.SetProgress(90);
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2));
g_Map.ExportMap();

View File

@ -0,0 +1,11 @@
{
"settings" : {
"Name" : "Balanced Mainland",
"Script" : "badmainland.js",
"Description" : "A typical map without any water. Resources are distributed evenly between players.",
"Preview" : "mainland.png",
"SupportedBiomes": "generic/",
"Keywords": ["badmod"],
"CircularMap" : true
}
}

View File

@ -0,0 +1,248 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("rmbiome");
Engine.LoadLibrary("balancedHelpers");
setSelectedBiome();
const tMainTerrain = g_Terrains.mainTerrain;
const tForestFloor1 = g_Terrains.forestFloor1;
const tForestFloor2 = g_Terrains.forestFloor2;
const tCliff = g_Terrains.cliff;
const tTier1Terrain = g_Terrains.tier1Terrain;
const tTier2Terrain = g_Terrains.tier2Terrain;
const tTier3Terrain = g_Terrains.tier3Terrain;
const tHill = g_Terrains.hill;
const tRoad = g_Terrains.road;
const tRoadWild = g_Terrains.roadWild;
const tTier4Terrain = g_Terrains.tier4Terrain;
const oTree1 = g_Gaia.tree1;
const oTree2 = g_Gaia.tree2;
const oTree3 = g_Gaia.tree3;
const oTree4 = g_Gaia.tree4;
const oTree5 = g_Gaia.tree5;
const oFruitBush = g_Gaia.fruitBush;
const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
const oStoneLarge = g_Gaia.stoneLarge;
const oStoneSmall = g_Gaia.stoneSmall;
const oMetalLarge = g_Gaia.metalLarge;
const aGrass = g_Decoratives.grass;
const aGrassShort = g_Decoratives.grassShort;
const aRockLarge = g_Decoratives.rockLarge;
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const heightLand = 3;
var g_Map = new RandomMap(heightLand, tMainTerrain);
const numPlayers = getNumPlayers();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
let playerDistanceFraction;
switch(g_Map.getSize()) {
case 128: // tiny
playerDistanceFraction = 0.32;
break;
case 192: // small
playerDistanceFraction = 0.31;
break;
case 256: // medium
playerDistanceFraction = 0.28;
break;
case 320: // normal
playerDistanceFraction = 0.27;
break;
default:
playerDistanceFraction = 0.26;
}
const playerPlacements = playerPlacementCircle(fractionToTiles(playerDistanceFraction + numPlayers * 0.007));
let [playersOrder, playerPositions, playerAngles] = playerPlacements;
let playerIDs = [];
for (let i = 0; i < numPlayers; ++i)
playerIDs.push(i+1);
playerPlacements[0] = playerIDs;
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oFruitBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oTree1,
"count": 5
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(20);
createBumps(avoidClasses(clPlayer, 20));
Engine.SetProgress(25);
if (randBool())
createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 35, clHill, 15), clHill, scaleByMapSize(2, 11));
else
createMountains(tCliff, avoidClasses(clPlayer, 35, clHill, 15), clHill, scaleByMapSize(2, 11));
placeBalancedMinerals(playerPositions);
placeBalancedFood(playerPlacements,
avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10)
);
Engine.SetProgress(40);
if (currentBiome() != "generic/savanna") {
createBalancedPlayerForests(
playerPositions,
avoidClasses(clForest, 18, clHill, 1, clMetal, 4, clRock, 4, clFood, 4),
clForest);
}
var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1));
createForests(
[tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2],
avoidClasses(clPlayer, 30, clForest, 18, clHill, 1, clMetal, 4, clRock, 4, clFood, 4),
clForest,
forestTrees);
Engine.SetProgress(50);
g_Map.log("Creating dirt patches");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1, 1],
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12),
scaleByMapSize(15, 45),
clDirt);
g_Map.log("Creating grass patches");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(55);
g_Map.log("Creating stone mines");
createMines(
[
[new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)]
],
avoidClasses(clForest, 1, clPlayer, 60, clRock, 22, clHill, 1),
clRock,
scaleByMapSize(4, 16) - 1
);
Engine.SetProgress(60);
g_Map.log("Creating metal mines");
createMines(
[
[new SimpleObject(oMetalLarge, 1, 1, 0, 4)]
],
avoidClasses(clForest, 1, clPlayer, 60, clMetal, 22, clRock, 5, clHill, 1),
clMetal,
scaleByMapSize(4, 16) - 1
);
Engine.SetProgress(65);
var planetm = 1;
if (currentBiome() == "generic/tropic")
planetm = 8;
createDecoration(
[
[new SimpleObject(aRockMedium, 1, 3, 0, 1)],
[new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
[new SimpleObject(aGrassShort, 1, 2, 0, 1)],
[new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3,6, 1.2, 2.5)],
[new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0));
Engine.SetProgress(70);
createBadFood(avoidClasses(clForest, 0, clHill, 1, clMetal, 4, clRock, 4, clFood, 20));
Engine.SetProgress(75);
createFood(
[
[new SimpleObject(oFruitBush, 5, 7, 0, 4)]
],
[
2 * numPlayers
],
avoidClasses(clForest, 0, clPlayer, 45, clHill, 1, clMetal, 4, clRock, 4, clFood, 10),
clFood);
Engine.SetProgress(85);
createStragglerTrees(
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(
clForest, 8, clHill, 1, clPlayer,
(currentBiome() == "generic/savanna") ? 12 : 38,
clMetal, 6, clRock, 6, clFood, 1
),
clForest,
stragglerTrees);
createBalancedPlayerStragglerTrees(
playerPositions,
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(clForest, 8, clHill, 1, clMetal, 6, clRock, 6, clFood, 1, clBaseResource, 2),
25,
clForest
)
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2));
g_Map.ExportMap();

View File

@ -0,0 +1,11 @@
{
"settings" : {
"Name" : "Balanced Mainland (fixed)",
"Script" : "badmainland_fixed.js",
"Description" : "A typical map without any water. Resources are distributed evenly between players. Positions defined by players",
"Preview" : "mainland.png",
"SupportedBiomes": "generic/",
"Keywords": ["badmod"],
"CircularMap" : true
}
}

View File

@ -0,0 +1,432 @@
Engine.LoadLibrary("rmbiome");
const debugFood = true;
function dWarn(message) {
if (debugFood) {
warn(message);
}
}
const temperateInitialFood = () => randBool(0.05) ? randIntInclusive(23, 30) : randIntInclusive(0, 22);
const balancedFoodConfig = {
'generic/alpine': {
placer: placeFoodTemperate,
initialFood: temperateInitialFood,
},
'generic/aegean': {
placer: placeFoodTemperate,
initialFood: temperateInitialFood,
},
'generic/temperate': {
placer: placeFoodTemperate,
initialFood: temperateInitialFood,
},
'generic/autumn': {
placer: placeFoodAutumn,
initialFood: temperateInitialFood,
},
'generic/india': {
placer: placeFoodTropic,
initialFood: () => randIntInclusive(0, 22), // disallow high-food due to poor fauna
},
'generic/sahara': {
placer: placeFoodDesert,
initialFood: () => randIntInclusive(4, 30),
},
'generic/nubia': {
placer: placeFoodDesert,
initialFood: () => randIntInclusive(4, 30),
},
'generic/arctic': {
placer: placeFoodSnowy,
initialFood: () => randIntInclusive(3, 30),
evenInitialFood: true,
},
'generic/steppe': {
placer: placeFoodSnowy,
initialFood: () => randIntInclusive(3, 30),
evenInitialFood: true,
},
'generic/savanna': {
placer: function() {
if (oMainHuntableAnimal == 'gaia/fauna_elephant_african_bush') {
placeFoodEles.apply(null, arguments);
} else if (oMainHuntableAnimal == 'gaia/fauna_giraffe') {
placeFoodGiraffes.apply(null, arguments);
} else {
placeFoodSavanna.apply(null, arguments);
}
},
initialFood: function() {
if (oMainHuntableAnimal == 'gaia/fauna_elephant_african_bush') {
return randIntInclusive(17, 50);
} else if (oMainHuntableAnimal == 'gaia/fauna_giraffe') {
return 7 * randIntInclusive(2, 6);
} else {
return randIntInclusive(10, 30);
}
},
},
};
function placeInitialFoodAmount(type, min, max, foodAmount, playerPosition, constraints, minTileBound = 23, maxTileBound = 29) {
if (type != oFruitBush) {
minTileBound += 11;
maxTileBound += 12;
constraints = new AndConstraint([constraints, avoidClasses(clPlayer, minTileBound - 6)]);
}
return placeFoodAmount(type, min, limitQtyForAmount(foodAmount, type, max), playerPosition, constraints, minTileBound, maxTileBound) * getFoodValue(type);
}
function placeFoodAmount(type, min, max, position, constraints, minTileBound = 17, maxTileBound = 25) {
const amountPlaced = randIntInclusive(min, max);
const group = new SimpleGroup(
[new SimpleObject(type, amountPlaced, amountPlaced, 0, 4)],
true,
clFood
);
createObjectGroupsByAreas(group, 0,
constraints,
1, 400, [getAnnulusArea(minTileBound, maxTileBound, position)]
);
return amountPlaced;
}
function placeStragglerFauna(type, foodAmount, playerId, playerPosition, constraints) {
const foodQty = Math.floor(foodAmount / getFoodValue(type));
const [minTile, maxTile] = getCivCode(playerId) == 'iber' ? [21, 23] : [8, 12];
const placedAmount = placeInitialFoodAmount(type, foodQty, foodQty, foodAmount, playerPosition, constraints, minTile, maxTile);
dWarn("Player " + playerId + " - placed " + type + ": " + placedAmount);
return placedAmount;
}
function placeInitialBerries(foodAmount, playerId, playerPosition, constraints) {
if (getCivCode(playerId) == 'iber') {
return placeInitialFoodAmount(oFruitBush, 5, 7, foodAmount, playerPosition, constraints, 27, 30);
} else {
return placeInitialFoodAmount(oFruitBush, 5, 7, foodAmount, playerPosition, constraints);
}
}
function placeBalancedFood(playerPlacements, constraints, multiplier = 1) {
const biome = currentBiome() || 'generic/temperate';
const biomeConfig = balancedFoodConfig[biome];
dWarn('Placing food for biome: ' + biome);
const [playerIDs, playerPositions] = playerPlacements;
const foodPlacer = biomeConfig.placer;
const foodAmount = getFoodAmount(multiplier, biomeConfig);
for (let i = 0; i < playerPositions.length; ++i)
foodPlacer(foodAmount, playerIDs[i], playerPositions[i], constraints);
}
function getFoodAmount(multiplier = 1, biomeConfig) {
let initialFoodAmount = Math.floor(multiplier * biomeConfig.initialFood());
if (biomeConfig['evenInitialFood']) {
if (initialFoodAmount % 2 == 1) initialFoodAmount++;
}
return initialFoodAmount * 100;
}
function placeFoodTemperate(initialFoodAmount, playerId, playerPosition, constraints, maxBerries = 2, mainHunt = oMainHuntableAnimal) {
// Goats now are 70 food which messes everything up
if (currentBiome() == 'generic/alpine') {
mainHunt = 'gaia/fauna_sheep';
}
let remainingFood = initialFoodAmount;
let remainingBerries = maxBerries;
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood <= 400) {
remainingFood -= placeStragglerFauna(mainHunt, remainingFood, playerId, playerPosition, constraints);
} else if (remainingFood <= 1000) {
const placedAmount = placeInitialFoodAmount(mainHunt, 5, 7, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + mainHunt + ": " + placedAmount);
}
else {
if (remainingBerries > 0 && randBool()) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
} else {
const placedAmount = placeInitialFoodAmount(oSecondaryHuntableAnimal, 5, 7, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oSecondaryHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function placeFoodAutumn(initialFoodAmount, playerId, playerPosition, constraints, maxBerries = 2) {
let remainingFood = initialFoodAmount;
let remainingBerries = maxBerries;
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood <= 400) {
remainingFood -= placeStragglerFauna(oSecondaryHuntableAnimal, remainingFood, playerId, playerPosition, constraints);
} else if (remainingFood <= 1000) {
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, 5, 7, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
else {
if (remainingBerries > 0 && randBool()) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
}
else {
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, 5, 7, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function placeFoodDesert(initialFoodAmount, playerId, playerPosition, constraints, maxBerries = 2) {
let remainingFood = initialFoodAmount;
let remainingBerries = maxBerries;
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood <= 400) {
remainingFood -= placeStragglerFauna(oSecondaryHuntableAnimal, remainingFood, playerId, playerPosition, constraints);
}
else if (remainingFood <= 1000) {
const placedAmount = placeInitialFoodAmount(oSecondaryHuntableAnimal, 5, 7, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oSecondaryHuntableAnimal + ": " + placedAmount);
}
else {
if (remainingBerries > 0 && randBool()) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
}
else {
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, 5, 7, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function placeFoodTropic(initialFoodAmount, playerId, playerPosition, constraints, maxBerries = 2) {
let remainingFood = initialFoodAmount;
let remainingBerries = maxBerries;
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood <= 400) {
remainingFood -= placeStragglerFauna(oMainHuntableAnimal, remainingFood, playerId, playerPosition, constraints);
} else if (remainingFood <= 950) {
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, 10, 12, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
}
else {
if (remainingBerries > 0 && randBool(0.7)) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
} else {
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, 10, 12, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function placeFoodSnowy(initialFoodAmount, playerId, playerPosition, constraints, maxBerries = 2) {
let remainingFood = initialFoodAmount;
let remainingBerries = maxBerries;
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood <= 400) {
remainingFood -= placeStragglerFauna(oMainHuntableAnimal, remainingFood, playerId, playerPosition, constraints);
} else if (remainingFood <= 900) {
const placedAmount = placeInitialFoodAmount(oSecondaryHuntableAnimal, 2, 3, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oSecondaryHuntableAnimal + ": " + placedAmount);
}
else {
if (remainingBerries > 0 && randBool()) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
} else {
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, 5, 7, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function placeFoodSavanna(initialFoodAmount, playerId, playerPosition, constraints) {
if (oMainHuntableAnimal == 'gaia/fauna_elephant_african_bush') {
placeFoodEles(initialFoodAmount, playerId, playerPosition, constraints);
return;
}
else if (oMainHuntableAnimal == 'gaia/fauna_giraffe') {
placeFoodGiraffes(initialFoodAmount, playerId, playerPosition);
return;
}
let remainingFood = initialFoodAmount;
let remainingBerries = 2;
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood<=getFoodValue(oSecondaryHuntableAnimal)*2 && remainingFood % getFoodValue(oSecondaryHuntableAnimal) == 0) {
dWarn("place_stragglers_fauna");
remainingFood -= placeStragglerFauna(oSecondaryHuntableAnimal, remainingFood, playerId, playerPosition, constraints);
}
else {
if (remainingBerries > 0 && randBool()) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
}
else {
const foodQty = randIntInclusive(3, 4) * 2;
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, foodQty, foodQty, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function placeFoodEles(initialFoodAmount, playerId, playerPosition, constraints) {
let remainingFood = initialFoodAmount;
let remainingBerries = 2;
dWarn("PLACE FOOD ELES");
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood<=getFoodValue(oSecondaryHuntableAnimal)*2 && remainingFood % getFoodValue(oSecondaryHuntableAnimal) == 0) {
dWarn("place_stragglers_fauna");
remainingFood -= placeStragglerFauna(oSecondaryHuntableAnimal, remainingFood, playerId, playerPosition, constraints);
}
else {
if (remainingBerries > 0 && randBool()) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
}
else {
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, 1, 2, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function placeFoodGiraffes(initialFoodAmount, playerId, playerPosition, constraints) {
let remainingFood = initialFoodAmount;
let remainingBerries = 2;
dWarn("PLACE FOOD GIRAFFES")
dWarn("Assigning " + remainingFood + " food for player " + playerId);
while (remainingFood > 0) {
if (remainingFood<=getFoodValue(oSecondaryHuntableAnimal)*2 && remainingFood % getFoodValue(oSecondaryHuntableAnimal) == 0) {
dWarn("place_stragglers_fauna");
remainingFood -= placeStragglerFauna(oSecondaryHuntableAnimal, remainingFood, playerId, playerPosition, constraints);
}
else {
if (remainingBerries > 0 && randBool()) {
const placedAmount = placeInitialBerries(remainingFood, playerId, playerPosition, constraints);
remainingFood -= placedAmount;
remainingBerries -= 1;
dWarn("Player " + playerId + " - placed " + oFruitBush + ": " + placedAmount);
}
else {
const foodQty = 4; // must be fixed at the moment
const placedAmount = placeInitialFoodAmount(oMainHuntableAnimal, foodQty, foodQty, remainingFood, playerPosition, constraints);
remainingFood -= placedAmount;
dWarn("Player " + playerId + " - placed " + oMainHuntableAnimal + ": " + placedAmount);
}
}
dWarn("Remaining " + remainingFood);
}
if (remainingFood < 0)
warn('Player ' + playerId + ' ended up with additional ' + Math.abs(remainingFood) + ' food');
}
function createBadFood(constraints, multiplier = 2) {
// Separate for eles generation farther
let huntGenDistance = oMainHuntableAnimal == 'gaia/fauna_elephant_african_bush' ? 80 : 50;
createFood(
[ [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)] ],
[ multiplier * numPlayers ],
new AndConstraint([avoidClasses(clPlayer, huntGenDistance), constraints]),
clFood);
createFood(
[ [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] ],
[ multiplier * numPlayers ],
new AndConstraint([avoidClasses(clPlayer, huntGenDistance), constraints]),
clFood);
}
function limitQtyForAmount(foodAmount, type, max) {
return Math.min(max, Math.floor(foodAmount / getFoodValue(type)));
}

View File

@ -0,0 +1,34 @@
const foodValues = {
'gaia/fauna_wildebeest': 150, // m random savanna
'gaia/fauna_zebra': 150, // m random savanna
'gaia/fauna_giraffe': 350, // m random savanna
'gaia/fauna_elephant_african_bush': 800, // m random savanna
'gaia/fauna_gazelle': 100, // s savanna, s desert
'gaia/fauna_camel': 200, // m desert
'gaia/fauna_peacock': 50, // m tropical
'gaia/fauna_goat': 70, // m alpine
'gaia/fauna_deer': 100, // m alpine, m autumn, m mediterranean, m temperate
'gaia/fauna_sheep': 100, // s alpine, s mediterranean, s temperate
'gaia/fauna_rabbit': 50, // s autumn
'gaia/fauna_horse': 200, // s steppe
'gaia/fauna_muskox': 200, // m snowy
'gaia/fauna_walrus': 300, // s snowy
'gaia/fauna_tiger': 0, // s tropic
'gaia/fruit/berry_': 200, // all regular biomes
};
function getFoodValue(template) {
let foodValue = foodValues[template];
dWarn('get: ' + template);
if (foodValue)
return foodValue;
for (let foodtemp in foodValues)
if (template.startsWith(foodtemp))
return foodValues[foodtemp];
dWarn('miss: ' + template);
return null;
}

View File

@ -0,0 +1,15 @@
let annulusAreas = {};
// Memoize areas
function getAnnulusArea(minTileBound, maxTileBound, position) {
const key = [minTileBound, maxTileBound, position.x, position.y];
if (key in annulusAreas) {
return annulusAreas[key];
} else {
const area = new Area(new AnnulusPlacer(minTileBound, maxTileBound, position).place());
annulusAreas[key] = area;
return area;
}
}

View File

@ -0,0 +1,33 @@
function placeBalancedMinerals(playerPositions, constraints = new NullConstraint()) {
for (let i = 0; i < playerPositions.length; ++i)
{
const playerPosition = playerPositions[i];
let placer = new AnnulusPlacer(40, 44, playerPosition).place(
new AndConstraint([avoidClasses(clForest, 10, clHill, 2, clFood, 4, clPlayer, 34), constraints])
);
let surroundingArea = new Area(placer);
let stone = new SimpleGroup(
[new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)],
true,
clRock
);
let metal = new SimpleGroup(
[new SimpleObject(oMetalLarge, 1, 1, 0, 4)],
true,
clRock
);
createObjectGroupsByAreas(stone, 0,
new NullConstraint(),
1, 400, [surroundingArea]
);
createObjectGroupsByAreas(metal, 0,
avoidClasses(clRock, 6),
1, 400, [surroundingArea]
);
}
}

View File

@ -0,0 +1,63 @@
Engine.LoadLibrary("rmgen-common");
function getTeams() {
const playerIDs = [];
for (let i = 0; i < getNumPlayers(); ++i)
playerIDs.push(i + 1);
return playerIDs.reduce((obj, playerID) => {
const teamID = g_MapSettings.PlayerData[playerID].Team;
if (!obj.hasOwnProperty(teamID))
obj[teamID] = [];
obj[teamID].push(playerID);
return obj;
}, {});
}
function placeOpposingTeams(radius, startingAngle = undefined, center = undefined) {
let startAngle = startingAngle !== undefined ? startingAngle : randomAngle();
center = center || g_Map.getCenter();
const teams = getTeams();
const teamIDs = shuffleArray(Object.keys(teams));
const teamCount = teamIDs.length;
if (teamCount === 1)
warn('This map is optimized for at least 2 teams');
const [teamPositions, teamAngles] = distributePointsOnCircle(teamIDs.length, startAngle, radius, center)
let playerPositions = [];
let ids = [];
for (let i = 0; i < teamCount; i++) {
const team = teams[teamIDs[i]];
ids = ids.concat(team);
playerPositions = playerPositions.concat(placeTeam(
team,
teamCount === 1 ? center : teamPositions[i],
teamAngles[i]
));
}
return [ids, playerPositions];
}
// Places a team in a circle formation at a certain position
function placeTeam(team, pos, startAngle = 0) {
const teamSize = team.length;
if (teamSize === 1)
return [pos];
// Make uneven sizes point to center, and even to face center
const orientationAngle = Math.min(teamSize - 2, 1) * Math.PI / Math.pow(2, teamSize - 2);
return distributePointsOnCircle(
teamSize,
orientationAngle + startAngle + Math.PI/2,
22 + teamSize * 6,
pos
)[0];
}

View File

@ -0,0 +1,91 @@
function pickRandomCollection(collection, amount) {
let newCollection = [];
let dup = collection.slice();
for (let i = 0; i < amount; ++i) {
const index = Math.floor(dup.length * Math.random());
const item = dup.splice(index, 1)[0];
newCollection.push(item);
}
return newCollection;
}
function createBalancedPlayerStragglerTrees(playerPositions, templateNames, constraint, treeCount, tileClass) {
templateNames = templateNames.filter((templateName) => !templateName.startsWith('gaia/fruit/'));
for (let playerPosition of playerPositions) {
const playerArea = new Area(new DiskPlacer(38, playerPosition).place(avoidClasses(clPlayer, 12)));
for (let templateName of templateNames) {
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(templateName, 1, 1, 0, 3)], true, tileClass),
0,
constraint,
Math.floor(treeCount / templateNames.length), 400,
[playerArea]
);
}
}
}
function createBalancedPlayerForests(playerPositions, constraint, tileClass, forestAmount, treeCount)
{
treeCount = treeCount !== undefined ? treeCount : randIntInclusive(25, 35);
forestAmount = forestAmount !== undefined ? forestAmount : randIntInclusive(3, 4);
for (let i = 0; i < playerPositions.length; ++i)
{
const playerPosition = playerPositions[i];
let forestArea = new Area(new AnnulusPlacer(28, 40, playerPosition).place(new NullConstraint()));
createForestsInArea(forestArea, constraint, tileClass, treeCount, 3, Math.floor(scaleByMapSize(3, 4)), 1, forestAmount, 0);
}
}
/**
* Places uniformly sized forests at random locations.
* Generates two variants of forests from the given terrain textures and tree templates.
* The forest border has less trees than the inside.
*/
function createForestsInArea(area, constraint, tileClass, treeCount,
minRadius = 1,
maxRadius = Math.floor(scaleByMapSize(3, 5)),
forestVariantNumber = 2,
numberOfForests = Math.floor(treeCount / (scaleByMapSize(3, 6) * getNumPlayers() * forestVariantNumber)),
failurePercentage = 0.5,
retryFactor = 400)
{
if (!treeCount)
return;
const terrainSet = [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2];
// Construct different forest types from the terrain textures and template names.
const [mainTerrain, terrainForestFloor1, terrainForestFloor2, terrainForestTree1, terrainForestTree2] = terrainSet;
// The painter will pick a random Terrain for each part of the forest.
let forestVariants = pickRandomCollection([
{
"borderTerrains": [terrainForestFloor2, mainTerrain, terrainForestTree1],
"interiorTerrains": [terrainForestFloor2, terrainForestTree1]
},
{
"borderTerrains": [terrainForestFloor1, mainTerrain, terrainForestTree2],
"interiorTerrains": [terrainForestFloor1, terrainForestTree2]
}
], forestVariantNumber);
g_Map.log("Creating forests");
for (let forestVariant of forestVariants) {
createAreasInAreas(
new ChainPlacer(minRadius, maxRadius, treeCount / numberOfForests, failurePercentage),
[
new LayeredPainter([forestVariant.borderTerrains, forestVariant.interiorTerrains], [2]),
new TileClassPainter(tileClass)
],
constraint,
numberOfForests,
retryFactor,
[area]);
}
}

View File

@ -0,0 +1,596 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
const tPrimary = "alpine_grass_a";
const tGrass = ["temp_forestfloor_aut", "temp_forestfloor_aut", "temp_forestfloor_aut"];
const tGrassPForest = "temp_forestfloor_aut";
const tGrassDForest = "temp_forestfloor_aut";
const tGrassA = "temp_forestfloor_aut";
const tGrassB = "temp_forestfloor_aut";
const tGrassC = "temp_mud_a";
const tRoad = "temp_road";
const tRoadCenter = "temp_road_broken";
const tRoadWild = "temp_road_overgrown_aut";
const tGrassPatchBlend = "temp_forestfloor_aut";
const tGrassPatchA = ["alpine_grass_c", "alpine_grass_c"];
const tGrassPatchB = ["alpine_grass_d", "alpine_grass_d"];
const tGrassPatchTypes = [tGrassPatchA, tGrassPatchB];
const tShore = "temp_forestfloor_aut";
const tWater = "temp_mud_a";
const oBeech = "gaia/tree/euro_beech_aut";
const oOak = "gaia/tree/oak_aut";
const oOakBig = "gaia/tree/oak_aut_new"
const oBerryBush = "gaia/fruit/berry_01";
const oDeer = "gaia/fauna_deer";
const oRabbit = "gaia/fauna_rabbit";
const oSheep = "gaia/fauna_sheep";
const oStoneLarge = "gaia/rock/temperate_large_02";
const oStoneSmall = "gaia/rock/temperate_small";
const oMetalLarge = "gaia/ore/temperate_large";
const aDryGrass = "actor|props/flora/grass_field_dry_tall.xml";
const aGrassFlower = "actor|props/flora/grass_field_flowering_tall.xml";
const aGrassSoft = "actor|props/flora/grass_soft_large";
const aGrassSoftTall = "actor|props/flora/grass_soft_large_tall";
const aRockLarge = "actor|geology/stone_granite_med.xml";
const aRockMedium = "actor|geology/stone_granite_med.xml";
const aBushMedium = "actor|props/flora/bush_desert_dry_a.xml";
const aBushSmall = "actor|props/flora/bush_desert_dry_a.xml";
const pForestB = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest];
const pForestO = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest];
const pForestN = [tGrassPForest + TERRAIN_SEPARATOR + oOakBig, tGrassPForest];
const pForestR = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest, tGrassDForest + TERRAIN_SEPARATOR + oOak, tGrassDForest, tGrassDForest, tGrassDForest];
const heightSeaGround = -4;
const heightShallows = -2;
const heightLand = 3;
const heightOffsetBump = 2;
const surroundingPlayerAreaMin = 20;
const surroundingPlayerAreaMax = 50;
var g_Map = new RandomMap(heightLand, tPrimary);
const numPlayers = getNumPlayers();
const mapSize = g_Map.getSize();
const mapCenter = g_Map.getCenter();
const mapBounds = g_Map.getBounds();
const neighbouringPlayerTiles = 50;
var clPlayers = [];
var clPlayer = g_Map.createTileClass();
var clHill = g_Map.createTileClass();
var clForest = g_Map.createTileClass();
var clDirt = g_Map.createTileClass();
var clDryGrass = g_Map.createTileClass();
var clRock = g_Map.createTileClass();
var clMetal = g_Map.createTileClass();
var clFood = g_Map.createTileClass();
var clBaseResource = g_Map.createTileClass();
var clRoad = g_Map.createTileClass();
var clBorder = g_Map.createTileClass();
var surroundingPlayersAreas = [];
var startAngle = randomAngle();
for (let i = 0; i < numPlayers; ++i) {
clPlayers[i] = g_Map.createTileClass();
}
var playerPositions = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.5));
placePlayerBasesCustom({
"PlayerPlacement": playerPositions,
// PlayerTileClass marked below
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad//,
//"painters": [
// new TileClassPainter(clPlayer)
//]
},
"StartingAnimal": {
},
"Berries": {
"template": oBerryBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oOak,
"count": 3
},
});
Engine.SetProgress(20);
for (let i = 0; i < numPlayers; ++i) {
let playerClass = clPlayers[i];
surroundingPlayersAreas[i] = createArea(new DiskPlacer(surroundingPlayerAreaMax, playerPositions[1][i]), null, avoidClasses(playerClass, surroundingPlayerAreaMin));
}
Engine.SetProgress(30);
var roadPositions = [
new Vector2D(mapBounds.left + 1, mapCenter.y),
new Vector2D(mapBounds.right - 1, mapCenter.y)
].map(v => v.rotateAround(startAngle, mapCenter));
g_Map.log("Creating the central road");
createArea(
new PathPlacer(roadPositions[0], roadPositions[1], scaleByMapSize(2, 4), 0.2, 3 * scaleByMapSize(1, 4), 0.1, 0.01),
[new TerrainPainter(tRoadCenter), new TileClassPainter(clRoad)],
avoidClasses(clPlayer, 4));
Engine.SetProgress(35);
g_Map.log("Creating bumps");
createAreas(
new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity),
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2),
avoidClasses(clRoad, 2, clPlayer, 15),
scaleByMapSize(100, 200)
);
Engine.SetProgress(55);
g_Map.log("Creating primary grass patches");
for (let size of [scaleByMapSize(8, 20), scaleByMapSize(13, 35), scaleByMapSize(25, 70)])
createAreas(
new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5),
[new LayeredPainter([tGrassPatchA, tGrassPatchA], [1]), new TileClassPainter(clDryGrass)],
avoidClasses(clRoad, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6),
scaleByMapSize(15, 45)
);
Engine.SetProgress(58);
g_Map.log("Creating secondary grass patches");
//for (let size of [scaleByMapSize(3, 8), scaleByMapSize(5, 15), scaleByMapSize(8, 20)])
for (let size of [scaleByMapSize(8, 20), scaleByMapSize(13, 35), scaleByMapSize(25, 60)])
createAreas(
new ChainPlacer(1, Math.floor(scaleByMapSize(3, 4)), size, 0.5),
[new LayeredPainter([tGrassPatchB, tGrassPatchB], [1]), new TileClassPainter(clDryGrass)],
avoidClasses(clRoad, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6),
scaleByMapSize(10, 30)
);
Engine.SetProgress(61);
g_Map.log("Creating the bordering trees");
var [borderForests, borderStragglers] = getTreeCounts(500, 2500, 0.7);
/*createForestsCustom(
[tGrass, tGrassDForest, tGrassPForest, pForestN, pForestN],
new AndConstraint([avoidClasses(clPlayer, 15, clBorder, 2, clHill, 1, clRoad, 5), new BorderTileClassConstraint(clRoad, 0, 20)]),
clBorder,
borderForests);
Engine.SetProgress(60);*/
g_Map.log("Creating player owned forest");
for (let i = 0; i < numPlayers; ++i)
createPlayerForests(
[tGrass, tGrassDForest, tGrassPForest, pForestB, pForestO],
new AndConstraint([avoidClasses(clPlayer, 12, clRoad, 30, clForest, 16, clHill, 1), borderClasses(clPlayer, 0, 30)]),
clForest,
surroundingPlayersAreas[i]);
Engine.SetProgress(65);
g_Map.log("Creating the regular trees");
var [forestTrees, stragglerTrees] = getTreeCounts(300, 1600, 0.7);
createThickerForests(
[tGrass, tGrassDForest, tGrassPForest, pForestB, pForestO],
avoidClasses(clPlayer, 15, clRoad, 30, clForest, 16, clHill, 1),
clForest,
forestTrees);
Engine.SetProgress(70);
/*g_Map.log("Creating dirt patches");
for (let size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)])
createAreas(
new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5),
[
new LayeredPainter([[tGrass,tGrassA], tGrassB, [tGrassB,tGrassC]], [1, 1]),
new TileClassPainter(clDirt)
],
avoidClasses(clRoad, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6),
scaleByMapSize(15, 45)
);*/
g_Map.log("Creating additionnal mines for players (balance)");
var minesAmountDistribution = [];
if (numPlayers <= 2)
minesAmountDistribution = [0.2, 0.5, 0.2, 0.1];
else
minesAmountDistribution = [0.1, 0.6, 0.3];
var incrementedProbability = 0;
var minesAmount = 0;
var random = Math.random();
for (let i = 0; i < minesAmountDistribution.length; ++i) {
incrementedProbability += minesAmountDistribution[i];
if (random < incrementedProbability) {
minesAmount = i;
break;
}
}
// For now, equal probability for both mine types.
// In 1v1, both players will have exactly the same mine types nearby. In games with more player the type can vary.
var objects = [new SimpleObject(oStoneLarge, 1, 1, 0,4), new SimpleObject(oMetalLarge, 1, 1, 0,4)];
var groups = [];
for (let i = 0; i < minesAmount; i++)
groups[i] = new RandomGroup(objects, true, clRock);
for (let i = 0; i < numPlayers; ++i) {
for (let j = 0; j < minesAmount; j++) {
if (numPlayers <= 2) {
createObjectGroupsByAreas(
groups[j],
0,
[avoidClasses(clRoad, 20, clForest, 3, clPlayer, 15, clRock, 10, clHill, 1)],
1,
50,
[surroundingPlayersAreas[i]]);
}
else {
createObjectGroupsByAreas(
new SimpleGroup([pickRandom(objects)], true, clRock),
0,
[avoidClasses(clRoad, 20, clForest, 3, clPlayer, 15, clRock, 10, clHill, 1)],
1,
50,
[surroundingPlayersAreas[i]]);
}
}
}
Engine.SetProgress(80);
g_Map.log("Creating stone mines");
var group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock);
createObjectGroupsDeprecated(group, 0,
[avoidClasses(clRoad, 20, clForest, 1, clPlayer, surroundingPlayerAreaMax + 5, clRock, 10, clHill, 1)],
scaleByMapSize(5,18), 100
);
g_Map.log("Creating small stone quarries");
group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock);
createObjectGroupsDeprecated(group, 0,
[avoidClasses(clRoad, 20, clForest, 1, clPlayer, surroundingPlayerAreaMax + 5, clRock, 10, clHill, 1)],
scaleByMapSize(5,18), 100
);
g_Map.log("Creating metal mines");
group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal);
createObjectGroupsDeprecated(group, 0,
[avoidClasses(clRoad, 20, clForest, 1, clPlayer, surroundingPlayerAreaMax + 5, clMetal, 10, clRock, 5, clHill, 1)],
scaleByMapSize(5,18), 100
);
Engine.SetProgress(86);
g_Map.log("Creating small decorative rocks");
group = new SimpleGroup(
[new SimpleObject(aRockMedium, 1,3, 0,1)],
true
);
createObjectGroupsDeprecated(
group, 0,
avoidClasses(clRoad, 0, clForest, 0, clPlayer, 0, clHill, 0),
scaleByMapSize(16, 262), 50
);
g_Map.log("Creating large decorative rocks");
group = new SimpleGroup(
[new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)],
true
);
createObjectGroupsDeprecated(
group, 0,
avoidClasses(clRoad, 0, clForest, 0, clPlayer, 0, clHill, 0),
scaleByMapSize(8, 131), 50
);
g_Map.log("Creating additionnal food for players (balance)");
// Player ressource balance calculation
var initialFoodAmount = randIntInclusive(0, 35)// * 100 // 1 unit = 100 food
// I want it likely that there is no additionnal food for the player.
if (initialFoodAmount < 6)
initialFoodAmount = 0;
for (let i = 0; i < numPlayers; ++i) {
let playerClass = clPlayers[i];
let remainingFood = initialFoodAmount;
while (remainingFood > 0) {
// Not sure if i should remove groups of 1 / 2 sheep or not.
if (remainingFood <= 2) {
remainingFood = 0;
}
else if (remainingFood <= 4) {
placeFood(oSheep, remainingFood, remainingFood, remainingFood, playerClass, i);
remainingFood = 0;
}
else if (remainingFood <= 10) {
remainingFood -= placeFood(oDeer, 5, 8, remainingFood, playerClass, i);
}
else {
// There I want it more likely to pick berries since hunt will always be chosen for the lower remaining food amounts
if (randBool(0.68)) {
remainingFood -= 2 * placeFood(oBerryBush, 5, 7, Math.floor(remainingFood/2), playerClass, i);
}
else {
remainingFood -= placeFood(oDeer, 5, 8, remainingFood, playerClass, i);
}
}
}
}
g_Map.log("Creating deer");
group = new SimpleGroup(
[new SimpleObject(oDeer, 5,7, 0,4)],
true, clFood
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clRoad, 0, clForest, 0, clPlayer, neighbouringPlayerTiles, clHill, 1, clMetal, 4, clRock, 4, clFood, 20),
3 * numPlayers, 50
);
g_Map.log("Creating rabbits");
group = new SimpleGroup(
[new SimpleObject(oRabbit, 2,3, 0,2)],
true, clFood
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clRoad, 0, clForest, 0, clPlayer, neighbouringPlayerTiles, clHill, 1, clMetal, 4, clRock, 4, clFood, 20),
3 * numPlayers, 50
);
g_Map.log("Creating berry bush");
group = new SimpleGroup(
[new SimpleObject(oBerryBush, 5,7, 0,4)],
true, clFood
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clRoad, 20, clForest, 0, clPlayer, neighbouringPlayerTiles, clHill, 1, clMetal, 4, clRock, 4, clFood, 10),
randIntInclusive(1, 4) * numPlayers + 2, 50
);
createStragglerTrees(
[oOak, oBeech],
avoidClasses(clRoad, 30, clForest, 7, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6),
clForest,
stragglerTrees);
createAutomnalStragglerTrees(tGrassDForest,
oOakBig,
clForest,
borderStragglers,
new AndConstraint([avoidClasses(clForest, 7, clBorder, 4, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6, clRoad, 2), borderClasses(clRoad, 0, 20)]),
10);
g_Map.log("Creating dry grass");
group = new SimpleGroup(
[new SimpleObject(aDryGrass, 4,6, 0,0.8, -Math.PI / 8, Math.PI / 8)]
);
createObjectGroupsDeprecated(group, 0,
new AndConstraint([avoidClasses(clRoad, 2, clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clDryGrass, 0)]),
scaleByMapSize(125, 800)
);
g_Map.log("Creating flowering grass");
group = new SimpleGroup(
[new SimpleObject(aGrassFlower, 4,6, 0,1, -Math.PI / 8, Math.PI / 8)]
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clRoad, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0, clDryGrass, 2),
scaleByMapSize(125, 1000)
);
g_Map.log("Creating soft grass");
group = new SimpleGroup(
[new SimpleObject(aGrassSoft, 1,2, 0,1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(aGrassSoftTall, 1,1, 1.2,2.5, -Math.PI / 8, Math.PI / 8)]
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clRoad, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0, clDryGrass, 2),
scaleByMapSize(18, 150)
);
g_Map.log("Creating bushes");
group = new SimpleGroup(
[new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)]
);
createObjectGroupsDeprecated(group, 0,
avoidClasses(clRoad, 1, clHill, 1, clPlayer, 1, clDirt, 1),
scaleByMapSize(13, 200), 50
);
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2));
setSkySet("sunset");
setSunColor(1.17359, 1.01251, 0.478641);
setSunElevation(0.297592);
setSunRotation(3.14159);
setAmbientColor(0.392157, 0.427451, 0.529412);
setFogFactor(0.00298828);
setFogThickness(0.00195313);
setFogColor(0.886275, 0.811765, 0.576471);
g_Map.ExportMap();
function createAutomnalStragglerTrees(groundTexture, treeType, tileClass, count, constraints, retryFactor)
{
let placeFunc = function() {
let center = g_Map.randomCoordinate(false);
let centeredPlacer = new ClumpPlacer(randIntInclusive(2, 6), 0, 0.25);
centeredPlacer.setCenterPosition(center);
let area = createArea(centeredPlacer, new TerrainPainter(groundTexture), constraints);
if (area)
g_Map.placeEntityAnywhere(treeType, 0, center, randomAngle())
return area;
};
return retryPlacing(placeFunc, retryFactor, count, false);
}
// Places a bounded amount of corresponding type food to the specified player and returns the amount placed.
function placeFood(type, min, max, remainingFood, playerClass, areaId) {
// Since the placing function doesn't specify (i think ?) the number of objects placed, randomization is done there.
max = max < remainingFood ? max : remainingFood;
let amountPlaced = randIntInclusive(min, max);
// Hunt should spawn farther from the CC in general.
let minTileBound = 15;
let maxTileBound = 25;
if (type != oBerryBush) {
minTileBound += 10;
maxTileBound += 10;
}
let group = new SimpleGroup(
[new SimpleObject(type, amountPlaced, amountPlaced, 0,4)],
true, clFood
);
createObjectGroupsByAreas(group, 0,
new AndConstraint([avoidClasses(clRoad, 0, clForest, 0, clPlayer, minTileBound, clHill, 1, clMetal, 4, clRock, 4, clFood, 10), borderClasses(playerClass, 0, maxTileBound)]),
1, 400, [surroundingPlayersAreas[areaId]]
);
return amountPlaced;
}
// If we move this function, add tileClass ids for each player in argument
function placePlayerBasesCustom(playerBaseArgs)
{
g_Map.log("Creating playerbases");
let [playerIDs, playerPosition] = playerBaseArgs.PlayerPlacement;
for (let i = 0; i < getNumPlayers(); ++i)
{
playerBaseArgs.playerID = playerIDs[i];
playerBaseArgs.playerPosition = playerPosition[i];
playerBaseArgs.CityPatch.painters = [new TileClassPainter(clPlayer), new TileClassPainter(clPlayers[i])];
placePlayerBase(playerBaseArgs);
}
}
function createForestsCustom(terrainSet, constraint, tileClass, treeCount, retryFactor)
{
if (!treeCount)
return;
// Construct different forest types from the terrain textures and template names.
let [mainTerrain, terrainForestFloor1, terrainForestFloor2, terrainForestTree1, terrainForestTree2] = terrainSet;
// The painter will pick a random Terrain for each part of the forest.
let forestVariants = [
{
"borderTerrains": [terrainForestFloor2, mainTerrain, terrainForestTree1],
"interiorTerrains": [terrainForestFloor2, terrainForestTree1]
},
{
"borderTerrains": [terrainForestFloor1, mainTerrain, terrainForestTree2],
"interiorTerrains": [terrainForestFloor1, terrainForestTree2]
}
];
let groundVariants = [
{
"borderTerrains": [terrainForestFloor2, mainTerrain],
"interiorTerrains": [terrainForestFloor2]
},
{
"borderTerrains": [terrainForestFloor1, mainTerrain],
"interiorTerrains": [terrainForestFloor1]
}
];
g_Map.log("Creating forests");
let numberOfForests = Math.floor(treeCount / (scaleByMapSize(3, 6) * getNumPlayers() * forestVariants.length));
for (let forestVariant of forestVariants)
createAreas(
new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), treeCount / numberOfForests, 0.5),
[
//new LayeredPainter([groundVariants.borderTerrains, groundVariants.interiorTerrains], [2]),
new TerrainPainter(terrainForestFloor1),
new CustomLayeredPainter([forestVariant.borderTerrains, forestVariant.interiorTerrains], [2]),
new TileClassPainter(tileClass)
],
constraint,
numberOfForests,
retryFactor);
}
function createThickerForests(terrainSet, constraint, tileClass, treeCount, retryFactor)
{
if (!treeCount)
return;
// Construct different forest types from the terrain textures and template names.
let [mainTerrain, terrainForestFloor1, terrainForestFloor2, terrainForestTree1, terrainForestTree2] = terrainSet;
// The painter will pick a random Terrain for each part of the forest.
let forestVariants = [
{
"borderTerrains": [terrainForestFloor2, mainTerrain, terrainForestTree1],
"interiorTerrains": [terrainForestFloor2, terrainForestTree1]
},
{
"borderTerrains": [terrainForestFloor1, mainTerrain, terrainForestTree2],
"interiorTerrains": [terrainForestFloor1, terrainForestTree2]
}
];
//treeCount /= Math.floor(getNumPlayers() / 2);
g_Map.log("Creating forests");
let numberOfForests = Math.floor(treeCount / (scaleByMapSize(24, 40) * forestVariants.length));
for (let forestVariant of forestVariants)
createAreas(
new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), treeCount / numberOfForests, 0.5),
[
new LayeredPainter([forestVariant.borderTerrains, forestVariant.interiorTerrains], [2]),
new TileClassPainter(tileClass)
],
constraint,
numberOfForests,
retryFactor);
}
function createPlayerForests(terrainSet, constraint, tileClass, playerArea)
{
// Construct different forest types from the terrain textures and template names.
let [mainTerrain, terrainForestFloor1, terrainForestFloor2, terrainForestTree1, terrainForestTree2] = terrainSet;
// The painter will pick a random Terrain for each part of the forest.
let forestVariants = [
{
"borderTerrains": [terrainForestFloor2, mainTerrain, terrainForestTree1],
"interiorTerrains": [terrainForestFloor2, terrainForestTree1]
},
{
"borderTerrains": [terrainForestFloor1, mainTerrain, terrainForestTree2],
"interiorTerrains": [terrainForestFloor1, terrainForestTree2]
}
];
let forestVariant = pickRandom(forestVariants);
let treeCount = 28;
createAreasInAreas(
new ChainPlacer(1, /*Math.floor(scaleByMapSize(3, 5))*/3, treeCount, 0),
[
new LayeredPainter([forestVariant.borderTerrains, forestVariant.interiorTerrains], [2]),
new TileClassPainter(tileClass)
],
constraint,
1,
100,
[playerArea]);
}

View File

@ -0,0 +1,10 @@
{
"settings" : {
"Name" : "Britannic Road",
"Script" : "britannic_road.js",
"Description" : "Britannic Road",
"Preview" : "britannic_road.png",
"Keywords": ["badmod"],
"CircularMap" : true
}
}

View File

@ -0,0 +1,338 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("rmbiome");
Engine.LoadLibrary("balancedHelpers");
setSelectedBiome();
const heightSeaGround = -3;
const tMainTerrain = g_Terrains.mainTerrain;
const tForestFloor1 = g_Terrains.forestFloor1;
const tForestFloor2 = g_Terrains.forestFloor2;
const tCliff = g_Terrains.cliff;
const tShore = g_Terrains.shore;
const tTier1Terrain = g_Terrains.tier1Terrain;
const tTier2Terrain = g_Terrains.tier2Terrain;
const tTier3Terrain = g_Terrains.tier3Terrain;
const tHill = g_Terrains.hill;
const tRoad = g_Terrains.road;
const tRoadWild = g_Terrains.roadWild;
const tTier4Terrain = g_Terrains.tier4Terrain;
const tWater = g_Terrains.water;
const oTree1 = g_Gaia.tree1;
const oTree2 = g_Gaia.tree2;
const oTree3 = g_Gaia.tree3;
const oTree4 = g_Gaia.tree4;
const oTree5 = g_Gaia.tree5;
const oFish = g_Gaia.fish;
const oFruitBush = g_Gaia.fruitBush;
const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
const oStoneLarge = g_Gaia.stoneLarge;
const oStoneSmall = g_Gaia.stoneSmall;
const oMetalLarge = g_Gaia.metalLarge;
const aGrass = g_Decoratives.grass;
const aGrassShort = g_Decoratives.grassShort;
const aRockLarge = g_Decoratives.rockLarge;
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const heightLand = 3;
var g_Map = new RandomMap(heightLand, tMainTerrain);
const mapSize = g_Map.getSize();
const numPlayers = getNumPlayers();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clWater = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
var playerPlacements = playerPlacementCircle(fractionToTiles(0.26 + (numPlayers - 2) * 0.008));
const mapCenter = g_Map.getCenter();
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oFruitBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oTree1,
"count": 5
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(20);
const [playersOrder, playerPositions, playerAngles, startingAngle] = playerPlacements;
for (let i = 0; i < numPlayers; ++i)
{
const playerPosition = playerPositions[i];
const angle = playerAngles[i];
const lakeRadius = 40;
const lakePosition = Vector2D.add(playerPosition, new Vector2D(lakeRadius, 0).rotate(-angle)).round();
const lakeSize = Math.round(scaleByMapSize(40, 70) - (numPlayers - 2) * 6);
createArea(
new ChainPlacer(
3,
4,
45,
Infinity,
lakePosition,
lakeRadius - 5,
[lakeSize]),
[
new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4),
new TileClassPainter(clWater)
],
avoidClasses(clPlayer, 25));
let lakeArea = new Area(new DiskPlacer(30, lakePosition).place(new NullConstraint()));
let fish = new SimpleGroup(
[new SimpleObject(oFish, 2, 2, 0, 2)],
true,
clFood
);
createObjectGroupsByAreas(fish, 0,
new AndConstraint([avoidClasses(clFood, 10), stayClasses(clWater, 8)]),
5, 400, [lakeArea]
);
const offsetAngle = Math.PI / numPlayers;
const sideLakeRadius = fractionToTiles(0.5) - 2;
const sideLakePosition = Vector2D.add(mapCenter, new Vector2D(sideLakeRadius, 0).rotate(-angle - offsetAngle)).round();
if (mapSize > 128) {
const sideMinesRadius = lakeSize + 10;
const sideStonePosition = Vector2D.add(sideLakePosition, new Vector2D(sideMinesRadius, 0).rotate(-angle + -offsetAngle + Math.PI - Math.PI/5)).round();
const sideMetalPosition = Vector2D.add(sideLakePosition, new Vector2D(sideMinesRadius, 0).rotate(-angle + -offsetAngle + Math.PI + Math.PI/5)).round();
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock),
0,
avoidClasses(clForest, 10, clWater, 3),
1, 400,
[new Area(new DiskPlacer(2, sideStonePosition).place(new NullConstraint()))]
);
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal),
0,
avoidClasses(clForest, 10, clWater, 3, clRock, 4),
1, 400,
[new Area(new DiskPlacer(3, sideMetalPosition).place(new NullConstraint()))]
);
}
createArea(
new ChainPlacer(
3,
4,
45,
Infinity,
sideLakePosition,
lakeRadius - 5,
[lakeSize + 5]),
[
new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4),
new TileClassPainter(clWater)
],
avoidClasses(clPlayer, 25, clRock, 5, clMetal, 5));
const sideLakeArea = new Area(new DiskPlacer(35, sideLakePosition).place(stayClasses(clWater, 1)));
createObjectGroupsByAreas(fish, 0,
new AndConstraint([avoidClasses(clFood, 10), stayClasses(clWater, 8)]),
randIntInclusive(7, 10), 400, [sideLakeArea]
);
Engine.SetProgress(20 + 2 * i);
}
const constraints = avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10, clWater, 2);
const foodMultiplier = 0.5; // Fishing is map dynamic 0.5 causes errors?
placeBalancedFood(playerPlacements, constraints, foodMultiplier);
Engine.SetProgress(35);
if (numPlayers <= 2 && mapSize > 192) {
placeBalancedMinerals(playerPositions, avoidClasses(clWater, 6, clMetal, 40, clRock, 40));
}
Engine.SetProgress(40);
paintTerrainBasedOnHeight(2.4, 3.4, 3, tMainTerrain);
paintTerrainBasedOnHeight(1, 2.4, 0, tShore);
paintTerrainBasedOnHeight(-8, 1, 2, tWater);
paintTileClassBasedOnHeight(-6, 0, 1, clWater);
createBumps(avoidClasses(clPlayer, 20, clWater, 1));
Engine.SetProgress(45);
if (randBool())
createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 35, clHill, 15, clWater, 6, clFood, 4, clMetal, 6, clRock, 6), clHill, scaleByMapSize(2, 11));
else
createMountains(tCliff, avoidClasses(clPlayer, 35, clHill, 15, clWater, 6, clFood, 4, clMetal, 6, clRock, 6), clHill, scaleByMapSize(2, 11));
Engine.SetProgress(50);
if (currentBiome() != "generic/savanna") {
createBalancedPlayerForests(
playerPositions,
avoidClasses(clForest, 18, clHill, 0, clMetal, 4, clRock, 4, clFood, 4, clWater, 4),
clForest);
}
Engine.SetProgress(55);
var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1));
createForests(
[tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2],
avoidClasses(clPlayer, 18, clForest, 15, clHill, 0, clMetal, 4, clRock, 4, clWater, 4),
clForest,
forestTrees);
Engine.SetProgress(60);
g_Map.log("Creating dirt patches");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1, 1],
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWater, 1),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(63);
g_Map.log("Creating grass patches");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWater, 1),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(65);
const mineralAvoidance = numPlayers > 2 ? 10 : 30;
const playerMineralAvoidance = numPlayers > 2 ? 50 : 65;
g_Map.log("Creating stone mines");
createMines(
[
[new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)]
],
avoidClasses(clForest, 1, clPlayer, playerMineralAvoidance, clMetal, mineralAvoidance, clRock, mineralAvoidance, clHill, 1, clWater, 6),
clRock,
scaleByMapSize(4, 16) - 1
);
Engine.SetProgress(68);
g_Map.log("Creating metal mines");
createMines(
[
[new SimpleObject(oMetalLarge, 1, 1, 0, 4)]
],
avoidClasses(clForest, 1, clPlayer, playerMineralAvoidance, clMetal, mineralAvoidance, clRock, mineralAvoidance, clHill, 1, clWater, 6),
clMetal,
scaleByMapSize(4, 16) - 1
);
Engine.SetProgress(70);
var planetm = 1;
if (currentBiome() == "generic/tropic")
planetm = 8;
createDecoration(
[
[new SimpleObject(aRockMedium, 1, 3, 0, 1)],
[new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
[new SimpleObject(aGrassShort, 1, 2, 0, 1)],
[new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3,6, 1.2, 2.5)],
[new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0, clWater, 0));
Engine.SetProgress(73);
createBadFood(avoidClasses(clForest, 0, clHill, 1, clMetal, 4, clRock, 4, clFood, 20, clWater, 4));
Engine.SetProgress(75);
createFood(
[
[new SimpleObject(oFruitBush, 5, 7, 0, 4)]
],
[
2 * numPlayers
],
avoidClasses(clForest, 0, clPlayer, 45, clHill, 1, clMetal, 4, clRock, 4, clFood, 10, clWater, 4),
clFood);
Engine.SetProgress(85);
createStragglerTrees(
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(
clForest, 8, clHill, 1, clPlayer,
currentBiome() === "generic/savanna" ? 12 : 30,
clMetal, 6, clRock, 6, clFood, 1, clWater, 4
),
clForest,
stragglerTrees);
createBalancedPlayerStragglerTrees(
playerPositions,
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(clForest, 8, clHill, 1, clMetal, 6, clRock, 6, clFood, 1, clWater, 2, clBaseResource, 2),
25,
clForest
)
Engine.SetProgress(95);
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWater, 6));
g_Map.ExportMap();

View File

@ -0,0 +1,11 @@
{
"settings" : {
"Name" : "Cross",
"Script" : "cross.js",
"Description" : "Players start with lake behind the base with plenty of fishing.",
"Preview" : "cross.png",
"SupportedBiomes": "generic/",
"Keywords": ["badmod"],
"CircularMap" : true
}
}

View File

@ -0,0 +1,41 @@
/**
* The LayeredPainter sets different Terrains within the Area.
* It choses the Terrain depending on the distance to the border of the Area.
*
* The Terrains given in the first array are painted from the border of the area towards the center (outermost first).
* The widths array has one item less than the Terrains array.
* Each width specifies how many tiles the corresponding Terrain should be wide (distance to the prior Terrain border).
* The remaining area is filled with the last terrain.
*/
function CustomLayeredPainter(terrainArray, widths)
{
if (!(terrainArray instanceof Array))
throw new Error("CustomLayeredPainter: terrains must be an array!");
this.terrains = terrainArray.map(terrain => createTerrain(terrain));
this.widths = widths;
}
CustomLayeredPainter.prototype.paint = function(area)
{
breadthFirstSearchPaint({
"area": area,
"brushSize": 1,
"gridSize": g_Map.getSize(),
"withinArea": (area, position) => area.contains(position),
"paintTile": (point, distance) => {
let width = 0;
let i = 0;
for (; i < this.widths.length; ++i)
{
width += this.widths[i];
if (width >= distance)
break;
}
if (randBool(0.3))
this.terrains[i].place(point);
}
});
};

View File

@ -0,0 +1,37 @@
function AnnulusPlacer(minRadius, maxRadius, centerPosition = undefined)
{
this.minRadiusSquared = Math.square(minRadius);
this.maxRadiusSquared = Math.square(maxRadius);
this.maxRadius = maxRadius;
this.centerPosition = undefined;
if (centerPosition)
this.setCenterPosition(centerPosition);
}
AnnulusPlacer.prototype.setCenterPosition = function(position)
{
this.centerPosition = deepfreeze(position.clone().round());
};
AnnulusPlacer.prototype.place = function(constraint = new NullConstraint())
{
let points = [];
const xMin = Math.floor(Math.max(0, this.centerPosition.x - this.maxRadius));
const yMin = Math.floor(Math.max(0, this.centerPosition.y - this.maxRadius));
const xMax = Math.ceil(Math.min(g_Map.getSize() - 1, this.centerPosition.x + this.maxRadius));
const yMax = Math.ceil(Math.min(g_Map.getSize() - 1, this.centerPosition.y + this.maxRadius));
let it = new Vector2D();
for (it.x = xMin; it.x <= xMax; ++it.x)
for (it.y = yMin; it.y <= yMax; ++it.y)
{
const distance = this.centerPosition.distanceToSquared(it);
if (this.minRadiusSquared <= distance && this.maxRadiusSquared >= distance && constraint.allows(it))
points.push(it.clone());
}
return points;
};

View File

@ -0,0 +1,406 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("rmbiome");
setSelectedBiome();
Engine.LoadLibrary("balancedHelpers");
const tMainTerrain = g_Terrains.mainTerrain;
const tForestFloor1 = g_Terrains.forestFloor1;
const tForestFloor2 = g_Terrains.forestFloor2;
const tCliff = g_Terrains.cliff;
const tTier1Terrain = g_Terrains.tier1Terrain;
const tTier2Terrain = g_Terrains.tier2Terrain;
const tTier3Terrain = g_Terrains.tier3Terrain;
const tHill = g_Terrains.hill;
const tRoad = g_Terrains.road;
const tRoadWild = g_Terrains.roadWild;
const tTier4Terrain = g_Terrains.tier4Terrain;
const tWater = g_Terrains.water;
const tShore = g_Terrains.shore;
const oTree1 = g_Gaia.tree1;
const oTree2 = g_Gaia.tree2;
const oTree3 = g_Gaia.tree3;
const oTree4 = g_Gaia.tree4;
const oTree5 = g_Gaia.tree5;
const oFish = g_Gaia.fish;
const oFruitBush = g_Gaia.fruitBush;
const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
const oStoneLarge = g_Gaia.stoneLarge;
const oStoneSmall = g_Gaia.stoneSmall;
const oMetalLarge = g_Gaia.metalLarge;
const aGrass = g_Decoratives.grass;
const aGrassShort = g_Decoratives.grassShort;
const aRockLarge = g_Decoratives.rockLarge;
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const heightLand = 0;
var g_Map = new RandomMap(heightLand, tMainTerrain);
const center = g_Map.getCenter();
const mapSize = g_Map.getSize();
const halfMapSize = g_Map.getSize() / 2;
const numPlayers = getNumPlayers();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clFish = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
const clRamp = g_Map.createTileClass();
const clWater = g_Map.createTileClass();
const playerDistance = fractionToTiles(0.29);
const [playerIDs, playerPositions] = placeOpposingTeams(playerDistance, Math.PI / 2, center);
const playerPlacements = [playerIDs, playerPositions];
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oFruitBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oTree1,
"count": 5
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(10);
const heightTop = heightLand + 5;
const lowlandsWidth = fractionToTiles(0.36);
const rampWidth = fractionToTiles(0.05);
const elevationPainter = new ElevationPainter(heightTop);
const rightRampStartX = halfMapSize + lowlandsWidth / 2;
const rightRampEndX = rightRampStartX + rampWidth;
const leftRampStartX = halfMapSize - lowlandsWidth / 2;
const leftRampEndX = leftRampStartX - rampWidth;
const rightPlateauPlacer = new RectPlacer(new Vector2D(rightRampEndX, mapSize), new Vector2D(mapSize, 0));
const leftPlateauPlacer = new RectPlacer(new Vector2D(0, mapSize), new Vector2D(leftRampEndX, 0));
createArea(rightPlateauPlacer, elevationPainter);
Engine.SetProgress(12);
createArea(leftPlateauPlacer, elevationPainter);
Engine.SetProgress(14);
createPassage({
"start": new Vector2D(rightRampStartX, halfMapSize),
"end": new Vector2D(rightRampEndX, halfMapSize),
"startWidth": mapSize,
"endWidth": mapSize,
"smoothWidth": 2,
"tileClass": clRamp,
"terrain": tCliff,
"edgeTerrain": tHill
});
Engine.SetProgress(16);
createPassage({
"start": new Vector2D(leftRampStartX, halfMapSize),
"end": new Vector2D(leftRampEndX, halfMapSize),
"startWidth": mapSize,
"endWidth": mapSize,
"smoothWidth": 2,
"tileClass": clRamp,
"terrain": tCliff,
"edgeTerrain": tHill
});
Engine.SetProgress(18);
const heightWaterLevel = heightTop - 7;
const fish = new SimpleGroup([new SimpleObject(oFish, 2, 2, 0, 2)], true, clFish);
const stone = new SimpleGroup(
[new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)],
true,
clRock
);
const metal = new SimpleGroup(
[new SimpleObject(oMetalLarge, 1, 1, 0, 4)],
true,
clMetal
);
function createSideLakes(xDistance, yDistance) {
const stoneRight = randBool();
let mineralDistribution = [stoneRight, !stoneRight];
for (let x of [halfMapSize + xDistance, halfMapSize - xDistance]) {
const position = new Vector2D(x, halfMapSize + yDistance);
const lakeSize = scaleByMapSize(14, 38);
const placer = new ChainPlacer(
2,
Math.floor(scaleByMapSize(3, 8)),
Math.floor(scaleByMapSize(8, 20)),
Infinity,
position,
0,
[lakeSize]
);
createArea(
placer,
[
new SmoothElevationPainter(ELEVATION_SET, heightWaterLevel - 3, 4),
new TileClassPainter(clWater),
],
new NullConstraint()
);
createObjectGroupsByAreas(fish, 0,
avoidClasses(clFish, 6),
scaleByMapSize(3, 9), 1000,
[new Area(placer.place(stayClasses(clWater, 1)))]
);
const lowerRadius = lakeSize + 2;
const maxRadius = lakeSize + 4;
createObjectGroupsByAreas(mineralDistribution.pop() ? stone : metal, 0,
avoidClasses(clWater, 4, clPlayer, 50),
1, 400, [getAnnulusArea(lowerRadius, maxRadius, position)]
);
placeFoodAmount(oMainHuntableAnimal, 4, 4, position, avoidClasses(clWater, 2, clFood, 25, clRock, 4, clMetal, 4, clPlayer, 50), lowerRadius, maxRadius);
placeFoodAmount(oMainHuntableAnimal, 4, 4, position, avoidClasses(clWater, 2, clFood, 25, clRock, 4, clMetal, 4, clPlayer, 50), lowerRadius, maxRadius);
}
}
const lakeDistance = rampWidth + lowlandsWidth / 2 + fractionToTiles(0.11);
createSideLakes(lakeDistance, fractionToTiles(0.31));
Engine.SetProgress(22);
createSideLakes(lakeDistance, -fractionToTiles(0.31));
Engine.SetProgress(24);
createArea(
leftPlateauPlacer,
new TerrainPainter(tWater),
new HeightConstraint(-Infinity, heightTop - 1.5));
Engine.SetProgress(26);
createArea(
leftPlateauPlacer,
new TerrainPainter(tShore),
new HeightConstraint(heightTop - 1, heightTop - 2));
Engine.SetProgress(27);
createArea(
rightPlateauPlacer,
new TerrainPainter(tWater),
new HeightConstraint(-Infinity, heightTop - 1.5));
Engine.SetProgress(28);
createArea(
rightPlateauPlacer,
new TerrainPainter(tShore),
new HeightConstraint(heightTop - 1, heightTop - 2));
Engine.SetProgress(29);
createBumps(avoidClasses(clPlayer, 20));
Engine.SetProgress(30);
const mineralPlacer = new DiskPlacer(4, center);
const centerMineralsArea = new Area(mineralPlacer.place(new NullConstraint()));
createObjectGroupsByAreas(stone, 0,
new NullConstraint(),
1, 400, [centerMineralsArea]
);
createObjectGroupsByAreas(metal, 0,
avoidClasses(clRock, 6),
1, 400, [centerMineralsArea]
);
Engine.SetProgress(32);
if (randBool())
createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 35, clHill, 15, clMetal, 4, clRock, 4, clWater, 8), clHill, scaleByMapSize(2, 11));
else
createMountains(tCliff, avoidClasses(clPlayer, 35, clHill, 15, clMetal, 4, clRock, 4, clWater, 8), clHill, scaleByMapSize(2, 11));
Engine.SetProgress(34);
placeBalancedFood(playerPlacements,
avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10, clWater, 4),
0.5
);
Engine.SetProgress(40);
if (currentBiome() != "generic/savanna") {
createBalancedPlayerForests(
playerPositions,
avoidClasses(clForest, 18, clHill, 1, clMetal, 4, clRock, 4, clFood, 4, clWater, 4, clBaseResource, 8),
clForest);
}
Engine.SetProgress(44);
const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(0.7));
const leftPlateauArea = new Area(leftPlateauPlacer.place(avoidClasses(clWater, 4, clPlayer, 40)));
const rightPlateauArea = new Area(rightPlateauPlacer.place(avoidClasses(clWater, 4, clPlayer, 40)));
createForestsInArea(
leftPlateauArea,
avoidClasses(clForest, 13, clHill, 1, clMetal, 4, clRock, 4, clFood, 4, clWater, 3, clPlayer, 40),
clForest,
forestTrees,
2);
Engine.SetProgress(48);
createForestsInArea(
rightPlateauArea,
avoidClasses(clForest, 13, clHill, 1, clMetal, 4, clRock, 4, clFood, 4, clWater, 3, clPlayer, 40),
clForest,
forestTrees,
2);
Engine.SetProgress(52);
const lowlandsPlacer = new RectPlacer(new Vector2D(leftRampStartX, 0), new Vector2D(rightRampStartX, mapSize));
const lowlandsArea = new Area(lowlandsPlacer.place(avoidClasses(clPlayer, 40)));
createForestsInArea(
lowlandsArea,
avoidClasses(clForest, 14, clHill, 1, clMetal, 4, clRock, 4, clFood, 4, clPlayer, 38),
clForest,
Math.round(forestTrees),
2,
2
);
Engine.SetProgress(55);
g_Map.log("Creating dirt patches");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1, 1],
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWater, 3),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(57);
g_Map.log("Creating grass patches");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWater, 3, clRamp, 0),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(59);
g_Map.log("Creating stone mines");
createMines(
[
[new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)]
],
avoidClasses(clForest, 1, clPlayer, 60, clRock, 22, clHill, 1, clWater, 30),
clRock,
scaleByMapSize(4, 16) - 2
);
Engine.SetProgress(62);
g_Map.log("Creating metal mines");
createMines(
[
[new SimpleObject(oMetalLarge, 1, 1, 0, 4)]
],
avoidClasses(clForest, 1, clPlayer, 60, clMetal, 22, clRock, 5, clHill, 1, clWater, 30),
clMetal,
scaleByMapSize(4, 16) - 2
);
Engine.SetProgress(65);
var planetm = 1;
if (currentBiome() == "generic/tropic")
planetm = 8;
createDecoration(
[
[new SimpleObject(aRockMedium, 1, 3, 0, 1)],
[new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
[new SimpleObject(aGrassShort, 1, 2, 0, 1)],
[new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3,6, 1.2, 2.5)],
[new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0, clWater, 0));
Engine.SetProgress(70);
createBadFood(avoidClasses(clForest, 0, clHill, 1, clMetal, 4, clRock, 4, clFood, 20, clWater, 20));
Engine.SetProgress(75);
createFood(
[
[new SimpleObject(oFruitBush, 5, 7, 0, 4)]
],
[
2 * numPlayers
],
avoidClasses(clForest, 0, clPlayer, 45, clHill, 1, clMetal, 4, clRock, 4, clFood, 10, clWater, 14),
clFood);
Engine.SetProgress(80);
createStragglerTrees(
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(
clForest, 8, clHill, 1, clPlayer,
(currentBiome() == "generic/savanna") ? 12 : 30,
clMetal, 6, clRock, 6, clFood, 1, clWater, 4
),
clForest,
(currentBiome() == "generic/savanna") ? stragglerTrees * 1.5 : stragglerTrees);
Engine.SetProgress(85);
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWater, 6));
g_Map.ExportMap();

View File

@ -0,0 +1,11 @@
{
"settings" : {
"Name" : "Slopes",
"Script" : "slopes.js",
"Description" : "Teams are placed in opposite sides, surrounded by plateaus with plenty of wood and fish from lakes.",
"Preview" : "slopes.png",
"SupportedBiomes": "generic/",
"Keywords": ["badmod"],
"CircularMap" : false
}
}

View File

@ -0,0 +1,280 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("rmbiome");
Engine.LoadLibrary("balancedHelpers");
setSelectedBiome();
const tMainTerrain = g_Terrains.mainTerrain;
const tForestFloor1 = g_Terrains.forestFloor1;
const tForestFloor2 = g_Terrains.forestFloor2;
const tCliff = g_Terrains.cliff;
const tTier1Terrain = g_Terrains.tier1Terrain;
const tTier2Terrain = g_Terrains.tier2Terrain;
const tTier3Terrain = g_Terrains.tier3Terrain;
const tHill = g_Terrains.hill;
const tRoad = g_Terrains.road;
const tRoadWild = g_Terrains.roadWild;
const tTier4Terrain = g_Terrains.tier4Terrain;
const oTree1 = g_Gaia.tree1;
const oTree2 = g_Gaia.tree2;
const oTree3 = g_Gaia.tree3;
const oTree4 = g_Gaia.tree4;
const oTree5 = g_Gaia.tree5;
const oFruitBush = g_Gaia.fruitBush;
const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
const oStoneLarge = g_Gaia.stoneLarge;
const oStoneSmall = g_Gaia.stoneSmall;
const oMetalLarge = g_Gaia.metalLarge;
const aGrass = g_Decoratives.grass;
const aGrassShort = g_Decoratives.grassShort;
const aRockLarge = g_Decoratives.rockLarge;
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const heightLand = 3;
var g_Map = new RandomMap(heightLand, tMainTerrain);
const mapSize = g_Map.getSize();
const numPlayers = getNumPlayers();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clWrenchHead = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
const wrenchScaling = 10 * (numPlayers - 2);
const playersCircleRadius = 28 + wrenchScaling;
const playerPlacements = playerPlacementCircle(playersCircleRadius);
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oFruitBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oTree1,
"count": 5
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(20);
var [playersOrder, playerPositions, playerAngles, startingAngle] = playerPlacements;
const mapCenter = g_Map.getCenter();
const minesVariation = randIntInclusive(2, 12);
for (let i = 0; i < numPlayers; ++i) {
const playerAngle = playerAngles[i];
const offsetAngle = Math.PI / numPlayers;
const minesRadius = playersCircleRadius + numPlayers * 3 + minesVariation;
const minesPoint = new Vector2D(minesRadius).rotate(- playerAngle - offsetAngle);
const minesArea = new Area(
new DiskPlacer(2.2, Vector2D.add(mapCenter, minesPoint).round()).place(new NullConstraint())
);
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal),
0,
avoidClasses(clForest, 6, clHill, 7),
1, 400,
[minesArea]
);
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock),
0,
avoidClasses(clForest, 6, clHill, 7, clMetal, 6),
1, 400,
[minesArea]
);
const minesClumpPosition = new Vector2D(minesRadius - 15).rotate(- playerAngle - offsetAngle);
const wrenchHeadSize = 20;
createArea(
new DiskPlacer(wrenchHeadSize, Vector2D.add(mapCenter, minesClumpPosition).round()),
[
new TerrainPainter(tCliff),
new SmoothElevationPainter(ELEVATION_SET, 24, 1),
new TileClassPainter(clWrenchHead)
],
avoidClasses(clPlayer, 18, clMetal, 9, clRock, 9)
);
// If map is not tiny, create metal and stone far from each player near edges
if (mapSize > 128) {
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock),
0,
avoidClasses(clForest, 6, clHill, 7),
1, 400,
[new Area(new DiskPlacer(3, Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.42), 0).rotate(- playerAngle + offsetAngle / 3)).round()).place(new NullConstraint()))]
);
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal),
0,
avoidClasses(clForest, 6, clHill, 7),
1, 400,
[new Area(new DiskPlacer(3, Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.42), 0).rotate(- playerAngle - offsetAngle / 3)).round()).place(new NullConstraint()))]
);
}
Engine.SetProgress(20 + i);
}
const handleSize = 30 + 11.5 * (numPlayers - 2);
createArea(
new DiskPlacer(handleSize, mapCenter),
[
new TerrainPainter(tCliff),
new SmoothElevationPainter(ELEVATION_SET, 24, 1),
new TileClassPainter(clHill)
],
avoidClasses(clPlayer, 18, clMetal, 10, clRock, 10)
);
Engine.SetProgress(35);
createBumps(avoidClasses(clPlayer, 20, clMetal, 6, clRock, 6));
Engine.SetProgress(40);
placeBalancedFood(playerPlacements,
avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10, clWrenchHead, 1),
1.2 - numPlayers * 0.1
);
Engine.SetProgress(45);
if (randBool())
createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 42, clHill, 15, clMetal, 10, clRock, 10, clWrenchHead, 20, clFood, 4), clHill, scaleByMapSize(2, 11));
else
createMountains(tCliff, avoidClasses(clPlayer, 42, clHill, 15, clMetal, 10, clRock, 10, clWrenchHead, 20, clFood, 4), clHill, scaleByMapSize(2, 11));
Engine.SetProgress(48);
if (currentBiome() != "generic/savanna") {
createBalancedPlayerForests(
playerPositions,
avoidClasses(clForest, 4, clHill, 2, clMetal, 4, clRock, 4, clFood, 2, clWrenchHead, 2, clBaseResource, 1),
clForest, 4 - Math.round((numPlayers - 2) / 4), 39 - numPlayers * 2
);
}
Engine.SetProgress(50);
const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1));
createForests(
[tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2],
avoidClasses(clPlayer, 18, clForest, 14, clHill, 1, clMetal, 6, clRock, 6, clFood, 6, clWrenchHead, 9),
clForest,
forestTrees);
Engine.SetProgress(60);
g_Map.log("Creating dirt patches");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1, 1],
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWrenchHead, 2),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(63);
g_Map.log("Creating grass patches");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWrenchHead, 2),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(65);
var planetm = 1;
if (currentBiome() == "generic/tropic")
planetm = 8;
createDecoration(
[
[new SimpleObject(aRockMedium, 1, 3, 0, 1)],
[new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
[new SimpleObject(aGrassShort, 1, 2, 0, 1)],
[new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3,6, 1.2, 2.5)],
[new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0, clWrenchHead, 0));
Engine.SetProgress(70);
createBadFood(avoidClasses(clForest, 0, clHill, 1, clMetal, 4, clRock, 4, clFood, 20, clWrenchHead, 5));
Engine.SetProgress(85);
createStragglerTrees(
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(
clForest, 8, clHill, 1, clPlayer,
currentBiome() === "generic/savanna" ? 12 : 30,
clMetal, 6, clRock, 6, clFood, 1, clWrenchHead, 10
),
clForest,
stragglerTrees);
createBalancedPlayerStragglerTrees(
playerPositions,
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(clForest, 8, clHill, 1, clMetal, 6, clRock, 6, clFood, 1, clWrenchHead, 2, clBaseResource, 2),
25 - numPlayers,
clForest
)
Engine.SetProgress(90);
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWrenchHead, 10));
Engine.SetProgress(95);
g_Map.ExportMap();

View File

@ -0,0 +1,11 @@
{
"settings" : {
"Name" : "Wrench",
"Script" : "wrench.js",
"Description" : "Players start side by side, protected by mountains. Extra minerals on border.",
"Preview" : "wrench.png",
"SupportedBiomes": "generic/",
"Keywords": ["badmod"],
"CircularMap" : true
}
}

View File

@ -0,0 +1,286 @@
Engine.LoadLibrary("rmgen");
Engine.LoadLibrary("rmgen-common");
Engine.LoadLibrary("rmbiome");
Engine.LoadLibrary("balancedHelpers");
setSelectedBiome();
const tMainTerrain = g_Terrains.mainTerrain;
const tForestFloor1 = g_Terrains.forestFloor1;
const tForestFloor2 = g_Terrains.forestFloor2;
const tCliff = g_Terrains.cliff;
const tTier1Terrain = g_Terrains.tier1Terrain;
const tTier2Terrain = g_Terrains.tier2Terrain;
const tTier3Terrain = g_Terrains.tier3Terrain;
const tHill = g_Terrains.hill;
const tRoad = g_Terrains.road;
const tRoadWild = g_Terrains.roadWild;
const tTier4Terrain = g_Terrains.tier4Terrain;
const oTree1 = g_Gaia.tree1;
const oTree2 = g_Gaia.tree2;
const oTree3 = g_Gaia.tree3;
const oTree4 = g_Gaia.tree4;
const oTree5 = g_Gaia.tree5;
const oFruitBush = g_Gaia.fruitBush;
const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal;
const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal;
const oStoneLarge = g_Gaia.stoneLarge;
const oStoneSmall = g_Gaia.stoneSmall;
const oMetalLarge = g_Gaia.metalLarge;
const aGrass = g_Decoratives.grass;
const aGrassShort = g_Decoratives.grassShort;
const aRockLarge = g_Decoratives.rockLarge;
const aRockMedium = g_Decoratives.rockMedium;
const aBushMedium = g_Decoratives.bushMedium;
const aBushSmall = g_Decoratives.bushSmall;
const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2];
const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1];
const heightLand = 3;
var g_Map = new RandomMap(heightLand, tMainTerrain);
const mapSize = g_Map.getSize();
const numPlayers = getNumPlayers();
const clPlayer = g_Map.createTileClass();
const clHill = g_Map.createTileClass();
const clWrenchHead = g_Map.createTileClass();
const clForest = g_Map.createTileClass();
const clDirt = g_Map.createTileClass();
const clRock = g_Map.createTileClass();
const clMetal = g_Map.createTileClass();
const clFood = g_Map.createTileClass();
const clBaseResource = g_Map.createTileClass();
const wrenchScaling = 10 * (numPlayers - 2);
const playersCircleRadius = 28 + wrenchScaling;
let playerPlacements = playerPlacementCircle(playersCircleRadius);
let [playersOrder, playerPositions, playerAngles, startingAngle] = playerPlacements;
let playerIDs = [];
for (let i = 0; i < numPlayers; ++i)
playerIDs.push(i+1);
playerPlacements[0] = playerIDs;
placePlayerBases({
"PlayerPlacement": playerPlacements,
"PlayerTileClass": clPlayer,
"BaseResourceClass": clBaseResource,
"CityPatch": {
"outerTerrain": tRoadWild,
"innerTerrain": tRoad
},
"StartingAnimal": {
},
"Berries": {
"template": oFruitBush
},
"Mines": {
"types": [
{ "template": oMetalLarge },
{ "template": oStoneLarge }
]
},
"Trees": {
"template": oTree1,
"count": 5
},
"Decoratives": {
"template": aGrassShort
}
});
Engine.SetProgress(20);
const mapCenter = g_Map.getCenter();
const minesVariation = randIntInclusive(2, 12);
for (let i = 0; i < numPlayers; ++i) {
const playerAngle = playerAngles[i];
const offsetAngle = Math.PI / numPlayers;
const minesRadius = playersCircleRadius + numPlayers * 3 + minesVariation;
const minesPoint = new Vector2D(minesRadius).rotate(- playerAngle - offsetAngle);
const minesArea = new Area(
new DiskPlacer(2.2, Vector2D.add(mapCenter, minesPoint).round()).place(new NullConstraint())
);
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal),
0,
avoidClasses(clForest, 6, clHill, 7),
1, 400,
[minesArea]
);
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock),
0,
avoidClasses(clForest, 6, clHill, 7, clMetal, 6),
1, 400,
[minesArea]
);
const minesClumpPosition = new Vector2D(minesRadius - 15).rotate(- playerAngle - offsetAngle);
const wrenchHeadSize = 20;
createArea(
new DiskPlacer(wrenchHeadSize, Vector2D.add(mapCenter, minesClumpPosition).round()),
[
new TerrainPainter(tCliff),
new SmoothElevationPainter(ELEVATION_SET, 24, 1),
new TileClassPainter(clWrenchHead)
],
avoidClasses(clPlayer, 18, clMetal, 9, clRock, 9)
);
// If map is not tiny, create metal and stone far from each player near edges
if (mapSize > 128) {
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock),
0,
avoidClasses(clForest, 6, clHill, 7),
1, 400,
[new Area(new DiskPlacer(3, Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.42), 0).rotate(- playerAngle + offsetAngle / 3)).round()).place(new NullConstraint()))]
);
createObjectGroupsByAreas(
new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal),
0,
avoidClasses(clForest, 6, clHill, 7),
1, 400,
[new Area(new DiskPlacer(3, Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.42), 0).rotate(- playerAngle - offsetAngle / 3)).round()).place(new NullConstraint()))]
);
}
Engine.SetProgress(20 + i);
}
const handleSize = 30 + 11.5 * (numPlayers - 2);
createArea(
new DiskPlacer(handleSize, mapCenter),
[
new TerrainPainter(tCliff),
new SmoothElevationPainter(ELEVATION_SET, 24, 1),
new TileClassPainter(clHill)
],
avoidClasses(clPlayer, 18, clMetal, 10, clRock, 10)
);
Engine.SetProgress(35);
createBumps(avoidClasses(clPlayer, 20, clMetal, 6, clRock, 6));
Engine.SetProgress(40);
placeBalancedFood(playerPlacements,
avoidClasses(clHill, 1, clMetal, 4, clRock, 4, clBaseResource, 10, clFood, 10, clWrenchHead, 1),
1.2 - numPlayers * 0.1
);
Engine.SetProgress(45);
if (randBool())
createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 42, clHill, 15, clMetal, 10, clRock, 10, clWrenchHead, 20, clFood, 4), clHill, scaleByMapSize(2, 11));
else
createMountains(tCliff, avoidClasses(clPlayer, 42, clHill, 15, clMetal, 10, clRock, 10, clWrenchHead, 20, clFood, 4), clHill, scaleByMapSize(2, 11));
Engine.SetProgress(48);
if (currentBiome() != "generic/savanna") {
createBalancedPlayerForests(
playerPositions,
avoidClasses(clForest, 4, clHill, 2, clMetal, 4, clRock, 4, clFood, 2, clWrenchHead, 2, clBaseResource, 1),
clForest, 4 - Math.round((numPlayers - 2) / 4), 39 - numPlayers * 2
);
}
Engine.SetProgress(50);
const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1));
createForests(
[tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2],
avoidClasses(clPlayer, 18, clForest, 14, clHill, 1, clMetal, 6, clRock, 6, clFood, 6, clWrenchHead, 9),
clForest,
forestTrees);
Engine.SetProgress(60);
g_Map.log("Creating dirt patches");
createLayeredPatches(
[scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)],
[[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]],
[1, 1],
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWrenchHead, 2),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(63);
g_Map.log("Creating grass patches");
createPatches(
[scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)],
tTier4Terrain,
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWrenchHead, 2),
scaleByMapSize(15, 45),
clDirt);
Engine.SetProgress(65);
var planetm = 1;
if (currentBiome() == "generic/tropic")
planetm = 8;
createDecoration(
[
[new SimpleObject(aRockMedium, 1, 3, 0, 1)],
[new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)],
[new SimpleObject(aGrassShort, 1, 2, 0, 1)],
[new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3,6, 1.2, 2.5)],
[new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]
],
[
scaleByMapSize(16, 262),
scaleByMapSize(8, 131),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200),
planetm * scaleByMapSize(13, 200)
],
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0, clWrenchHead, 0));
Engine.SetProgress(70);
createBadFood(avoidClasses(clForest, 0, clHill, 1, clMetal, 4, clRock, 4, clFood, 20, clWrenchHead, 5));
Engine.SetProgress(85);
createStragglerTrees(
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(
clForest, 8, clHill, 1, clPlayer,
currentBiome() === "generic/savanna" ? 12 : 30,
clMetal, 6, clRock, 6, clFood, 1, clWrenchHead, 10
),
clForest,
stragglerTrees);
createBalancedPlayerStragglerTrees(
playerPositions,
[oTree1, oTree2, oTree4, oTree3],
avoidClasses(clForest, 8, clHill, 1, clMetal, 6, clRock, 6, clFood, 1, clWrenchHead, 2, clBaseResource, 2),
25 - numPlayers,
clForest
)
Engine.SetProgress(90);
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWrenchHead, 10));
Engine.SetProgress(95);
g_Map.ExportMap();

View File

@ -0,0 +1,11 @@
{
"settings" : {
"Name" : "Wrench (fixed)",
"Script" : "wrench_fixed.js",
"Description" : "Players start side by side, protected by mountains, extra minerals on border. Positions defined by players",
"Preview" : "wrench.png",
"SupportedBiomes": "generic/",
"Keywords": ["badmod"],
"CircularMap" : true
}
}