Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hellas.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hellas.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hellas.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hellas.png (revision 21228) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hellas.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/maps/random/hellas.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/hellas.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/hellas.js (revision 21228) @@ -0,0 +1,569 @@ +/** + * Heightmap image source: + * Imagery by Jesse Allen, NASA's Earth Observatory, + * using data from the General Bathymetric Chart of the Oceans (GEBCO) + * produced by the British Oceanographic Data Centre. + * https://visibleearth.nasa.gov/view.php?id=73934 + * + * Licensing: Public Domain, https://visibleearth.nasa.gov/useterms.php + * + * The heightmap image is reproduced using: + * wget https://eoimages.gsfc.nasa.gov/images/imagerecords/73000/73934/gebco_08_rev_elev_C1_grey_geo.tif + * lat=37; lon=23; width=7; # including crete + * gdal_translate -projwin $((lon-width/2)) $((lat+width/2)) $((lon+width/2)) $((lat-width/2)) gebco_08_rev_elev_C1_grey_geo.tif hellas.tif + * convert hellas.tif -contrast-stretch 0 hellas.png + * No further changes should be applied to the image to keep it easily interchangeable. + */ + +Engine.LoadLibrary("rmgen"); + +TILE_CENTERED_HEIGHT_MAP = true; + +var mapStyles = [ + // mainland + { + "minMapSize": 0, + "enabled": randBool(0.15), + "landRatio": [0.95, 1] + }, + // lots of water + { + "minMapSize": 384, + "enabled": randBool(1/4), + "landRatio": [0.3, 0.5] + }, + // few water + { + "minMapSize": 192, + "enabled": true, + "landRatio": [0.65, 0.9] + } +]; + +const heightmapHellas = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/hellas.png")); +const biomes = Engine.ReadJSONFile("maps/random/hellas_biomes.json"); + +const heightScale = num => num * g_MapSettings.Size / 320; + +const heightSeaGround = heightScale(-6); +const heightReedsMin = heightScale(-2); +const heightReedsMax = heightScale(-0.5); +const heightShoreline = heightScale(1); +const heightLowlands = heightScale(30); +const heightHighlands = heightScale(60); + +const heightmapMin = 0; +const heightmapMax = 100; + +var g_Map = new RandomMap(0, biomes.lowlands.terrains.main); +var mapSize = g_Map.getSize(); +var mapCenter = g_Map.getCenter(); +var numPlayers = getNumPlayers(); + +var clWater; +var clCliffs; +var clPlayer = g_Map.createTileClass(); +var clForest = g_Map.createTileClass(); +var clDirt = g_Map.createTileClass(); +var clRock = g_Map.createTileClass(); +var clMetal = g_Map.createTileClass(); +var clFood = g_Map.createTileClass(); +var clBaseResource = g_Map.createTileClass(); +var clDock = g_Map.createTileClass(); + +var constraintLowlands = new HeightConstraint(heightShoreline, heightLowlands); +var constraintHighlands = new HeightConstraint(heightLowlands, heightHighlands); +var constraintMountains = new HeightConstraint(heightHighlands, Infinity); + +var [minLandRatio, maxLandRatio] = mapStyles.filter(mapStyle => mapSize >= mapStyle.minMapSize).sort((a, b) => a.enabled - b.enabled).pop().landRatio; +var [minCliffRatio, maxCliffRatio] = [maxLandRatio < 0.75 ? 0 : 0.08, 0.18]; + +var playerIDs = sortAllPlayers(); +var playerPosition; + +// Pick a random subset of the heightmap that meets the mapStyle and has space for all players +var subAreaSize; +var subAreaTopLeft; +while (true) +{ + subAreaSize = Math.floor(randFloat(0.01, 0.2) * heightmapHellas.length); + subAreaTopLeft = new Vector2D(randFloat(0, 1), randFloat(0, 1)).mult(heightmapHellas.length - subAreaSize).floor(); + + let heightmap = extractHeightmap(heightmapHellas, subAreaTopLeft, subAreaSize); + let heightmapPainter = new HeightmapPainter(heightmap, heightmapMin, heightmapMax); + + // Quick area test + let points = new DiskPlacer(heightmap.length / 2 - MAP_BORDER_WIDTH, new Vector2D(1, 1).mult(heightmap.length / 2)).place(new NullConstraint()); + let landArea = 0; + for (let point of points) + if (heightmapPainter.scaleHeight(heightmap[point.x][point.y]) > heightShoreline) + ++landArea; + + let landRatio = landArea / points.length; + g_Map.log("Chosen heightmap at " + uneval(subAreaTopLeft) + " of size " + subAreaSize + ", land-ratio: " + landRatio.toFixed(3)); + if (landRatio < minLandRatio || landRatio > maxLandRatio) + continue; + + g_Map.log("Copying heightmap"); + createArea( + new MapBoundsPlacer(), + heightmapPainter); + + g_Map.log("Measuring land area"); + let passableLandArea = createArea( + new DiskPlacer(fractionToTiles(0.5), mapCenter), + undefined, + new HeightConstraint(heightShoreline, Infinity)); + + if (!passableLandArea) + continue; + + landRatio = passableLandArea.points.length / diskArea(fractionToTiles(0.5)); + g_Map.log("Land ratio: " + landRatio.toFixed(3)); + if (landRatio < minLandRatio || landRatio > maxLandRatio) + continue; + + g_Map.log("Lowering sea ground"); + clWater = g_Map.createTileClass(); + createArea( + new MapBoundsPlacer(), + [ + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), + new TileClassPainter(clWater) + ], + new HeightConstraint(-Infinity, heightShoreline)); + + let cliffsRatio; + while (true) + { + createArea( + new DiskPlacer(fractionToTiles(0.5) - MAP_BORDER_WIDTH, mapCenter), + new SmoothingPainter(1, 0.5, 1)); + Engine.SetProgress(25); + + clCliffs = g_Map.createTileClass(); + + // Marking cliffs + let cliffsArea = createArea( + new MapBoundsPlacer(), + new TileClassPainter(clCliffs), + [ + avoidClasses(clWater, 2), + new SlopeConstraint(2, Infinity) + ]); + + cliffsRatio = cliffsArea.points.length / Math.square(g_Map.getSize()); + g_Map.log("Smoothing heightmap, cliff ratio: " + cliffsRatio.toFixed(3)); + if (cliffsRatio < maxCliffRatio) + break; + } + + if (cliffsRatio < minCliffRatio) + { + g_Map.log("Too few cliffs: " + cliffsRatio); + continue; + } + + if (isNomad()) + break; + + g_Map.log("Finding player locations"); + let players = playerPlacementRandom( + playerIDs, + avoidClasses( + clCliffs, scaleByMapSize(6, 15), + clWater, scaleByMapSize(10, 20))); + + if (players) + { + [playerIDs, playerPosition] = players; + break; + } + + g_Map.log("Too few player locations, starting over"); +} +Engine.SetProgress(35); + +if (!isNomad()) +{ + g_Map.log("Flattening initial CC area..."); + let playerRadius = defaultPlayerBaseRadius() * 0.8; + for (let position of playerPosition) + createArea( + new ClumpPlacer(diskArea(playerRadius), 0.95, 0.6, Infinity, position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), playerRadius / 2)); + Engine.SetProgress(38); +} + +g_Map.log("Painting lowlands"); +createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.lowlands.terrains.main), + constraintLowlands); +Engine.SetProgress(40); + +g_Map.log("Painting highlands"); +createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.highlands.terrains.main), + constraintHighlands); +Engine.SetProgress(45); + +g_Map.log("Painting mountains"); +createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.common.terrains.cliffs), + [ + avoidClasses(clWater, 2), + constraintMountains + ]); +Engine.SetProgress(48); + +g_Map.log("Painting water and shoreline"); +createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.water.terrains.main), + new HeightConstraint(-Infinity, heightShoreline)); +Engine.SetProgress(50); + +g_Map.log("Painting cliffs"); +createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.common.terrains.cliffs), + [ + avoidClasses(clWater, 2), + new SlopeConstraint(2, Infinity) + ]); +Engine.SetProgress(55); + +for (let i = 0; i < numPlayers; ++i) +{ + let localBiome = constraintHighlands.allows(playerPosition[i]) ? biomes.highlands : biomes.lowlands; + placePlayerBase({ + "playerID": playerIDs[i], + "playerPosition": playerPosition[i], + "PlayerTileClass": clPlayer, + "Walls": "towers", + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clPlayer, 4, clWater, 1, clCliffs, 1), + "CityPatch": { + "outerTerrain": biomes.common.terrains.roadWild, + "innerTerrain": biomes.common.terrains.road + }, + "Chicken": { + "template": localBiome.gaia.fauna.sheep, + "groupCount": 1, + "minGroupCount": 4, + "maxGroupCount": 4 + }, + "Berries": { + "template": localBiome.gaia.flora.fruitBush, + "minCount": 3, + "maxCount": 3 + }, + "Mines": { + "types": [ + { "template": biomes.common.gaia.mines.metalLarge }, + { "template": biomes.common.gaia.mines.stoneLarge } + ], + "minAngle": Math.PI / 2, + "maxAngle": Math.PI + }, + "Trees": { + "template": pickRandom(localBiome.gaia.flora.trees), + "count": 15 + } + // No decoratives + }); +} +Engine.SetProgress(60); + +g_Map.log("Marking dock search start location"); +var areaLand = createArea( + new DiskPlacer(fractionToTiles(0.5) - 10, mapCenter), + undefined, + avoidClasses(clWater, 2)); + +g_Map.log("Marking dock search end location"); +var areaWater = createArea( + new DiskPlacer(fractionToTiles(0.5) - 10, mapCenter), + undefined, + stayClasses(clWater, 2)); + +g_Map.log("Creating docks"); +if (areaWater && areaWater.points.length) + for (let i = 0; i < scaleByMapSize(1, 2); ++i) + for (let tryNr = 0; tryNr < 60; ++tryNr) + { + let positionLand = pickRandom(areaLand.points); + let positionDock = areaWater.getClosestPointTo(positionLand); + + if (!g_Map.inMapBounds(positionDock) || !avoidClasses(clDock, 50, clPlayer, 30).allows(positionDock)) + continue; + + g_Map.placeEntityPassable(biomes.shoreline.gaia.dock, 0, positionDock, -positionLand.angleTo(positionDock) + Math.PI / 2); + clDock.add(positionDock); + break; + } +Engine.SetProgress(65); + +let [forestTrees, stragglerTrees] = getTreeCounts(600, 4000, 0.7); +let biomeTreeRatioHighlands = 0.4; +for (let biome of ["lowlands", "highlands"]) + createForests( + [ + biomes[biome].terrains.main, + biomes[biome].terrains.forestFloors[0], + biomes[biome].terrains.forestFloors[1], + biomes[biome].terrains.forests[0], + biomes[biome].terrains.forests[1] + ], + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clPlayer, 20, clForest, 18, clCliffs, 1, clWater, 2) + ], + clForest, + forestTrees * (biome == "highlands" ? biomeTreeRatioHighlands : 1 - biomeTreeRatioHighlands)); +Engine.SetProgress(70); + +g_Map.log("Creating stone mines"); +var minesStone = [ + [new SimpleObject(biomes.common.gaia.mines.stoneLarge, 1, 1, 0, 4)], + [new SimpleObject(biomes.common.gaia.mines.stoneSmall, 2, 3, 1, 3)] +]; +for (let mine of minesStone) + createObjectGroups( + new SimpleGroup(mine, true, clRock), + 0, + [avoidClasses(clForest, 1, clPlayer, 20, clRock, 20, clCliffs, 2, clWater, 2, clDock, 6)], + scaleByMapSize(1, 6), + 40); +Engine.SetProgress(75); + +g_Map.log("Creating metal mines"); +var minesMetal = [ + [new SimpleObject(biomes.common.gaia.mines.metalLarge, 1, 1, 0, 4)], + [new SimpleObject(biomes.common.gaia.mines.metalSmall, 2, 3, 1, 3)] +]; +for (let mine of minesMetal) + createObjectGroups( + new SimpleGroup(mine, true, clMetal), + 0, + [avoidClasses(clForest, 1, clPlayer, 20, clRock, 8, clMetal, 20, clCliffs, 2, clWater, 2, clDock, 6)], + scaleByMapSize(1, 6), + 40); +Engine.SetProgress(80); + +for (let biome of ["lowlands", "highlands"]) + createStragglerTrees( + biomes[biome].gaia.flora.trees, + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clForest, 8, clCliffs, 1, clPlayer, 12, clMetal, 6, clRock, 6, clCliffs, 2, clWater, 2, clDock, 6) + ], + clForest, + stragglerTrees * (biome == "highlands" ? biomeTreeRatioHighlands * 4 : 1 - biomeTreeRatioHighlands)); +Engine.SetProgress(85); + +createFood( + [ + [new SimpleObject(biomes.highlands.gaia.fauna.horse, 3, 5, 0, 4)], + [new SimpleObject(biomes.highlands.gaia.fauna.pony, 2, 3, 0, 4)] + ], + [ + scaleByMapSize(1, 8), + scaleByMapSize(1, 6), + scaleByMapSize(2, 12) + ], + [ + avoidClasses(clForest, 0, clPlayer, 20, clFood, 20, clCliffs, 2, clWater, 2, clRock, 4, clMetal, 4, clDock, 6), + constraintHighlands + ], + clFood); +Engine.SetProgress(90); + +createFood( + [ + [new SimpleObject(biomes.lowlands.gaia.fauna.sheep, 2, 3, 0, 2)], + [new SimpleObject(biomes.lowlands.gaia.fauna.rabbit, 2, 3, 0, 2)], + [new SimpleObject(biomes.lowlands.gaia.flora.fruitBush, 5, 7, 0, 4)] + ], + [ + scaleByMapSize(1, 8), + scaleByMapSize(2, 12), + scaleByMapSize(1, 6) + ], + [ + avoidClasses(clForest, 0, clPlayer, 20, clFood, 20, clCliffs, 2, clWater, 2, clRock, 4, clMetal, 4, clDock, 6), + constraintLowlands + ], + clFood); +Engine.SetProgress(95); + +createFood( + [ + [new SimpleObject(biomes.highlands.gaia.fauna.goat, 3, 5, 0, 4)] + ], + [ + 3 * numPlayers + ], + [ + avoidClasses(clForest, 1, clPlayer, 20, clFood, 20, clCliffs, 1, clRock, 4, clMetal, 4, clDock, 6), + constraintMountains + ], + clFood); + +g_Map.log("Creating hawk"); +for (let i = 0; i < scaleByMapSize(0, 2); ++i) + g_Map.placeEntityAnywhere(biomes.highlands.gaia.fauna.hawk, 0, mapCenter, randomAngle()); + +g_Map.log("Creating fish"); +createObjectGroups( + new SimpleGroup([new SimpleObject(biomes.water.gaia.fauna.fish, 1, 1, 0, 3)], true, clFood), + 0, + [stayClasses(clWater, 1), avoidClasses(clFood, 8, clDock, 6)], + scaleByMapSize(15, 50), + 100); +Engine.SetProgress(95); + +g_Map.log("Creating grass patches"); +for (let biome of ["lowlands", "highlands"]) + for (let patch of biomes[biome].terrains.patches) + createPatches( + [scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + patch, + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clForest, 0, clDirt, 5, clPlayer, 12, clCliffs, 2, clWater, 2), + ], + scaleByMapSize(15, 45) / biomes[biome].terrains.patches.length, + clDirt); +Engine.SetProgress(95); + +for (let biome of ["lowlands", "highlands"]) +{ + createDecoration( + [ + [new SimpleObject(actorTemplate(biomes[biome].actors.mushroom), 1, 4, 1, 2)], + [ + new SimpleObject(actorTemplate(biomes.common.actors.grass), 2, 4, 0, 1.8), + new SimpleObject(actorTemplate(biomes.common.actors.grassShort), 3,6, 1.2, 2.5) + ], + [ + new SimpleObject(actorTemplate(biomes.common.actors.bushMedium), 1, 2, 0, 2), + new SimpleObject(actorTemplate(biomes.common.actors.bushSmall), 2, 4, 0, 2) + ] + ], + [ + scaleByMapSize(20, 300), + scaleByMapSize(13, 200), + scaleByMapSize(13, 200), + scaleByMapSize(13, 200) + ], + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clCliffs, 1, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), + ]); + + createDecoration( + [ + biomes[biome].actors.stones.map(template => new SimpleObject(actorTemplate(template), 1, 3, 0, 1)) + ], + [ + biomes[biome].actors.stones.map(template => scaleByMapSize(2, 40) * randIntInclusive(1, 3)) + ], + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clWater, 4, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), + ]); +} +Engine.SetProgress(70); + +g_Map.log("Creating temple"); +createObjectGroups( + new SimpleGroup([new SimpleObject(biomes.highlands.gaia.athen.temple, 1, 1, 0, 0)], true), + 0, + [ + avoidClasses(clCliffs, 4, clWater, 4, clPlayer, 40, clForest, 4, clRock, 4, clMetal, 4), + constraintHighlands + ], + 1, + 200); + +g_Map.log("Creating statues"); +createObjectGroups( + new SimpleGroup([new SimpleObject(actorTemplate(biomes.lowlands.actors.athen.statue), 1, 1, 0, 0)], true), + 0, + [ + avoidClasses(clCliffs, 2, clWater, 4, clPlayer, 30, clForest, 1, clRock, 8, clMetal, 8, clDock, 6), + constraintLowlands + ], + scaleByMapSize(1, 2), + 50); + +g_Map.log("Creating campfire"); +createObjectGroups( + new SimpleGroup([new SimpleObject(actorTemplate(biomes.common.actors.campfire), 1, 1, 0, 0)], true), + 0, + [avoidClasses(clCliffs, 2, clWater, 4, clPlayer, 30, clForest, 1, clRock, 8, clMetal, 8, clDock, 6)], + scaleByMapSize(0, 2), + 50); + +g_Map.log("Creating oxybeles"); +createObjectGroups( + new SimpleGroup([new SimpleObject(biomes.highlands.gaia.athen.oxybeles, 1, 1, 0, 0)], true), + 0, + [ + avoidClasses(clCliffs, 2, clPlayer, 30, clForest, 1, clRock, 4, clMetal, 4), + constraintHighlands + ], + scaleByMapSize(0, 2), + 100); + +g_Map.log("Creating handcart"); +createObjectGroups( + new SimpleGroup([new SimpleObject(actorTemplate(biomes.highlands.actors.handcart), 1, 1, 0, 0)], true), + 0, + [ + avoidClasses(clCliffs, 1, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), + constraintHighlands + ], + scaleByMapSize(1, 4), + 50); + +g_Map.log("Creating water log"); +createObjectGroups( + new SimpleGroup([new SimpleObject(actorTemplate(biomes.water.actors.waterlog), 1, 1, 0, 0)], true), + 0, + [stayClasses(clWater, 4)], + scaleByMapSize(1, 2), + 10); + +g_Map.log("Creating reeds"); +createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(actorTemplate(biomes.shoreline.actors.reeds), 5, 12, 1, 4), + new SimpleObject(actorTemplate(biomes.shoreline.actors.lillies), 1, 2, 1, 5) + ], + false, + clDirt), + 0, + new HeightConstraint(heightReedsMin, heightReedsMax), + scaleByMapSize(10, 25), + 20); + +placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2, clCliffs, 2, clWater, 2)); +Engine.SetProgress(95); + +setWaterColor(0.024, 0.212, 0.024); +setWaterTint(0.133, 0.725, 0.855); +setWaterMurkiness(0.8); +setWaterWaviness(3); +setFogFactor(0); +setPPEffect("hdr"); +setPPSaturation(0.51); +setPPContrast(0.62); +setPPBloom(0.12); + +g_Map.ExportMap(); Property changes on: ps/trunk/binaries/data/mods/public/maps/random/hellas.js ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/maps/random/hellas.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/hellas.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/hellas.json (revision 21228) @@ -0,0 +1,10 @@ +{ + "settings" : { + "Name" : "Hellas", + "Script" : "hellas.js", + "Description" : "Hellas, home to the Greeks and through them birthplace to the foundation of western civilization. Yet the land lacks unity, countless cit-states vie for dominance. Will you lead your polis to glory and greatness or see it fall into oblivion, erased from the histories?", + "Keywords": ["new"], + "Preview" : "hellas.png", + "CircularMap": true + } +} Property changes on: ps/trunk/binaries/data/mods/public/maps/random/hellas.json ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/maps/random/hellas.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/maps/random/hellas.png =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/hellas.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/hellas.png (revision 21228) Property changes on: ps/trunk/binaries/data/mods/public/maps/random/hellas.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/maps/random/hellas_biomes.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/hellas_biomes.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/hellas_biomes.json (revision 21228) @@ -0,0 +1,187 @@ +{ + "water": { + "terrains": { + "main": "medit_sand_wet" + }, + "gaia": { + "fauna": { + "fish": "gaia/fauna_fish" + } + }, + "actors": { + "waterlog": "props/flora/water_log" + } + }, + "shoreline": { + "gaia": { + "dock": "structures/athen_dock" + }, + "actors": { + "reeds": "props/flora/reeds_pond_lush_b", + "lillies": "props/flora/water_lillies" + } + }, + "common": { + "terrains": { + "cliffs": [ + "medit_cliff_italia_grass", + "medit_cliff_grass", + "medit_cliff_aegean", + "medit_cliff_italia" + ], + "road": "medit_city_tile", + "roadWild": "medit_city_tile" + }, + "gaia": { + "mines": { + "stoneLarge": "gaia/geology_stonemine_medit_quarry", + "stoneSmall": "gaia/geology_stone_mediterranean", + "metalLarge": "gaia/geology_metal_mediterranean_slabs", + "metalSmall": "gaia/geology_metal_mediterranean" + } + }, + "actors": { + "grass": "props/flora/grass_soft_large_tall", + "grassShort": "props/flora/grass_soft_large", + "bushMedium": "props/flora/bush_medit_me", + "bushSmall": "props/flora/bush_medit_sm", + "campfire": "props/special/eyecandy/campfire" + } + }, + "lowlands": { + "terrains": { + "main": [ + "medit_grass_field_a", + "medit_grass_field_b", + "grass1_spring", + "grass_field", + "grass_field_a" + ], + "forests": [ + [ + "medit_grass_shrubs|gaia/flora_tree_oak_large", + "medit_grass_shrubs|gaia/flora_tree_oak", + "medit_grass_shrubs" + ], + [ + "medit_grass_field|gaia/flora_tree_euro_beech", + "medit_grass_field|gaia/flora_tree_poplar", + "medit_grass_field" + ] + ], + "forestFloors": [ + "medit_grass_field", + "medit_grass_shrubs" + ], + "patches": [ + "medit_grass_field_b", + "medit_grass_field_brown", + "medit_grass_field_dry", + "medit_shrubs" + ] + }, + "gaia": { + "flora": { + "trees": [ + "gaia/flora_tree_euro_beech", + "gaia/flora_tree_poplar", + "gaia/flora_tree_oak", + "gaia/flora_tree_oak_large" + ], + "fruitBush": "gaia/flora_bush_grapes" + }, + "fauna": { + "sheep": "gaia/fauna_sheep", + "rabbit": "gaia/fauna_rabbit" + }, + "athen": { + "columns": "gaia/ruins/column_doric", + "stoa": "other/hellenic_stoa" + } + }, + "actors": + { + "flora": { + "flowers": [ + "flora/grass_field_flowering_tall", + "flora/grass_medit_flowering_tall" + ], + "bushes": [ + "flora/foliagebush", + "flora/forage_grapes_prop" + ] + }, + "stones": [ + "geology/highland1_moss", + "geology/highland2_moss" + ], + "mushroom": "fungi/small_grey", + "athen": { + "statue": "props/special/eyecandy/statue_aphrodite_huge" + } + } + }, + "highlands": { + "terrains": { + "main": [ + "alpine_grass_c", + "alpine_grass_d", + "alpine_grass_e" + ], + "forests": [ + [ + "alpine_grass_e|gaia/flora_tree_cypress", + "alpine_grass_e|gaia/flora_tree_poplar_lombardy", + "alpine_grass_e" + ], + [ + "alpine_grass_d|gaia/flora_tree_cypress", + "alpine_grass_d|gaia/flora_tree_aleppo_pine", + "alpine_grass_d" + ] + ], + "forestFloors": [ + "alpine_grass_d", + "alpine_grass_e" + ], + "patches": [ + "medit_grass_wild" + ] + }, + "gaia": { + "flora": { + "trees": [ + "gaia/flora_tree_poplar_lombardy", + "gaia/flora_tree_cypress", + "gaia/flora_tree_aleppo_pine" + ], + "fruitBush": "gaia/flora_bush_berry" + }, + "fauna": { + "goat": "gaia/fauna_goat", + "hawk": "gaia/fauna_hawk", + "horse": "gaia/fauna_horse", + "pony": "gaia/fauna_pony" + }, + "athen": { + "temple": "structures/athen_temple", + "oxybeles": "units/athen_mechanical_siege_oxybeles_unpacked" + } + }, + "actors": { + "stones": [ + "stone/medit_med", + "geology/stone_granite_greek_large", + "geology/stone_granite_greek_med", + "geology/stone_granite_greek_peak", + "geology/stone_granite_greek_small", + "geology/stone_granite_large", + "geology/stone_granite_med", + "geology/stone_granite_peak", + "geology/stone_granite_small" + ], + "mushroom": "fungi/medium_beige_reversed", + "handcart": "props/special/eyecandy/handcart_1_broken" + } + } +} Property changes on: ps/trunk/binaries/data/mods/public/maps/random/hellas_biomes.json ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js (revision 21227) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js (revision 21228) @@ -1,269 +1,289 @@ const TERRAIN_SEPARATOR = "|"; const SEA_LEVEL = 20.0; const HEIGHT_UNITS_PER_METRE = 92; /** * Number of impassable, unexplorable tiles at the map border. */ const MAP_BORDER_WIDTH = 3; const g_DamageTypes = new DamageTypes(); /** * Constants needed for heightmap_manipulation.js */ const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE; // Engine limit, Roughly 700 meters const MIN_HEIGHT = - SEA_LEVEL; /** * Length of one tile of the terrain grid in metres. * Useful to transform footprint sizes of templates to the coordinate system used by getMapSize. */ const TERRAIN_TILE_SIZE = Engine.GetTerrainTileSize(); const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL; /** * Default angle for buildings. */ const BUILDING_ORIENTATION = -1/4 * Math.PI; const g_CivData = deepfreeze(loadCivFiles(false)); /** * Sets whether setHeight operates on the center of a tile or on the vertices. */ var TILE_CENTERED_HEIGHT_MAP = false; +function actorTemplate(templateName) +{ + return "actor|" + templateName + ".xml"; +} + function fractionToTiles(f) { return g_MapSettings.Size * f; } function tilesToFraction(t) { return t / g_MapSettings.Size; } function scaleByMapSize(min, max, minMapSize = 128, maxMapSize = 512) { return min + (max - min) * (g_MapSettings.Size - minMapSize) / (maxMapSize - minMapSize); } function randomPositionOnTile(tilePosition) { return Vector2D.add(tilePosition, new Vector2D(randFloat(0, 1), randFloat(0, 1))); } /** * Retries the given function with those arguments as often as specified. */ function retryPlacing(placeFunc, retryFactor, amount, getResult, behaveDeprecated = false) { let maxFail = amount * retryFactor; let results = []; let good = 0; let bad = 0; while (good < amount && bad <= maxFail) { let result = placeFunc(); if (result !== undefined || behaveDeprecated) { ++good; if (getResult) results.push(result); } else ++bad; } return getResult ? results : good; } // TODO this is a hack to simulate the old behaviour of those functions // until all old maps are changed to use the correct version of these functions function createObjectGroupsDeprecated(group, player, constraint, amount, retryFactor = 10) { return createObjectGroups(group, player, constraint, amount, retryFactor, true); } function createObjectGroupsByAreasDeprecated(group, player, constraint, amount, retryFactor, areas) { return createObjectGroupsByAreas(group, player, constraint, amount, retryFactor, areas, true); } /** * Attempts to place the given number of areas in random places of the map. * Returns actually placed areas. */ function createAreas(centeredPlacer, painter, constraint, amount, retryFactor = 10) { let placeFunc = function() { centeredPlacer.setCenterPosition(g_Map.randomCoordinate(false)); return createArea(centeredPlacer, painter, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, true, false); } /** * Attempts to place the given number of areas in random places of the given areas. * Returns actually placed areas. */ function createAreasInAreas(centeredPlacer, painter, constraint, amount, retryFactor, areas) { let placeFunc = function() { centeredPlacer.setCenterPosition(pickRandom(pickRandom(areas).points)); return createArea(centeredPlacer, painter, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, true, false); } /** * Attempts to place the given number of groups in random places of the map. * Returns the number of actually placed groups. */ function createObjectGroups(group, player, constraint, amount, retryFactor = 10, behaveDeprecated = false) { let placeFunc = function() { group.setCenterPosition(g_Map.randomCoordinate(true)); return createObjectGroup(group, player, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, false, behaveDeprecated); } /** * Attempts to place the given number of groups in random places of the given areas. * Returns the number of actually placed groups. */ function createObjectGroupsByAreas(group, player, constraint, amount, retryFactor, areas, behaveDeprecated = false) { let placeFunc = function() { group.setCenterPosition(pickRandom(pickRandom(areas).points)); return createObjectGroup(group, player, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, false, behaveDeprecated); } function createTerrain(terrain) { return typeof terrain == "string" ? new SimpleTerrain(...terrain.split(TERRAIN_SEPARATOR)) : new RandomTerrain(terrain.map(t => createTerrain(t))); } /** * Constructs a new Area shaped by the Placer meeting the Constraints and calls the Painters there. * Supports both Centered and Non-Centered Placers. */ function createArea(placer, painters, constraints) { let points = placer.place(new AndConstraint(constraints)); if (!points) return undefined; let area = g_Map.createArea(points); new MultiPainter(painters).paint(area); return area; } /** * @param mode is one of the HeightPlacer constants determining whether to exclude the min/max elevation. */ function paintTerrainBasedOnHeight(minHeight, maxHeight, mode, terrain) { createArea( new HeightPlacer(mode, minHeight, maxHeight), new TerrainPainter(terrain)); } function paintTileClassBasedOnHeight(minHeight, maxHeight, mode, tileClass) { createArea( new HeightPlacer(mode, minHeight, maxHeight), new TileClassPainter(tileClass)); } function unPaintTileClassBasedOnHeight(minHeight, maxHeight, mode, tileClass) { createArea( new HeightPlacer(mode, minHeight, maxHeight), new TileClassUnPainter(tileClass)); } /** * Places the Entities of the given Group if they meet the Constraints * and sets the given player as the owner. */ function createObjectGroup(group, player, constraints) { return group.place(player, new AndConstraint(constraints)); } /** * Create an avoid constraint for the given classes by the given distances */ function avoidClasses(/*class1, dist1, class2, dist2, etc*/) { let ar = []; for (let i = 0; i < arguments.length/2; ++i) ar.push(new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1])); // Return single constraint if (ar.length == 1) return ar[0]; return new AndConstraint(ar); } /** * Create a stay constraint for the given classes by the given distances */ function stayClasses(/*class1, dist1, class2, dist2, etc*/) { let ar = []; for (let i = 0; i < arguments.length/2; ++i) ar.push(new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1])); // Return single constraint if (ar.length == 1) return ar[0]; return new AndConstraint(ar); } /** * Create a border constraint for the given classes by the given distances */ function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/) { let ar = []; for (let i = 0; i < arguments.length/3; ++i) ar.push(new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2])); // Return single constraint if (ar.length == 1) return ar[0]; return new AndConstraint(ar); } +/** + * Returns a subset of the given heightmap. + */ +function extractHeightmap(heightmap, topLeft, size) +{ + let result = []; + for (let x = 0; x < size; ++x) + { + result[x] = new Float32Array(size); + for (let y = 0; y < size; ++y) + result[x][y] = heightmap[x + topLeft.x][y + topLeft.y]; + } + return result; +} + function convertHeightmap1Dto2D(heightmap) { let result = []; let hmSize = Math.sqrt(heightmap.length); for (let x = 0; x < hmSize; ++x) { result[x] = new Float32Array(hmSize); for (let y = 0; y < hmSize; ++y) result[x][y] = heightmap[y * hmSize + x]; } return result; }