Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/randombiome.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/randombiome.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/randombiome.js (revision 19443) @@ -1,871 +1,871 @@ const g_BiomeTemperate = 1; const g_BiomeSnowy = 2; const g_BiomeDesert = 3; const g_BiomeAlpine = 4; const g_BiomeMediterranean = 5; const g_BiomeSavanna = 6; const g_BiomeTropic = 7; const g_BiomeAutumn = 8; var g_BiomeID = g_BiomeTemperate; var g_Terrains = { "mainTerrain": ["temp_grass_long_b"], "forestFloor1": "temp_forestfloor_pine", "forestFloor2": "temp_plants_bog", "tier1Terrain": "temp_grass_d", "tier2Terrain": "temp_grass_c", "tier3Terrain": "temp_grass_clovers_2", "tier4Terrain": "temp_grass_plants", "cliff": ["temp_cliff_a", "temp_cliff_b"], "hill": ["temp_dirt_gravel", "temp_dirt_gravel_b"], "dirt": ["temp_dirt_gravel", "temp_dirt_gravel_b"], "road": "temp_road", "roadWild": "temp_road_overgrown", "shoreBlend": "temp_mud_plants", "shore": "sand_grass_25", "water": "medit_sand_wet" }; var g_Gaia = { "tree1": "gaia/flora_tree_oak", "tree2": "gaia/flora_tree_oak_large", "tree3": "gaia/flora_tree_apple", "tree4": "gaia/flora_tree_pine", "tree5": "gaia/flora_tree_aleppo_pine", "fruitBush": "gaia/flora_bush_berry", "chicken": "gaia/fauna_chicken", "fish": "gaia/fauna_fish", "mainHuntableAnimal": "gaia/fauna_deer", "secondaryHuntableAnimal": "gaia/fauna_sheep", "stoneLarge": "gaia/geology_stonemine_medit_quarry", "stoneSmall": "gaia/geology_stone_mediterranean", "metalLarge": "gaia/geology_metal_mediterranean_slabs" }; var g_Decoratives = { "grass": "actor|props/flora/grass_soft_large_tall.xml", "grassShort": "actor|props/flora/grass_soft_large.xml", "reeds": "actor|props/flora/reeds_pond_lush_a.xml", "lillies": "actor|props/flora/pond_lillies_large.xml", "rockLarge": "actor|geology/stone_granite_large.xml", "rockMedium": "actor|geology/stone_granite_med.xml", "bushMedium": "actor|props/flora/bush_medit_me.xml", "bushSmall": "actor|props/flora/bush_medit_sm.xml", "tree": "actor|flora/trees/oak.xml" }; /** * Randomizes environment, optionally excluding some biome IDs. */ function randomizeBiome(avoid = []) { let biomeIndex; do - biomeIndex = randInt(1, 8); + biomeIndex = randIntInclusive(1, 8); while (avoid.indexOf(biomeIndex) != -1); setBiome(biomeIndex); return biomeIndex; } function setBiome(biomeIndex) { setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 6, PI / 3)); setUnitsAmbientColor(0.57, 0.58, 0.55); setTerrainAmbientColor(0.447059, 0.509804, 0.54902); g_BiomeID = biomeIndex; if (g_BiomeID == g_BiomeTemperate) { // temperate ocean blue, a bit too deep and saturated perhaps but it looks nicer. // this assumes ocean settings, maps that aren't oceans should reset. setWaterColor(0.114, 0.192, 0.463); setWaterTint(0.255, 0.361, 0.651); setWaterWaviness(5.5); setWaterMurkiness(0.83); setFogThickness(0.25); setFogFactor(0.4); setPPEffect("hdr"); setPPSaturation(0.62); setPPContrast(0.62); setPPBloom(0.3); g_Terrains = { "cliff": ["temp_cliff_a", "temp_cliff_b"], "hill": ["temp_dirt_gravel", "temp_dirt_gravel_b"], "dirt": ["temp_dirt_gravel", "temp_dirt_gravel_b"], "road": "temp_road", "roadWild": "temp_road_overgrown", "shoreBlend": "temp_mud_plants", "shore": "sand_grass_25", "water": "medit_sand_wet" }; if (randBool()) { g_Terrains.mainTerrain = "alpine_grass"; g_Terrains.forestFloor1 = "temp_forestfloor_pine"; g_Terrains.forestFloor2 = "temp_grass_clovers_2"; g_Terrains.tier1Terrain = "alpine_grass_a"; g_Terrains.tier2Terrain = "alpine_grass_b"; g_Terrains.tier3Terrain = "alpine_grass_c"; g_Terrains.tier4Terrain = "temp_grass_mossy"; } else { g_Terrains.mainTerrain = "temp_grass_long_b"; g_Terrains.forestFloor1 = "temp_forestfloor_pine"; g_Terrains.forestFloor2 = "temp_plants_bog"; g_Terrains.tier1Terrain = "temp_grass_d"; g_Terrains.tier2Terrain = "temp_grass_c"; g_Terrains.tier3Terrain = "temp_grass_clovers_2"; g_Terrains.tier4Terrain = "temp_grass_plants"; } g_Gaia = { "fruitBush": "gaia/flora_bush_berry", "chicken": "gaia/fauna_chicken", "fish": "gaia/fauna_fish", "mainHuntableAnimal": "gaia/fauna_deer", "secondaryHuntableAnimal": "gaia/fauna_sheep", "stoneLarge": "gaia/geology_stonemine_temperate_quarry", "stoneSmall": "gaia/geology_stone_temperate", "metalLarge": "gaia/geology_metal_temperate_slabs" }; - var random_trees = randInt(3); - if (random_trees == 0) + var random_trees = randIntInclusive(1, 3); + if (random_trees == 1) { g_Gaia.tree1 = "gaia/flora_tree_oak"; g_Gaia.tree2 = "gaia/flora_tree_oak_large"; } - else if (random_trees == 1) + else if (random_trees == 2) { g_Gaia.tree1 = "gaia/flora_tree_poplar"; g_Gaia.tree2 = "gaia/flora_tree_poplar"; } else { g_Gaia.tree1 = "gaia/flora_tree_euro_beech"; g_Gaia.tree2 = "gaia/flora_tree_euro_beech"; } g_Gaia.tree3 = "gaia/flora_tree_apple"; - random_trees = randInt(3); - if (random_trees == 0) + random_trees = randIntInclusive(1, 3); + if (random_trees == 1) { g_Gaia.tree4 = "gaia/flora_tree_pine"; g_Gaia.tree5 = "gaia/flora_tree_aleppo_pine"; } - else if (random_trees == 1) + else if (random_trees == 2) { g_Gaia.tree4 = "gaia/flora_tree_pine"; g_Gaia.tree5 = "gaia/flora_tree_pine"; } else { g_Gaia.tree4 = "gaia/flora_tree_aleppo_pine"; g_Gaia.tree5 = "gaia/flora_tree_aleppo_pine"; } g_Decoratives = { "grass": "actor|props/flora/grass_soft_large_tall.xml", "grassShort": "actor|props/flora/grass_soft_large.xml", "reeds": "actor|props/flora/reeds_pond_lush_a.xml", "lillies": "actor|props/flora/water_lillies.xml", "rockLarge": "actor|geology/stone_granite_large.xml", "rockMedium": "actor|geology/stone_granite_med.xml", "bushMedium": "actor|props/flora/bush_medit_me.xml", "bushSmall": "actor|props/flora/bush_medit_sm.xml", "tree": "actor|flora/trees/oak.xml" }; } else if (g_BiomeID == g_BiomeSnowy) { setSunColor(0.550, 0.601, 0.644); // a little darker // Water is a semi-deep blue, fairly wavy, fairly murky for an ocean. // this assumes ocean settings, maps that aren't oceans should reset. setWaterColor(0.067, 0.212, 0.361); setWaterTint(0.4, 0.486, 0.765); setWaterWaviness(5.5); setWaterMurkiness(0.83); g_Terrains = { "mainTerrain": ["polar_snow_b", "snow grass 75", "snow rocks", "snow forest"], "forestFloor1": "polar_tundra_snow", "forestFloor2": "polar_tundra_snow", "cliff": ["alpine_cliff_a", "alpine_cliff_b"], "tier1Terrain": "polar_snow_a", "tier2Terrain": "polar_ice_snow", "tier3Terrain": "polar_ice", "tier4Terrain": "snow grass 2", "hill": ["polar_snow_rocks", "polar_cliff_snow"], "dirt": "snow grass 2", "road": "new_alpine_citytile", "roadWild": "polar_ice_cracked", "shoreBlend": "polar_ice", "shore": "alpine_shore_rocks_icy", "water": "alpine_shore_rocks" }; g_Gaia = { "tree1": "gaia/flora_tree_pine_w", "tree2": "gaia/flora_tree_pine_w", "tree3": "gaia/flora_tree_pine_w", "tree4": "gaia/flora_tree_pine_w", "tree5": "gaia/flora_tree_pine", "fruitBush": "gaia/flora_bush_berry", "chicken": "gaia/fauna_chicken", "mainHuntableAnimal": "gaia/fauna_muskox", "fish": "gaia/fauna_fish_tuna", "secondaryHuntableAnimal": "gaia/fauna_walrus", "stoneLarge": "gaia/geology_stonemine_alpine_quarry", "stoneSmall": "gaia/geology_stone_alpine_a", "metalLarge": "gaia/geology_metal_alpine_slabs" }; g_Decoratives = { "grass": "actor|props/flora/grass_soft_dry_small_tall.xml", "grassShort": "actor|props/flora/grass_soft_dry_large.xml", "reeds": "actor|props/flora/reeds_pond_dry.xml", "lillies": "actor|geology/stone_granite_large.xml", "rockLarge": "actor|geology/stone_granite_large.xml", "rockMedium": "actor|geology/stone_granite_med.xml", "bushMedium": "actor|props/flora/bush_desert_dry_a.xml", "bushSmall": "actor|props/flora/bush_desert_dry_a.xml", "tree": "actor|flora/trees/pine_w.xml" }; setFogFactor(0.6); setFogThickness(0.21); setPPSaturation(0.37); setPPEffect("hdr"); } else if (g_BiomeID == g_BiomeDesert) { setSunColor(0.733, 0.746, 0.574); // Went for a very clear, slightly blue-ish water in this case, basically no waves. setWaterColor(0, 0.227, 0.843); setWaterTint(0, 0.545, 0.859); setWaterWaviness(1); setWaterMurkiness(0.22); setFogFactor(0.5); setFogThickness(0.0); setFogColor(0.852, 0.746, 0.493); setPPEffect("hdr"); setPPContrast(0.67); setPPSaturation(0.42); setPPBloom(0.23); g_Terrains = { "mainTerrain": ["desert_dirt_rough", "desert_dirt_rough_2", "desert_sand_dunes_50", "desert_sand_smooth"], "forestFloor1": "forestfloor_dirty", "forestFloor2": "desert_forestfloor_palms", "cliff": ["desert_cliff_1", "desert_cliff_2", "desert_cliff_3", "desert_cliff_4", "desert_cliff_5"], "tier1Terrain": "desert_dirt_rough", "tier2Terrain": "desert_dirt_rocks_1", "tier3Terrain": "desert_dirt_rocks_2", "tier4Terrain": "desert_dirt_rough", "hill": ["desert_dirt_rocks_1", "desert_dirt_rocks_2", "desert_dirt_rocks_3"], "dirt": ["desert_lakebed_dry", "desert_lakebed_dry_b"], "road": "desert_city_tile", "roadWild": "desert_city_tile", "shoreBlend": "desert_shore_stones", "shore": "desert_sand_smooth", "water": "desert_sand_wet" }; g_Gaia = { "fruitBush": "gaia/flora_bush_grapes", "chicken": "gaia/fauna_chicken", "mainHuntableAnimal": "gaia/fauna_camel", "fish": "gaia/fauna_fish", "secondaryHuntableAnimal": "gaia/fauna_gazelle", "stoneLarge": "gaia/geology_stonemine_desert_quarry", "stoneSmall": "gaia/geology_stone_desert_small", "metalLarge": "gaia/geology_metal_desert_slabs" }; if (randBool()) { g_Gaia.tree1 = "gaia/flora_tree_cretan_date_palm_short"; g_Gaia.tree2 = "gaia/flora_tree_cretan_date_palm_tall"; } else { g_Gaia.tree1 = "gaia/flora_tree_date_palm"; g_Gaia.tree2 = "gaia/flora_tree_date_palm"; } g_Gaia.tree3 = "gaia/flora_tree_fig"; if (randBool()) { g_Gaia.tree4 = "gaia/flora_tree_tamarix"; g_Gaia.tree5 = "gaia/flora_tree_tamarix"; } else { g_Gaia.tree4 = "gaia/flora_tree_senegal_date_palm"; g_Gaia.tree5 = "gaia/flora_tree_senegal_date_palm"; } g_Decoratives = { "grass": "actor|props/flora/grass_soft_dry_small_tall.xml", "grassShort": "actor|props/flora/grass_soft_dry_large.xml", "reeds": "actor|props/flora/reeds_pond_lush_a.xml", "lillies": "actor|props/flora/reeds_pond_lush_b.xml", "rockLarge": "actor|geology/stone_desert_med.xml", "rockMedium": "actor|geology/stone_desert_med.xml", "bushMedium": "actor|props/flora/bush_desert_dry_a.xml", "bushSmall": "actor|props/flora/bush_desert_dry_a.xml", "tree": "actor|flora/trees/palm_date.xml" }; } else if (g_BiomeID == g_BiomeAlpine) { // simulates an alpine lake, fairly deep. // this is not intended for a clear running river, or even an ocean. setWaterColor(0.0, 0.047, 0.286); // dark majestic blue setWaterTint(0.471, 0.776, 0.863); // light blue setWaterMurkiness(0.82); setWaterWaviness(2); setFogThickness(0.26); setFogFactor(0.4); setPPEffect("hdr"); setPPSaturation(0.48); setPPContrast(0.53); setPPBloom(0.12); g_Terrains = { "mainTerrain": ["alpine_dirt_grass_50"], "forestFloor1": "alpine_forrestfloor", "forestFloor2": "alpine_forrestfloor", "cliff": ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"], "tier1Terrain": "alpine_dirt", "tier2Terrain": ["alpine_grass_snow_50", "alpine_dirt_snow", "alpine_dirt_snow"], "tier3Terrain": ["alpine_snow_a", "alpine_snow_b"], "tier4Terrain": "new_alpine_grass_a", "hill": "alpine_cliff_snow", "dirt": ["alpine_dirt", "alpine_grass_d"], "road": "new_alpine_citytile", "roadWild": "new_alpine_citytile", "shoreBlend": "alpine_shore_rocks", "shore": "alpine_shore_rocks_grass_50", "water": "alpine_shore_rocks" }; g_Gaia = { "tree1": "gaia/flora_tree_pine", "tree2": "gaia/flora_tree_pine", "tree3": "gaia/flora_tree_pine", "tree4": "gaia/flora_tree_pine", "tree5": "gaia/flora_tree_pine", "fruitBush": "gaia/flora_bush_berry", "chicken": "gaia/fauna_chicken", "mainHuntableAnimal": "gaia/fauna_goat", "fish": "gaia/fauna_fish_tuna", "secondaryHuntableAnimal": "gaia/fauna_deer", "stoneLarge": "gaia/geology_stonemine_alpine_quarry", "stoneSmall": "gaia/geology_stone_alpine_a", "metalLarge": "gaia/geology_metal_alpine_slabs" }; g_Decoratives = { "grass": "actor|props/flora/grass_soft_small_tall.xml", "grassShort": "actor|props/flora/grass_soft_large.xml", "reeds": "actor|props/flora/reeds_pond_dry.xml", "lillies": "actor|geology/stone_granite_large.xml", "rockLarge": "actor|geology/stone_granite_large.xml", "rockMedium": "actor|geology/stone_granite_med.xml", "bushMedium": "actor|props/flora/bush_desert_a.xml", "bushSmall": "actor|props/flora/bush_desert_a.xml", "tree": "actor|flora/trees/pine.xml" }; } else if (g_BiomeID == g_BiomeMediterranean) { // Guess what, this is based on the colors of the mediterranean sea. setWaterColor(0.024,0.212,0.024); setWaterTint(0.133, 0.725,0.855); setWaterWaviness(3); setWaterMurkiness(0.8); setFogFactor(0.3); setFogThickness(0.25); setPPEffect("hdr"); setPPContrast(0.62); setPPSaturation(0.51); setPPBloom(0.12); g_Terrains = { "mainTerrain": ["medit_grass_field_a", "medit_grass_field_b"], "forestFloor1": "medit_grass_field", "forestFloor2": "medit_grass_shrubs", "cliff": ["medit_cliff_grass", "medit_cliff_greek", "medit_cliff_greek_2", "medit_cliff_aegean", "medit_cliff_italia", "medit_cliff_italia_grass"], "tier1Terrain": "medit_grass_field_b", "tier2Terrain": "medit_grass_field_brown", "tier3Terrain": "medit_grass_field_dry", "tier4Terrain": "medit_grass_wild", "hill": ["medit_rocks_grass_shrubs", "medit_rocks_shrubs"], "dirt": ["medit_dirt", "medit_dirt_b"], "road": "medit_city_tile", "roadWild": "medit_city_tile", "shoreBlend": "medit_sand", "shore": "sand_grass_25", "water": "medit_sand_wet" }; g_Gaia = { "chicken": "gaia/fauna_chicken", "mainHuntableAnimal": "gaia/fauna_deer", "fish": "gaia/fauna_fish", "secondaryHuntableAnimal": "gaia/fauna_sheep", "stoneLarge": "gaia/geology_stonemine_medit_quarry", "stoneSmall": "gaia/geology_stone_mediterranean", "metalLarge": "gaia/geology_metal_mediterranean_slabs" }; - var random_trees = randInt(3); - if (random_trees == 0) + var random_trees = randIntInclusive(1, 3); + if (random_trees == 1) { g_Gaia.tree1 = "gaia/flora_tree_cretan_date_palm_short"; g_Gaia.tree2 = "gaia/flora_tree_cretan_date_palm_tall"; } - else if (random_trees == 1) + else if (random_trees == 2) { g_Gaia.tree1 = "gaia/flora_tree_carob"; g_Gaia.tree2 = "gaia/flora_tree_carob"; } else { g_Gaia.tree1 = "gaia/flora_tree_medit_fan_palm"; g_Gaia.tree2 = "gaia/flora_tree_medit_fan_palm"; } if (randBool()) g_Gaia.tree3 = "gaia/flora_tree_apple"; else g_Gaia.tree3 = "gaia/flora_tree_poplar_lombardy"; if (randBool()) { g_Gaia.tree4 = "gaia/flora_tree_cypress"; g_Gaia.tree5 = "gaia/flora_tree_cypress"; } else { g_Gaia.tree4 = "gaia/flora_tree_aleppo_pine"; g_Gaia.tree5 = "gaia/flora_tree_aleppo_pine"; } if (randBool()) g_Gaia.fruitBush = "gaia/flora_bush_berry"; else g_Gaia.fruitBush = "gaia/flora_bush_grapes"; g_Decoratives = { "grass": "actor|props/flora/grass_soft_large_tall.xml", "grassShort": "actor|props/flora/grass_soft_large.xml", "reeds": "actor|props/flora/reeds_pond_lush_b.xml", "lillies": "actor|props/flora/water_lillies.xml", "rockLarge": "actor|geology/stone_granite_large.xml", "rockMedium": "actor|geology/stone_granite_med.xml", "bushMedium": "actor|props/flora/bush_medit_me.xml", "bushSmall": "actor|props/flora/bush_medit_sm.xml", "tree": "actor|flora/trees/palm_cretan_date.xml" }; } else if (g_BiomeID == g_BiomeSavanna) { // Using the Malawi as a reference, in parts where it's not too murky from a river nearby. setWaterColor(0.055,0.176,0.431); setWaterTint(0.227,0.749,0.549); setWaterWaviness(1.5); setWaterMurkiness(0.77); setFogFactor(0.25); setFogThickness(0.15); setFogColor(0.847059, 0.737255, 0.482353); setPPEffect("hdr"); setPPContrast(0.57031); setPPBloom(0.34); g_Terrains = { "mainTerrain": ["savanna_grass_a", "savanna_grass_b"], "forestFloor1": "savanna_forestfloor_a", "forestFloor2": "savanna_forestfloor_b", "cliff": ["savanna_cliff_a", "savanna_cliff_b"], "tier1Terrain": "savanna_shrubs_a", "tier2Terrain": "savanna_dirt_rocks_b", "tier3Terrain": "savanna_dirt_rocks_a", "tier4Terrain": "savanna_grass_a", "hill": ["savanna_grass_a", "savanna_grass_b"], "dirt": ["savanna_dirt_rocks_b", "dirt_brown_e"], "road": "savanna_tile_a", "roadWild": "savanna_tile_a", "shoreBlend": "savanna_riparian", "shore": "savanna_riparian_bank", "water": "savanna_riparian_wet" }; g_Gaia = { "tree1": "gaia/flora_tree_baobab", "tree2": "gaia/flora_tree_baobab", "tree3": "gaia/flora_tree_baobab", "tree4": "gaia/flora_tree_baobab", "tree5": "gaia/flora_tree_baobab", "fruitBush": "gaia/flora_bush_grapes", "chicken": "gaia/fauna_chicken", "fish": "gaia/fauna_fish", "mainHuntableAnimal": pickRandom([ "gaia/fauna_wildebeest", "gaia/fauna_zebra", "gaia/fauna_giraffe", "gaia/fauna_elephant_african_bush" ]), "secondaryHuntableAnimal": "gaia/fauna_gazelle", "stoneLarge": "gaia/geology_stonemine_desert_quarry", "stoneSmall": "gaia/geology_stone_savanna_small", "metalLarge": "gaia/geology_metal_savanna_slabs" }; g_Decoratives = { "grass": "actor|props/flora/grass_savanna.xml", "grassShort": "actor|props/flora/grass_medit_field.xml", "reeds": "actor|props/flora/reeds_pond_lush_a.xml", "lillies": "actor|props/flora/reeds_pond_lush_b.xml", "rockLarge": "actor|geology/stone_savanna_med.xml", "rockMedium": "actor|geology/stone_savanna_med.xml", "bushMedium": "actor|props/flora/bush_desert_dry_a.xml", "bushSmall": "actor|props/flora/bush_dry_a.xml", "tree": "actor|flora/trees/baobab.xml" }; } else if (g_BiomeID == g_BiomeTropic) { // Bora-Bora ish. Quite transparent, not wavy. // Mostly for shallow maps. Maps where the water level goes deeper should use a much darker Water Color to simulate deep water holes. setWaterColor(0.584,0.824,0.929); setWaterTint(0.569,0.965,0.945); setWaterWaviness(1.5); setWaterMurkiness(0.35); setFogFactor(0.4); setFogThickness(0.2); setPPEffect("hdr"); setPPContrast(0.67); setPPSaturation(0.62); setPPBloom(0.6); g_Terrains = { "mainTerrain": ["tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_plants", "tropic_plants", "tropic_plants_b"], "forestFloor1": "tropic_plants_c", "forestFloor2": "tropic_plants_c", "cliff": ["tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a_plants"], "tier1Terrain": "tropic_grass_c", "tier2Terrain": "tropic_grass_plants", "tier3Terrain": "tropic_plants", "tier4Terrain": "tropic_plants_b", "hill": ["tropic_cliff_grass"], "dirt": ["tropic_dirt_a", "tropic_dirt_a_plants"], "road": "tropic_citytile_a", "roadWild": "tropic_citytile_plants", "shoreBlend": "temp_mud_plants", "shore": "tropic_beach_dry_plants", "water": "tropic_beach_dry" }; g_Gaia = { "tree1": "gaia/flora_tree_toona", "tree2": "gaia/flora_tree_toona", "tree3": "gaia/flora_tree_palm_tropic", "tree4": "gaia/flora_tree_palm_tropic", "tree5": "gaia/flora_tree_palm_tropic", "fruitBush": "gaia/flora_bush_berry", "chicken": "gaia/fauna_chicken", "mainHuntableAnimal": "gaia/fauna_peacock", "fish": "gaia/fauna_fish", "secondaryHuntableAnimal": "gaia/fauna_tiger", "stoneLarge": "gaia/geology_stonemine_tropic_quarry", "stoneSmall": "gaia/geology_stone_tropic_a", "metalLarge": "gaia/geology_metal_tropic_slabs" }; g_Decoratives = { "grass": "actor|props/flora/plant_tropic_a.xml", "grassShort": "actor|props/flora/plant_lg.xml", "reeds": "actor|props/flora/reeds_pond_lush_b.xml", "lillies": "actor|props/flora/water_lillies.xml", "rockLarge": "actor|geology/stone_granite_large.xml", "rockMedium": "actor|geology/stone_granite_med.xml", "bushMedium": "actor|props/flora/plant_tropic_large.xml", "bushSmall": "actor|props/flora/plant_tropic_large.xml", "tree": "actor|flora/trees/tree_tropic.xml" }; } else if (g_BiomeID == g_BiomeAutumn) { // basically temperate with a reddish twist in the reflection and the tint. Also less wavy. // this assumes ocean settings, maps that aren't oceans should reset. setWaterColor(0.157, 0.149, 0.443); setWaterTint(0.443,0.42,0.824); setWaterWaviness(2.5); setWaterMurkiness(0.83); setFogFactor(0.35); setFogThickness(0.22); setFogColor(0.82,0.82, 0.73); setPPSaturation(0.56); setPPContrast(0.56); setPPBloom(0.38); setPPEffect("hdr"); g_Terrains = { "mainTerrain": ["temp_grass_aut", "temp_grass_aut", "temp_grass_d_aut"], "forestFloor1": "temp_plants_bog_aut", "forestFloor2": "temp_forestfloor_aut", "cliff": ["temp_cliff_a", "temp_cliff_b"], "tier1Terrain": "temp_grass_plants_aut", "tier2Terrain": ["temp_grass_b_aut", "temp_grass_c_aut"], "tier3Terrain": ["temp_grass_b_aut", "temp_grass_long_b_aut"], "tier4Terrain": "temp_grass_plants_aut", "hill": "temp_highlands_aut", "dirt": ["temp_cliff_a", "temp_cliff_b"], "road": "temp_road_aut", "roadWild": "temp_road_overgrown_aut", "shoreBlend": "temp_grass_plants_aut", "shore": "temp_forestfloor_pine", "water": "medit_sand_wet" }; g_Gaia = { "tree1": "gaia/flora_tree_euro_beech_aut", "tree2": "gaia/flora_tree_euro_beech_aut", "tree3": "gaia/flora_tree_pine", "tree4": "gaia/flora_tree_oak_aut", "tree5": "gaia/flora_tree_oak_aut", "fruitBush": "gaia/flora_bush_berry", "chicken": "gaia/fauna_chicken", "mainHuntableAnimal": "gaia/fauna_deer", "fish": "gaia/fauna_fish", "secondaryHuntableAnimal": "gaia/fauna_rabbit", "stoneLarge": "gaia/geology_stonemine_temperate_quarry", "stoneSmall": "gaia/geology_stone_temperate", "metalLarge": "gaia/geology_metal_temperate_slabs" }; g_Decoratives = { "grass": "actor|props/flora/grass_soft_dry_small_tall.xml", "grassShort": "actor|props/flora/grass_soft_dry_large.xml", "reeds": "actor|props/flora/reeds_pond_dry.xml", "lillies": "actor|geology/stone_granite_large.xml", "rockLarge": "actor|geology/stone_granite_large.xml", "rockMedium": "actor|geology/stone_granite_med.xml", "bushMedium": "actor|props/flora/bush_desert_dry_a.xml", "bushSmall": "actor|props/flora/bush_desert_dry_a.xml", "tree": "actor|flora/trees/european_beech_aut.xml" }; } } function rBiomeT1() { return g_Terrains.mainTerrain; } function rBiomeT2() { return g_Terrains.forestFloor1; } function rBiomeT3() { return g_Terrains.forestFloor2; } function rBiomeT4() { return g_Terrains.cliff; } function rBiomeT5() { return g_Terrains.tier1Terrain; } function rBiomeT6() { return g_Terrains.tier2Terrain; } function rBiomeT7() { return g_Terrains.tier3Terrain; } function rBiomeT8() { return g_Terrains.hill; } function rBiomeT9() { return g_Terrains.dirt; } function rBiomeT10() { return g_Terrains.road; } function rBiomeT11() { return g_Terrains.roadWild; } function rBiomeT12() { return g_Terrains.tier4Terrain; } function rBiomeT13() { return g_Terrains.shoreBlend; } function rBiomeT14() { return g_Terrains.shore; } function rBiomeT15() { return g_Terrains.water; } function rBiomeE1() { return g_Gaia.tree1; } function rBiomeE2() { return g_Gaia.tree2; } function rBiomeE3() { return g_Gaia.tree3; } function rBiomeE4() { return g_Gaia.tree4; } function rBiomeE5() { return g_Gaia.tree5; } function rBiomeE6() { return g_Gaia.fruitBush; } function rBiomeE7() { return g_Gaia.chicken; } function rBiomeE8() { return g_Gaia.mainHuntableAnimal; } function rBiomeE9() { return g_Gaia.fish; } function rBiomeE10() { return g_Gaia.secondaryHuntableAnimal; } function rBiomeE11() { return g_Gaia.stoneLarge; } function rBiomeE12() { return g_Gaia.stoneSmall; } function rBiomeE13() { return g_Gaia.metalLarge; } function rBiomeA1() { return g_Decoratives.grass; } function rBiomeA2() { return g_Decoratives.grassShort; } function rBiomeA3() { return g_Decoratives.reeds; } function rBiomeA4() { return g_Decoratives.lillies; } function rBiomeA5() { return g_Decoratives.rockLarge; } function rBiomeA6() { return g_Decoratives.rockMedium; } function rBiomeA7() { return g_Decoratives.bushMedium; } function rBiomeA8() { return g_Decoratives.bushSmall; } function rBiomeA9() { return g_Decoratives.tree; } Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen2/gaia.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen2/gaia.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen2/gaia.js (revision 19443) @@ -1,1325 +1,1325 @@ var g_Props = { "barrels": "actor|props/special/eyecandy/barrels_buried.xml", "crate": "actor|props/special/eyecandy/crate_a.xml", "cart": "actor|props/special/eyecandy/handcart_1_broken.xml", "well": "actor|props/special/eyecandy/well_1_c.xml", "skeleton": "actor|props/special/eyecandy/skeleton.xml", }; var g_DefaultDeviation = 0.1; /** * Create bluffs, i.e. a slope hill reachable from ground level. * Fill it with wood, mines, animals and decoratives. * * @param {Array} constraint - where to place them * @param {number} size - size of the bluffs (1.2 would be 120% of normal) * @param {number} deviation - degree of deviation from the defined size (0.2 would be 20% plus/minus) * @param {number} fill - size of map to fill (1.5 would be 150% of normal) */ function addBluffs(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var constrastTerrain = g_Terrains.tier2Terrain; if (g_MapInfo.biome == g_BiomeTropic) constrastTerrain = g_Terrains.dirt; if (g_MapInfo.biome == g_BiomeAutumn) constrastTerrain = g_Terrains.tier3Terrain; var count = fill * scaleByMapSize(15, 15); var minSize = scaleByMapSize(5, 5); var maxSize = scaleByMapSize(7, 7); var elevation = 30; var spread = scaleByMapSize(100, 100); for (var i = 0; i < count; ++i) { var offset = getRandomDeviation(size, deviation); var pMinSize = Math.floor(minSize * offset); var pMaxSize = Math.floor(maxSize * offset); var pSpread = Math.floor(spread * offset); var pElevation = Math.floor(elevation * offset); var placer = new ChainPlacer(pMinSize, pMaxSize, pSpread, 0.5); var terrainPainter = new LayeredPainter([g_Terrains.cliff, g_Terrains.mainTerrain, constrastTerrain], [2, 3]); var elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, pElevation, 2); var rendered = createAreas(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.bluff)], constraint, 1); // Find the bounding box of the bluff if (rendered[0] === undefined) continue; var points = rendered[0].points; var corners = findCorners(points); // Seed an array the size of the bounding box var bb = createBoundingBox(points, corners); // Get a random starting position for the baseline and the endline - var angle = randInt(4); + var angle = randIntInclusive(0, 3); var opAngle = angle - 2; if (angle < 2) opAngle = angle + 2; // Find the edges of the bluff var baseLine; var endLine; // If we can't access the bluff, try different angles var retries = 0; var bluffCat = 2; while (bluffCat != 0 && retries < 5) { baseLine = findClearLine(bb, corners, angle); endLine = findClearLine(bb, corners, opAngle); bluffCat = unreachableBluff(bb, corners, baseLine, endLine); ++angle; if (angle > 3) angle = 0; opAngle = angle - 2; if (angle < 2) opAngle = angle + 2; ++retries; } // Inaccessible, turn it into a plateau if (bluffCat > 0) { removeBluff(points); continue; } // Create an entrance area by using a small margin var margin = 0.08; var ground = createTerrain(g_Terrains.mainTerrain); var slopeLength = (1 - margin) * getDistance(baseLine.midX, baseLine.midZ, endLine.midX, endLine.midZ); // Adjust the height of each point in the bluff for (var p = 0; p < points.length; ++p) { var pt = points[p]; var dist = distanceOfPointFromLine(baseLine.x1, baseLine.z1, baseLine.x2, baseLine.z2, pt.x, pt.z); var curHeight = g_Map.getHeight(pt.x, pt.z); var newHeight = curHeight - curHeight * (dist / slopeLength) - 2; newHeight = Math.max(newHeight, endLine.height); if (newHeight <= endLine.height + 2 && g_Map.validT(pt.x, pt.z) && g_Map.getTexture(pt.x, pt.z).indexOf('cliff') > -1) ground.place(pt.x, pt.z); g_Map.setHeight(pt.x, pt.z, newHeight); } // Smooth out the ground around the bluff fadeToGround(bb, corners.minX, corners.minZ, endLine.height); } addElements([ { "func": addHills, "avoid": [ g_TileClasses.hill, 3, g_TileClasses.player, 20, g_TileClasses.valley, 2, g_TileClasses.water, 2 ], "stay": [g_TileClasses.bluff, 3], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts } ]); addElements([ { "func": addLayeredPatches, "avoid": [ g_TileClasses.dirt, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.player, 12, g_TileClasses.water, 3 ], "stay": [g_TileClasses.bluff, 5], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] } ]); addElements([ { "func": addDecoration, "avoid": [ g_TileClasses.forest, 2, g_TileClasses.player, 12, g_TileClasses.water, 3 ], "stay": [g_TileClasses.bluff, 5], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] } ]); addElements([ { "func": addProps, "avoid": [ g_TileClasses.forest, 2, g_TileClasses.player, 12, g_TileClasses.prop, 40, g_TileClasses.water, 3 ], "stay": [ g_TileClasses.bluff, 7, g_TileClasses.mountain, 7 ], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["scarce"] } ]); addElements(shuffleArray([ { "func": addForests, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.forest, 18, g_TileClasses.metal, 5, g_TileClasses.mountain, 5, g_TileClasses.player, 20, g_TileClasses.rock, 5, g_TileClasses.water, 2 ], "stay": [g_TileClasses.bluff, 6], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["normal", "many", "tons"] }, { "func": addMetal, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.forest, 5, g_TileClasses.mountain, 2, g_TileClasses.player, 50, g_TileClasses.rock, 15, g_TileClasses.metal, 40, g_TileClasses.water, 3 ], "stay": [g_TileClasses.bluff, 6], "sizes": ["normal"], "mixes": ["same"], "amounts": ["normal"] }, { "func": addStone, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.forest, 5, g_TileClasses.mountain, 2, g_TileClasses.player, 50, g_TileClasses.rock, 40, g_TileClasses.metal, 15, g_TileClasses.water, 3 ], "stay": [g_TileClasses.bluff, 6], "sizes": ["normal"], "mixes": ["same"], "amounts": ["normal"] } ])); let savanna = g_MapInfo.biome == g_BiomeSavanna; addElements(shuffleArray([ { "func": addStragglerTrees, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.forest, 10, g_TileClasses.metal, 5, g_TileClasses.mountain, 1, g_TileClasses.player, 12, g_TileClasses.rock, 5, g_TileClasses.water, 5 ], "stay": [g_TileClasses.bluff, 6], "sizes": savanna ? ["big"] : g_AllSizes, "mixes": savanna ? ["varied"] : g_AllMixes, "amounts": savanna ? ["tons"] : ["normal", "many", "tons"] }, { "func": addAnimals, "avoid": [ g_TileClasses.animals, 20, g_TileClasses.forest, 5, g_TileClasses.mountain, 1, g_TileClasses.player, 20, g_TileClasses.rock, 5, g_TileClasses.metal, 5, g_TileClasses.water, 3 ], "stay": [g_TileClasses.bluff, 6], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["normal", "many", "tons"] }, { "func": addBerries, "avoid": [ g_TileClasses.berries, 50, g_TileClasses.forest, 5, g_TileClasses.metal, 10, g_TileClasses.mountain, 2, g_TileClasses.player, 20, g_TileClasses.rock, 10, g_TileClasses.water, 3 ], "stay": [g_TileClasses.bluff, 6], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["normal", "many", "tons"] } ])); } /** * Add grass, rocks and bushes. */ function addDecoration(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var offset = getRandomDeviation(size, deviation); var decorations = [ [ new SimpleObject(g_Decoratives.rockMedium, 1 * offset, 3 * offset, 0, 1 * offset) ], [ new SimpleObject(g_Decoratives.rockLarge, 1 * offset, 2 * offset, 0, 1 * offset), new SimpleObject(g_Decoratives.rockMedium, 1 * offset, 3 * offset, 0, 2 * offset) ], [ new SimpleObject(g_Decoratives.grassShort, 1 * offset, 2 * offset, 0, 1 * offset, -PI / 8, PI / 8) ], [ new SimpleObject(g_Decoratives.grass, 2 * offset, 4 * offset, 0, 1.8 * offset, -PI / 8, PI / 8), new SimpleObject(g_Decoratives.grassShort, 3 * offset, 6 * offset, 1.2 * offset, 2.5 * offset, -PI / 8, PI / 8) ], [ new SimpleObject(g_Decoratives.bushMedium, 1 * offset, 2 * offset, 0, 2 * offset), new SimpleObject(g_Decoratives.bushSmall, 2 * offset, 4 * offset, 0, 2 * offset) ] ]; var baseCount = 1; if (g_MapInfo.biome == g_BiomeTropic) baseCount = 8; var counts = [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), baseCount * scaleByMapSize(13, 200), baseCount * scaleByMapSize(13, 200), baseCount * scaleByMapSize(13, 200) ]; for (var i = 0; i < decorations.length; ++i) { var decorCount = Math.floor(counts[i] * fill); var group = new SimpleGroup(decorations[i], true); createObjectGroups(group, 0, constraint, decorCount, 5); } } /** * Create varying elevations. * * @param {Array} constraint - avoid/stay-classes * * @param {Object} el - the element to be rendered, for example: * "class": g_TileClasses.hill, * "painter": [g_Terrains.mainTerrain, g_Terrains.mainTerrain], * "size": 1, * "deviation": 0.2, * "fill": 1, * "count": scaleByMapSize(8, 8), * "minSize": Math.floor(scaleByMapSize(5, 5)), * "maxSize": Math.floor(scaleByMapSize(8, 8)), * "spread": Math.floor(scaleByMapSize(20, 20)), * "minElevation": 6, * "maxElevation": 12, * "steepness": 1.5 */ function addElevation(constraint, el) { var deviation = el.deviation || g_DefaultDeviation; var size = el.size || 1; var fill = el.fill || 1; var count = fill * el.count; var minSize = el.minSize; var maxSize = el.maxSize; var spread = el.spread; var elType = ELEVATION_MODIFY; if (el.class == g_TileClasses.water) elType = ELEVATION_SET; var widths = []; // Allow for shore and cliff rendering for (var s = el.painter.length; s > 2; --s) widths.push(1); for (var i = 0; i < count; ++i) { - var elevation = el.minElevation + randInt(el.maxElevation - el.minElevation); + var elevation = randIntExclusive(el.minElevation, el.maxElevation); var smooth = Math.floor(elevation / el.steepness); var offset = getRandomDeviation(size, el.deviation); var pMinSize = Math.floor(minSize * offset); var pMaxSize = Math.floor(maxSize * offset); var pSpread = Math.floor(spread * offset); var pSmooth = Math.abs(Math.floor(smooth * offset)); var pElevation = Math.floor(elevation * offset); pElevation = Math.max(el.minElevation, Math.min(pElevation, el.maxElevation)); pMinSize = Math.min(pMinSize, pMaxSize); pMaxSize = Math.min(pMaxSize, el.maxSize); pMinSize = Math.max(pMaxSize, el.minSize); pSmooth = Math.max(pSmooth, 1); var pWidths = widths.concat(pSmooth); var placer = new ChainPlacer(pMinSize, pMaxSize, pSpread, 0.5); var terrainPainter = new LayeredPainter(el.painter, [pWidths]); var elevationPainter = new SmoothElevationPainter(elType, pElevation, pSmooth); createAreas(placer, [terrainPainter, elevationPainter, paintClass(el.class)], constraint, 1); } } /** * Create rolling hills. */ function addHills(constraint, size, deviation, fill) { addElevation(constraint, { "class": g_TileClasses.hill, "painter": [g_Terrains.mainTerrain, g_Terrains.mainTerrain], "size": size, "deviation": deviation, "fill": fill, "count": scaleByMapSize(8, 8), "minSize": Math.floor(scaleByMapSize(5, 5)), "maxSize": Math.floor(scaleByMapSize(8, 8)), "spread": Math.floor(scaleByMapSize(20, 20)), "minElevation": 6, "maxElevation": 12, "steepness": 1.5 }); } /** * Create random lakes with fish in it. */ function addLakes(constraint, size, deviation, fill) { var lakeTile = g_Terrains.water; if (g_MapInfo.biome == g_BiomeTemperate || g_MapInfo.biome == g_BiomeTropic) lakeTile = g_Terrains.dirt; if (g_MapInfo.biome == g_BiomeMediterranean) lakeTile = g_Terrains.tier2Terrain; if (g_MapInfo.biome == g_BiomeAutumn) lakeTile = g_Terrains.shore; addElevation(constraint, { "class": g_TileClasses.water, "painter": [lakeTile, lakeTile], "size": size, "deviation": deviation, "fill": fill, "count": scaleByMapSize(6, 6), "minSize": Math.floor(scaleByMapSize(7, 7)), "maxSize": Math.floor(scaleByMapSize(9, 9)), "spread": Math.floor(scaleByMapSize(70, 70)), "minElevation": -15, "maxElevation": -2, "steepness": 1.5 }); addElements([ { "func": addFish, "avoid": [ g_TileClasses.fish, 12, g_TileClasses.hill, 8, g_TileClasses.mountain, 8, g_TileClasses.player, 8 ], "stay": [g_TileClasses.water, 7], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["normal", "many", "tons"] } ]); var group = new SimpleGroup([new SimpleObject(g_Decoratives.rockMedium, 1, 3, 1, 3)], true, g_TileClasses.dirt); createObjectGroups(group, 0, [stayClasses(g_TileClasses.water, 1), borderClasses(g_TileClasses.water, 4, 3)], 1000, 100); group = new SimpleGroup([new SimpleObject(g_Decoratives.reeds, 10, 15, 1, 3), new SimpleObject(g_Decoratives.rockMedium, 1, 3, 1, 3)], true, g_TileClasses.dirt); createObjectGroups(group, 0, [stayClasses(g_TileClasses.water, 2), borderClasses(g_TileClasses.water, 4, 3)], 1000, 100); } /** * Universal function to create layered patches. */ function addLayeredPatches(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var minRadius = 1; var maxRadius = Math.floor(scaleByMapSize(3, 5)); var count = fill * scaleByMapSize(15, 45); var sizes = [ scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21) ]; for (var i = 0; i < sizes.length; ++i) { var offset = getRandomDeviation(size, deviation); var patchMinRadius = Math.floor(minRadius * offset); var patchMaxRadius = Math.floor(maxRadius * offset); var patchSize = Math.floor(sizes[i] * offset); var patchCount = count * offset; if (patchMinRadius > patchMaxRadius) patchMinRadius = patchMaxRadius; var placer = new ChainPlacer(patchMinRadius, patchMaxRadius, patchSize, 0.5); var painter = new LayeredPainter( [ [g_Terrains.mainTerrain, g_Terrains.tier1Terrain], [g_Terrains.tier1Terrain, g_Terrains.tier2Terrain], [g_Terrains.tier2Terrain, g_Terrains.tier3Terrain], [g_Terrains.tier4Terrain] ], [1, 1] // widths ); createAreas(placer, [painter, paintClass(g_TileClasses.dirt)], constraint, patchCount); } } /** * Create steep mountains. */ function addMountains(constraint, size, deviation, fill) { addElevation(constraint, { "class": g_TileClasses.mountain, "painter": [g_Terrains.cliff, g_Terrains.hill], "size": size, "deviation": deviation, "fill": fill, "count": scaleByMapSize(8, 8), "minSize": Math.floor(scaleByMapSize(2, 2)), "maxSize": Math.floor(scaleByMapSize(4, 4)), "spread": Math.floor(scaleByMapSize(100, 100)), "minElevation": 100, "maxElevation": 120, "steepness": 4 }); } /** * Create plateaus. */ function addPlateaus(constraint, size, deviation, fill) { var plateauTile = g_Terrains.dirt; if (g_MapInfo.biome == g_BiomeSnowy) plateauTile = g_Terrains.tier1Terrain; if (g_MapInfo.biome == g_BiomeAlpine || g_MapInfo.biome == g_BiomeSavanna) plateauTile = g_Terrains.tier2Terrain; if (g_MapInfo.biome == g_BiomeAutumn) plateauTile = g_Terrains.tier4Terrain; addElevation(constraint, { "class": g_TileClasses.plateau, "painter": [g_Terrains.cliff, plateauTile], "size": size, "deviation": deviation, "fill": fill, "count": scaleByMapSize(15, 15), "minSize": Math.floor(scaleByMapSize(2, 2)), "maxSize": Math.floor(scaleByMapSize(4, 4)), "spread": Math.floor(scaleByMapSize(200, 200)), "minElevation": 20, "maxElevation": 30, "steepness": 8 }); for (var i = 0; i < 40; ++i) { var placer = new ChainPlacer(3, 15, 1, 0.5); var terrainPainter = new LayeredPainter([plateauTile, plateauTile], [3]); - var hillElevation = 4 + randInt(15); + var hillElevation = randIntInclusive(4, 18); var elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, hillElevation, hillElevation - 2); createAreas( placer, [ terrainPainter, elevationPainter, paintClass(g_TileClasses.hill) ], [ avoidClasses(g_TileClasses.hill, 7), stayClasses(g_TileClasses.plateau, 7) ], 1 ); } addElements([ { "func": addDecoration, "avoid": [ g_TileClasses.dirt, 15, g_TileClasses.forest, 2, g_TileClasses.player, 12, g_TileClasses.water, 3 ], "stay": [g_TileClasses.plateau, 8], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["tons"] }, { "func": addProps, "avoid": [ g_TileClasses.forest, 2, g_TileClasses.player, 12, g_TileClasses.prop, 40, g_TileClasses.water, 3 ], "stay": [g_TileClasses.plateau, 8], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["scarce"] } ]); } /** * Place less usual decoratives like barrels or crates. */ function addProps(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var offset = getRandomDeviation(size, deviation); var props = [ [ new SimpleObject(g_Props.skeleton, 1 * offset, 5 * offset, 0, 3 * offset + 2), ], [ new SimpleObject(g_Props.barrels, 1 * offset, 2 * offset, 2, 3 * offset + 2), new SimpleObject(g_Props.cart, 0, 1 * offset, 5, 2.5 * offset + 5), new SimpleObject(g_Props.crate, 1 * offset, 2 * offset, 2, 2 * offset + 2), new SimpleObject(g_Props.well, 0, 1, 2, 2 * offset + 2) ] ]; var baseCount = 1; var counts = [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), baseCount * scaleByMapSize(13, 200), baseCount * scaleByMapSize(13, 200), baseCount * scaleByMapSize(13, 200) ]; // Add small props for (var i = 0; i < props.length; ++i) { var propCount = Math.floor(counts[i] * fill); var group = new SimpleGroup(props[i], true); createObjectGroups(group, 0, constraint, propCount, 5); } // Add decorative trees var trees = new SimpleObject(g_Decoratives.tree, 5 * offset, 30 * offset, 2, 3 * offset + 10); createObjectGroups(new SimpleGroup([trees], true), 0, constraint, counts[0] * 5 * fill, 5); } /** * Create valleys. */ function addValleys(constraint, size, deviation, fill) { if (g_MapInfo.mapHeight < 6) return; var minElevation = (-1 * g_MapInfo.mapHeight) / (size * (1 + deviation)) + 1; if (minElevation < -1 * g_MapInfo.mapHeight) minElevation = -1 * g_MapInfo.mapHeight; var valleySlope = g_Terrains.tier1Terrain; var valleyFloor = g_Terrains.tier4Terrain; if (g_MapInfo.biome == g_BiomeDesert) { valleySlope = g_Terrains.tier3Terrain; valleyFloor = g_Terrains.dirt; } if (g_MapInfo.biome == g_BiomeMediterranean) { valleySlope = g_Terrains.tier2Terrain; valleyFloor = g_Terrains.dirt; } if (g_MapInfo.biome == g_BiomeAlpine || g_MapInfo.biome == g_BiomeSavanna) valleyFloor = g_Terrains.tier2Terrain; if (g_MapInfo.biome == g_BiomeTropic) valleySlope = g_Terrains.dirt; if (g_MapInfo.biome == g_BiomeAutumn) valleyFloor = g_Terrains.tier3Terrain; addElevation(constraint, { "class": g_TileClasses.valley, "painter": [valleySlope, valleyFloor], "size": size, "deviation": deviation, "fill": fill, "count": scaleByMapSize(8, 8), "minSize": Math.floor(scaleByMapSize(5, 5)), "maxSize": Math.floor(scaleByMapSize(8, 8)), "spread": Math.floor(scaleByMapSize(30, 30)), "minElevation": minElevation, "maxElevation": -2, "steepness": 4 }); } /** * Create huntable animals. */ function addAnimals(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var groupOffset = getRandomDeviation(size, deviation); var animals = [ [new SimpleObject(g_Gaia.mainHuntableAnimal, 5 * groupOffset, 7 * groupOffset, 0, 4 * groupOffset)], [new SimpleObject(g_Gaia.secondaryHuntableAnimal, 2 * groupOffset, 3 * groupOffset, 0, 2 * groupOffset)] ]; var counts = [scaleByMapSize(30, 30) * fill, scaleByMapSize(30, 30) * fill]; for (var i = 0; i < animals.length; ++i) { var group = new SimpleGroup(animals[i], true, g_TileClasses.animals); createObjectGroups(group, 0, constraint, Math.floor(counts[i]), 50); } } /** * Create fruits. */ function addBerries(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var groupOffset = getRandomDeviation(size, deviation); var count = scaleByMapSize(50, 50) * fill; var berries = [[new SimpleObject(g_Gaia.fruitBush, 5 * groupOffset, 5 * groupOffset, 0, 3 * groupOffset)]]; for (var i = 0; i < berries.length; ++i) { var group = new SimpleGroup(berries[i], true, g_TileClasses.berries); createObjectGroups(group, 0, constraint, Math.floor(count), 40); } } /** * Create fish. */ function addFish(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var groupOffset = getRandomDeviation(size, deviation); var fish = [ [new SimpleObject(g_Gaia.fish, 1 * groupOffset, 2 * groupOffset, 0, 2 * groupOffset)], [new SimpleObject(g_Gaia.fish, 2 * groupOffset, 4 * groupOffset, 10 * groupOffset, 20 * groupOffset)] ]; var counts = [scaleByMapSize(40, 40) * fill, scaleByMapSize(40, 40) * fill]; for (var i = 0; i < fish.length; ++i) { var group = new SimpleGroup(fish[i], true, g_TileClasses.fish); createObjectGroups(group, 0, constraint, floor(counts[i]), 50); } } /** * Create dense forests. */ function addForests(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; // No forests for the african biome if (g_MapInfo.biome == g_BiomeSavanna) return; var types = [ [ [g_Terrains.forestFloor2, g_Terrains.mainTerrain, g_Forests.forest1], [g_Terrains.forestFloor2, g_Forests.forest1] ], [ [g_Terrains.forestFloor2, g_Terrains.mainTerrain, g_Forests.forest2], [g_Terrains.forestFloor1, g_Forests.forest2]], [ [g_Terrains.forestFloor1, g_Terrains.mainTerrain, g_Forests.forest1], [g_Terrains.forestFloor2, g_Forests.forest1]], [ [g_Terrains.forestFloor1, g_Terrains.mainTerrain, g_Forests.forest2], [g_Terrains.forestFloor1, g_Forests.forest2] ] ]; for (var i = 0; i < types.length; ++i) { var offset = getRandomDeviation(size, deviation); var minSize = floor(scaleByMapSize(3, 5) * offset); var maxSize = Math.floor(scaleByMapSize(50, 50) * offset); var forestCount = scaleByMapSize(10, 10) * fill; var placer = new ChainPlacer(1, minSize, maxSize, 0.5); var painter = new LayeredPainter(types[i], [2]); createAreas(placer, [painter, paintClass(g_TileClasses.forest)], constraint, forestCount); } } /** * Create metal mines. */ function addMetal(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var offset = getRandomDeviation(size, deviation); var count = 1 + scaleByMapSize(20, 20) * fill; var mines = [[new SimpleObject(g_Gaia.metalLarge, 1 * offset, 1 * offset, 0, 4 * offset)]]; for (var i = 0; i < mines.length; ++i) { var group = new SimpleGroup(mines[i], true, g_TileClasses.metal); createObjectGroups(group, 0, constraint, count, 100); } } function addSmallMetal(constraint, size, mixes, amounts) { let deviation = getRandomDeviation(size || 1, mixes || g_DefaultDeviation); let count = 1 + scaleByMapSize(20, 20) * (amounts || 1); let mines = [[new SimpleObject(g_Gaia.metalSmall, 2 * deviation, 5 * deviation, 1 * deviation, 3 * deviation)]]; for (let i = 0; i < mines.length; ++i) { let group = new SimpleGroup(mines[i], true, g_TileClasses.metal); createObjectGroups(group, 0, constraint, count, 100); } } /** * Create stone mines. */ function addStone(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; var offset = getRandomDeviation(size, deviation); var count = 1 + scaleByMapSize(20, 20) * fill; var mines = [ [ new SimpleObject(g_Gaia.stoneSmall, 0, 2 * offset, 0, 4 * offset), new SimpleObject(g_Gaia.stoneLarge, 1 * offset, 1 * offset, 0, 4 * offset) ], [ new SimpleObject(g_Gaia.stoneSmall, 2 * offset, 5 * offset, 1 * offset, 3 * offset) ] ]; for (var i = 0; i < mines.length; ++i) { var group = new SimpleGroup(mines[i], true, g_TileClasses.rock); createObjectGroups(group, 0, constraint, count, 100); } } /** * Create straggler trees. */ function addStragglerTrees(constraint, size, deviation, fill) { deviation = deviation || g_DefaultDeviation; size = size || 1; fill = fill || 1; // Ensure minimum distribution on african biome if (g_MapInfo.biome == g_BiomeSavanna) { fill = Math.max(fill, 2); size = Math.max(size, 1); } var trees = [g_Gaia.tree1, g_Gaia.tree2, g_Gaia.tree3, g_Gaia.tree4]; var treesPerPlayer = 40; var playerBonus = Math.max(1, (g_MapInfo.numPlayers - 3) / 2); var offset = getRandomDeviation(size, deviation); var treeCount = treesPerPlayer * playerBonus * fill; var totalTrees = scaleByMapSize(treeCount, treeCount); var count = Math.floor(totalTrees / trees.length) * fill; var min = 1 * offset; var max = 4 * offset; var minDist = 1 * offset; var maxDist = 5 * offset; // More trees for the african biome if (g_MapInfo.biome == g_BiomeSavanna) { min = 3 * offset; max = 5 * offset; minDist = 2 * offset + 1; maxDist = 3 * offset + 2; } for (var i = 0; i < trees.length; ++i) { var treesMax = max; // Don't clump fruit trees if (i == 2 && (g_MapInfo.biome == g_BiomeDesert || g_MapInfo.biome == g_BiomeMediterranean)) treesMax = 1; min = Math.min(min, treesMax); var group = new SimpleGroup([new SimpleObject(trees[i], min, treesMax, minDist, maxDist)], true, g_TileClasses.forest); createObjectGroups(group, 0, constraint, count); } } /////////// // Terrain Helpers /////////// /** * Determine if the endline of the bluff is within the tilemap. * * @returns {Number} 0 if the bluff is reachable, otherwise a positive number */ function unreachableBluff(bb, corners, baseLine, endLine) { // If we couldn't find a slope line if (typeof baseLine.midX === "undefined" || typeof endLine.midX === "undefined") return 1; // If the end points aren't on the tilemap if (!g_Map.validT(endLine.x1, endLine.z1) && !g_Map.validT(endLine.x2, endLine.z2)) return 2; var minTilesInGroup = 1; var insideBluff = false; var outsideBluff = false; // If there aren't enough points in each row for (var x = 0; x < bb.length; ++x) { var count = 0; for (var z = 0; z < bb[x].length; ++z) { if (!bb[x][z].isFeature) continue; var valid = g_Map.validT(x + corners.minX, z + corners.minZ); if (valid) ++count; if (!insideBluff && valid) insideBluff = true; if (outsideBluff && valid) return 3; } // We're expecting the end of the bluff if (insideBluff && count < minTilesInGroup) outsideBluff = true; } var insideBluff = false; var outsideBluff = false; // If there aren't enough points in each column for (var z = 0; z < bb[0].length; ++z) { var count = 0; for (var x = 0; x < bb.length; ++x) { if (!bb[x][z].isFeature) continue; var valid = g_Map.validT(x + corners.minX, z + corners.minZ); if (valid) ++count; if (!insideBluff && valid) insideBluff = true; if (outsideBluff && valid) return 3; } // We're expecting the end of the bluff if (insideBluff && count < minTilesInGroup) outsideBluff = true; } // Bluff is reachable return 0; } /** * Remove the bluff class and turn it into a plateau. */ function removeBluff(points) { for (var i = 0; i < points.length; ++i) addToClass(points[i].x, points[i].z, g_TileClasses.mountain); } /** * Create an array of points the fill a bounding box around a terrain feature. */ function createBoundingBox(points, corners) { var bb = []; var width = corners.maxX - corners.minX + 1; var length = corners.maxZ - corners.minZ + 1; for (var w = 0; w < width; ++w) { bb[w] = []; for (var l = 0; l < length; ++l) { var curHeight = g_Map.getHeight(w + corners.minX, l + corners.minZ); bb[w][l] = { "height": curHeight, "isFeature": false }; } } // Define the coordinates that represent the bluff for (var p = 0; p < points.length; ++p) { var pt = points[p]; bb[pt.x - corners.minX][pt.z - corners.minZ].isFeature = true; } return bb; } /** * Flattens the ground touching a terrain feature. */ function fadeToGround(bb, minX, minZ, elevation) { var ground = createTerrain(g_Terrains.mainTerrain); for (var x = 0; x < bb.length; ++x) for (var z = 0; z < bb[x].length; ++z) { var pt = bb[x][z]; if (!pt.isFeature && nextToFeature(bb, x, z)) { var newEl = smoothElevation(x + minX, z + minZ); g_Map.setHeight(x + minX, z + minZ, newEl); ground.place(x + minX, z + minZ); } } } /** * Find a 45 degree line in a bounding box that does not intersect any terrain feature. */ function findClearLine(bb, corners, angle) { // Angle - 0: northwest; 1: northeast; 2: southeast; 3: southwest var z = corners.maxZ; var xOffset = -1; var zOffset = -1; switch(angle) { case 1: xOffset = 1; break; case 2: xOffset = 1; zOffset = 1; z = corners.minZ; break; case 3: zOffset = 1; z = corners.minZ; break; } var clearLine = {}; for (var x = corners.minX; x <= corners.maxX; ++x) { var x2 = x; var z2 = z; var clear = true; while (x2 >= corners.minX && x2 <= corners.maxX && z2 >= corners.minZ && z2 <= corners.maxZ) { var bp = bb[x2 - corners.minX][z2 - corners.minZ]; if (bp.isFeature && g_Map.validT(x2, z2)) { clear = false; break; } x2 = x2 + xOffset; z2 = z2 + zOffset; } if (clear) { var lastX = x2 - xOffset; var lastZ = z2 - zOffset; var midX = Math.floor((x + lastX) / 2); var midZ = Math.floor((z + lastZ) / 2); clearLine = { "x1": x, "z1": z, "x2": lastX, "z2": lastZ, "midX": midX, "midZ": midZ, "height": g_MapInfo.mapHeight }; } if (clear && (angle == 1 || angle == 2)) break; if (!clear && (angle == 0 || angle == 3)) break; } return clearLine; } /** * Returns the corners of a bounding box. */ function findCorners(points) { // Find the bounding box of the terrain feature var minX = g_MapInfo.mapSize + 1; var minZ = g_MapInfo.mapSize + 1; var maxX = -1; var maxZ = -1; for (var p = 0; p < points.length; ++p) { var pt = points[p]; minX = Math.min(pt.x, minX); minZ = Math.min(pt.z, minZ); maxX = Math.max(pt.x, maxX); maxZ = Math.max(pt.z, maxZ); } return { "minX": minX, "minZ": minZ, "maxX": maxX, "maxZ": maxZ }; } /** * Finds the average elevation around a point. */ function smoothElevation(x, z) { var min = g_Map.getHeight(x, z); for (var xOffset = -1; xOffset <= 1; ++xOffset) for (var zOffset = -1; zOffset <= 1; ++zOffset) { var thisX = x + xOffset; var thisZ = z + zOffset; if (!g_Map.validT(thisX, thisZ)) continue; var height = g_Map.getHeight(thisX, thisZ); if (height < min) min = height; } return min; } /** * Determines if a point in a bounding box array is next to a terrain feature. */ function nextToFeature(bb, x, z) { for (var xOffset = -1; xOffset <= 1; ++xOffset) for (var zOffset = -1; zOffset <= 1; ++zOffset) { var thisX = x + xOffset; var thisZ = z + zOffset; if (thisX < 0 || thisX >= bb.length || thisZ < 0 || thisZ >= bb[x].length || (thisX == 0 && thisZ == 0)) continue; if (bb[thisX][thisZ].isFeature) return true; } return false; } /** * Returns a number within a random deviation of a base number. */ function getRandomDeviation(base, deviation) { deviation = Math.min(base, deviation); - deviation = base + randInt(20 * deviation) / 10 - deviation; + deviation = base + randIntExclusive(0, 20 * deviation) / 10 - deviation; return deviation.toFixed(2); } /** * Import a given digital elevation model. * Scale it to the mapsize and paint the textures specified by coordinate on it. * * @param heightmap - An array with a square number of heights * @param tilemap - The IDs of the palletmap to be painted for each heightmap tile * @param pallet - The tile texture names used by the tilemap. * @return the ratio of heightmap tiles per map size tiles */ function paintHeightmap(heightmap, tilemap, pallet, func = undefined) { let mapSize = getMapSize(); // Width of the map in terrain tiles let hmSize = Math.sqrt(heightmap.length); let scale = hmSize / (mapSize + 1); // There are mapSize + 1 vertices (each 1 tile is surrounded by 2x2 vertices) for (let x = 0; x <= mapSize; ++x) for (let y = 0; y <= mapSize; ++y) { let hmPoint = { "x": x * scale, "y": y * scale }; let hmTile = { "x": Math.floor(hmPoint.x), "y": Math.floor(hmPoint.y) }; let shift = { "x": 0, "y": 0 }; if (hmTile.x == 0) shift.x = 1; else if (hmTile.x == hmSize - 1) shift.x = - 2; else if (hmTile.x == hmSize - 2) shift.x = - 1; if (hmTile.y == 0) shift.y = 1; else if (hmTile.y == hmSize - 1) shift.y = - 2; else if (hmTile.y == hmSize - 2) shift.y = - 1; let neighbors = []; for (let localXi = 0; localXi < 4; ++localXi) for (let localYi = 0; localYi < 4; ++localYi) neighbors.push(heightmap[(hmTile.x + localXi + shift.x - 1) * hmSize + (hmTile.y + localYi + shift.y - 1)]); setHeight(x, y, bicubicInterpolation(hmPoint.x - hmTile.x - shift.x, hmPoint.y - hmTile.y - shift.y, ...neighbors) / scale); if (x < mapSize && y < mapSize) { let i = hmTile.x * hmSize + hmTile.y; let tile = pallet[tilemap[i]]; placeTerrain(x, y, tile); if (func) func(tile, x, y); } } return scale; } Index: ps/trunk/binaries/data/mods/public/maps/random/migration.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/migration.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/migration.js (revision 19443) @@ -1,489 +1,489 @@ RMS.LoadLibrary("rmgen"); //random terrain textures var random_terrain = randomizeBiome(); const tMainTerrain = rBiomeT1(); const tForestFloor1 = rBiomeT2(); const tForestFloor2 = rBiomeT3(); const tCliff = rBiomeT4(); const tTier1Terrain = rBiomeT5(); const tTier2Terrain = rBiomeT6(); const tTier3Terrain = rBiomeT7(); const tHill = rBiomeT8(); const tDirt = rBiomeT9(); const tRoad = rBiomeT10(); const tRoadWild = rBiomeT11(); const tTier4Terrain = rBiomeT12(); const tShoreBlend = rBiomeT13(); const tShore = rBiomeT14(); const tWater = rBiomeT15(); // gaia entities const oTree1 = rBiomeE1(); const oTree2 = rBiomeE2(); const oTree3 = rBiomeE3(); const oTree4 = rBiomeE4(); const oTree5 = rBiomeE5(); const oFruitBush = rBiomeE6(); const oMainHuntableAnimal = rBiomeE8(); const oFish = rBiomeE9(); const oSecondaryHuntableAnimal = rBiomeE10(); const oStoneLarge = rBiomeE11(); const oStoneSmall = rBiomeE12(); const oMetalLarge = rBiomeE13(); const oWood = "gaia/special_treasure_wood"; // decorative props const aGrass = rBiomeA1(); const aGrassShort = rBiomeA2(); const aReeds = rBiomeA3(); const aLillies = rBiomeA4(); const aRockLarge = rBiomeA5(); const aRockMedium = rBiomeA6(); const aBushMedium = rBiomeA7(); const aBushSmall = rBiomeA8(); const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clLand = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = PI/2 + PI/14; for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle - (i+1)*(PI+ PI/7)/(numPlayers+1); playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var shoreRadius = 4; var elevation = 3; var hillSize = PI * radius * radius; // get the x and z in tiles fx = fractionToTiles(playerX[i]); fz = fractionToTiles(playerZ[i]); ix = round(fx); iz = round(fz); // create the hill var placer = new ClumpPlacer(hillSize, 0.80, 0.1, 10, ix, iz); var terrainPainter = new LayeredPainter( [tWater , tShore, tMainTerrain], // terrains [1, shoreRadius] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type elevation, // elevation shoreRadius // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clPlayer)], null); // create the city patch var cityRadius = radius/3; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id, { 'iberWall': false }); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create woods var bbAngle = randFloat(0, TWO_PI); var bbDist = 13; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); group = new SimpleGroup( [new SimpleObject(oWood, 14,14, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); var mDist = radius - 4; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 60); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = 11; var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oTree1, num, num, 0,4)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); //create docks var dockLocation = getTIPIADBON([ix, iz], [mapSize / 2, mapSize / 2], [-3 , 2.6], 0.5, 3); if (dockLocation !== undefined) placeObject(dockLocation[0], dockLocation[1], "structures/" + getCivCode(id-1) + "_dock", id, playerAngle[i] + PI); } RMS.SetProgress(15); //Create the continent body var fx = fractionToTiles(0.12); var fz = fractionToTiles(0.5); var ix = round(fx); var iz = round(fz); var placer = new ClumpPlacer(mapArea * 0.50, 0.80, 0.08, 10, ix, iz); var terrainPainter = new LayeredPainter( [tWater, tShore, tMainTerrain], // terrains [4, 2] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], avoidClasses(clPlayer, 8)); RMS.SetProgress(20); log("Creating shore jaggedness..."); placer = new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, 1); terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 3, 4); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clLand)], [borderClasses(clLand, 6, 3), avoidClasses(clPlayer, 8)], scaleByMapSize(20, 150) * 2, 150 ); paintTerrainBasedOnHeight(1, 3, 0, tShore); paintTerrainBasedOnHeight(-8, 1, 2, tWater); RMS.SetProgress(25); log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, [avoidClasses(clPlayer, 10), stayClasses(clLand, 3)], scaleByMapSize(100, 200) ); RMS.SetProgress(30); log("Creating hills..."); placer = new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1); terrainPainter = new LayeredPainter( [tCliff, tHill], // terrains [2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 18, 2); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], [avoidClasses(clPlayer, 10, clHill, 15), stayClasses(clLand, 7)], scaleByMapSize(1, 4) * numPlayers ); RMS.SetProgress(34); // calculate desired number of trees for map (based on size) if (random_terrain == g_BiomeSavanna) { var MIN_TREES = 200; var MAX_TREES = 1250; var P_FOREST = 0.02; } else if (random_terrain == g_BiomeTropic) { var MIN_TREES = 1000; var MAX_TREES = 6000; var P_FOREST = 0.6; } else { var MIN_TREES = 500; var MAX_TREES = 3000; var P_FOREST = 0.7; } var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); log("Creating forests..."); var types = [ [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] ]; // some variation var size = numForest / (scaleByMapSize(2,8) * numPlayers) * (random_terrain == g_BiomeSavanna ? 2 : 1); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ClumpPlacer(numForest / num, 0.1, 0.1, 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], [avoidClasses(clPlayer, 6, clForest, 10, clHill, 0), stayClasses(clLand, 7)], num ); } RMS.SetProgress(38); log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter( [[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 7)], scaleByMapSize(15, 45) ); } RMS.SetProgress(42); log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new TerrainPainter(tTier4Terrain); createAreas( placer, painter, [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 7)], scaleByMapSize(15, 45) ); } RMS.SetProgress(46); log("Creating stone mines..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 7)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(50); log("Creating small stone quarries..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 7)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(54); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 7)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(58); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 6)], scaleByMapSize(16, 262), 50 ); RMS.SetProgress(62); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 6)], scaleByMapSize(8, 131), 50 ); RMS.SetProgress(66); log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), stayClasses(clLand, 7)], 3 * numPlayers, 50 ); RMS.SetProgress(70); log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), stayClasses(clLand, 7)], 3 * numPlayers, 50 ); RMS.SetProgress(74); log("Creating fruit bush..."); group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clForest, 0, clPlayer, 8, clHill, 1, clFood, 20), stayClasses(clLand, 7)], - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); RMS.SetProgress(78); log("Creating fish..."); createObjectGroups( new SimpleGroup([new SimpleObject(oFish, 2,3, 0,2)], true, clFood), 0, avoidClasses(clLand, 2, clPlayer, 2, clHill, 0, clFood, 20), 25 * numPlayers, 60 ); RMS.SetProgress(82); log("Creating straggler trees..."); var types = [oTree1, oTree2, oTree4, oTree3]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6), stayClasses(clLand, 9)], num ); } RMS.SetProgress(86); var planetm = random_terrain == g_BiomeTropic ? 8 : 1; log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(90); log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(94); log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, [avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200), 50 ); RMS.SetProgress(98); setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 5, PI / 3)); setWaterWaviness(2); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/persian_highlands.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/persian_highlands.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/persian_highlands.js (revision 19443) @@ -1,444 +1,444 @@ RMS.LoadLibrary("rmgen"); const tCity = "desert_city_tile_pers_dirt"; if (randBool()) // summer { var tDirtMain = ["desert_dirt_persia_1", "desert_dirt_persia_2", "grass_field_dry"]; var tLakebed1 = ["desert_lakebed_dry_b", "desert_lakebed_dry"]; var tLakebed2 = ["desert_lakebed_dry_b", "desert_lakebed_dry", "desert_shore_stones", "desert_shore_stones"]; var tPebbles = "desert_pebbles_rough"; var tCliff = ["desert_cliff_persia_1", "desert_cliff_persia_crumbling"]; var tForestFloor = "medit_grass_field_dry"; var tRocky = "desert_dirt_persia_rocky"; var tRocks = "desert_dirt_persia_rocks"; var tGrass = "grass_field_dry"; var tHill = "desert_cliff_persia_base"; } else //spring { var tDirtMain = ["desert_grass_a", "desert_grass_a", "desert_grass_a", "desert_plants_a"]; var tLakebed1 = ["desert_lakebed_dry_b", "desert_lakebed_dry"]; var tLakebed2 = "desert_grass_a_sand"; var tPebbles = "desert_pebbles_rough"; var tCliff = ["desert_cliff_persia_1", "desert_cliff_persia_crumbling"]; var tForestFloor = "desert_plants_b_persia"; var tRocky = "desert_plants_b_persia"; var tRocks = "desert_plants_a"; var tGrass = "desert_dirt_persia_rocky"; var tHill = "desert_cliff_persia_base"; setTerrainAmbientColor(0.329412, 0.419608, 0.501961); } // gaia entities const oGrapesBush = "gaia/flora_bush_grapes"; const oCamel = "gaia/fauna_camel"; const oFish = "gaia/fauna_fish"; const oSheep = "gaia/fauna_sheep"; const oGoat = "gaia/fauna_goat"; const oLion = "gaia/fauna_lioness"; const oStoneLarge = "gaia/geology_stonemine_desert_badlands_quarry"; const oStoneSmall = "gaia/geology_stone_desert_small"; const oMetalLarge = "gaia/geology_metal_desert_slabs"; const oTamarix = "gaia/flora_tree_tamarix"; const oOak = "gaia/flora_tree_oak"; // decorative props const aBush1 = "actor|props/flora/bush_desert_a.xml"; const aBush2 = "actor|props/flora/bush_desert_dry_a.xml"; const aBush3 = "actor|props/flora/bush_dry_a.xml"; const aBush4 = "actor|props/flora/plant_desert_a.xml"; const aBushes = [aBush1, aBush2, aBush3, aBush4]; const aDecorativeRock = "actor|geology/stone_desert_med.xml"; // terrain + entity (for painting) const pForestO = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor, tDirtMain, tDirtMain]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clPatch = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clCP = createTileClass(); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); placeTerrain(ix, iz, tDirtMain); } } var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // scale radius of player area by map size var radius = scaleByMapSize(15,25); // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // calculate size based on the radius var size = PI * radius * radius; // create the player area var placer = new ClumpPlacer(size, 0.9, 0.5, 10, ix, iz); createArea(placer, paintClass(clPlayer), null); // create the city patch var cityRadius = 10; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tCity, tCity], [3]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oGrapesBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 11; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0), new RandomObject(aBushes, 2,4, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2), new RandomObject(aBushes, 2,4, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 3; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oOak, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } RMS.SetProgress(10); // create patches log("Creating rock patches..."); placer = new ChainPlacer(1, floor(scaleByMapSize(3, 6)), floor(scaleByMapSize(20, 45)), 0); painter = new TerrainPainter(tRocky); createAreas(placer, [painter, paintClass(clPatch)], avoidClasses(clPatch, 2, clPlayer, 0), scaleByMapSize(5, 20) ); RMS.SetProgress(15); var placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), floor(scaleByMapSize(15, 40)), 0); var painter = new TerrainPainter([tRocky, tRocks]); createAreas(placer, [painter, paintClass(clPatch)], avoidClasses(clPatch, 2, clPlayer, 4), scaleByMapSize(15, 50) ); RMS.SetProgress(20); log("Creating dirt patches..."); placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), floor(scaleByMapSize(15, 40)), 0); painter = new TerrainPainter([tGrass]); createAreas(placer, [painter, paintClass(clPatch)], avoidClasses(clPatch, 2, clPlayer, 4), scaleByMapSize(15, 50) ); RMS.SetProgress(25); // create centeral plateau log("Creating centeral plateau..."); var halfSize = mapSize / 2; var oRadius = scaleByMapSize(18, 68); placer = new ChainPlacer(2, floor(scaleByMapSize(5, 13)), floor(scaleByMapSize(35, 200)), 1, halfSize, halfSize, 0, [floor(oRadius)]); painter = new LayeredPainter([tLakebed2, tLakebed1], [6]); var elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, -10, 8); createArea(placer, [painter, elevationPainter, paintClass(clCP)], avoidClasses(clPlayer, 18)); RMS.SetProgress(30); // create hills log("Creating hills..."); var numHills = scaleByMapSize(20, 80); for (var i = 0; i < numHills; ++i) { createMountain( floor(scaleByMapSize(40, 60)), floor(scaleByMapSize(3, 4)), floor(scaleByMapSize(6, 12)), floor(scaleByMapSize(4, 10)), avoidClasses(clPlayer, 7, clCP, 5, clHill, floor(scaleByMapSize(18, 25))), - randInt(mapSize), - randInt(mapSize), + randIntExclusive(0, mapSize), + randIntExclusive(0, mapSize), tCliff, clHill, 14 ); } RMS.SetProgress(35); // calculate desired number of trees for map (based on size) const MIN_TREES = 500; const MAX_TREES = 2500; const P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [ [[tDirtMain, tForestFloor, pForestO], [tForestFloor, pForestO]], [[tDirtMain, tForestFloor, pForestO], [tForestFloor, pForestO]] ]; // some variation var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(floor(scaleByMapSize(1, 2)), floor(scaleByMapSize(2, 5)), floor(size / floor(scaleByMapSize(8, 3))), 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 6, clForest, 10, clHill, 1, clCP, 1), num ); } RMS.SetProgress(50); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4), new RandomObject(aBushes, 2,4, 0,2)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clCP, 1)], scaleByMapSize(2,8), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3), new RandomObject(aBushes, 2,4, 0,2)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clCP, 1)], scaleByMapSize(2,8), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4), new RandomObject(aBushes, 2,4, 0,2)], true, clMetal); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1, clCP, 1)], scaleByMapSize(2,8), 100 ); log("Creating centeral stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4), new RandomObject(aBushes, 2,4, 0,2)], true, clRock); createObjectGroups(group, 0, stayClasses(clCP, 6), 5*scaleByMapSize(5,30), 50 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3), new RandomObject(aBushes, 2,4, 0,2)], true, clRock); createObjectGroups(group, 0, stayClasses(clCP, 6), 5*scaleByMapSize(5,30), 50 ); log("Creating centeral metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4), new RandomObject(aBushes, 2,4, 0,2)], true, clMetal); createObjectGroups(group, 0, stayClasses(clCP, 6), 5*scaleByMapSize(5,30), 50 ); RMS.SetProgress(60); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aDecorativeRock, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(16, 262), 50 ); RMS.SetProgress(65); //create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(8, 131), 50 ); RMS.SetProgress(70); // create goats log("Creating goat..."); group = new SimpleGroup( [new SimpleObject(oGoat, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clCP, 2), 3 * numPlayers, 50 ); // create sheep log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oSheep, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clCP, 2), 3 * numPlayers, 50 ); // create grape bush log("Creating grape bush..."); group = new SimpleGroup( [new SimpleObject(oGrapesBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10, clCP, 2), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); // create camels log("Creating camels..."); group = new SimpleGroup( [new SimpleObject(oCamel, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, stayClasses(clCP, 2), 3 * numPlayers, 50 ); RMS.SetProgress(90); // create straggler trees log("Creating straggler trees..."); var types = [oOak]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6, clCP, 2), num ); } setSunColor(1.0, 0.796, 0.374); setSunElevation(PI / 6); setSunRotation(-1.86532); setFogFactor(0.2); setFogThickness(0.0); setFogColor(0.852, 0.746, 0.493); setPPEffect("hdr"); setPPContrast(0.75); setPPSaturation(0.45); setPPBloom(0.3); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/pyrenean_sierra.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/pyrenean_sierra.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/pyrenean_sierra.js (revision 19443) @@ -1,869 +1,869 @@ RMS.LoadLibrary("rmgen"); // Some functions // This is the basic SmoothElevationPainter with a random component thrown in. function SemiRandomElevationPainter(elevation, blendRadius,roughness) { this.elevation = elevation; this.blendRadius = blendRadius; if (!roughness) this.roughness = 5; else this.roughness = roughness; } SemiRandomElevationPainter.prototype.checkInArea = function(areaID, x, z) { // Check given tile and its neighbors return ( (g_Map.inMapBounds(x, z) && g_Map.area[x][z] == areaID) || (g_Map.inMapBounds(x-1, z) && g_Map.area[x-1][z] == areaID) || (g_Map.inMapBounds(x, z-1) && g_Map.area[x][z-1] == areaID) || (g_Map.inMapBounds(x-1, z-1) && g_Map.area[x-1][z-1] == areaID) ); }; SemiRandomElevationPainter.prototype.paint = function(area) { var pointQ = []; var pts = area.points; var heightPts = []; var mapSize = getMapSize()+1; var saw = new Array(mapSize); var dist = new Array(mapSize); var gotHeightPt = new Array(mapSize); var newHeight = new Array(mapSize); // init typed arrays for (var i = 0; i < mapSize; ++i) { saw[i] = new Uint8Array(mapSize); // bool / uint8 dist[i] = new Uint16Array(mapSize); // uint16 gotHeightPt[i] = new Uint8Array(mapSize); // bool / uint8 newHeight[i] = new Float32Array(mapSize); // float32 } var length = pts.length; var areaID = area.getID(); // get a list of all points for (var i=0; i < length; i++) { var x = pts[i].x; var z = pts[i].z; for (var dx=-1; dx <= 2; dx++) { var nx = x+dx; for (var dz=-1; dz <= 2; dz++) { var nz = z+dz; if (g_Map.validH(nx, nz) && !gotHeightPt[nx][nz]) { gotHeightPt[nx][nz] = 1; heightPts.push(new PointXZ(nx, nz)); newHeight[nx][nz] = g_Map.height[nx][nz]; } } } } // push edge points for (var i=0; i < length; i++) { var x = pts[i].x; var z = pts[i].z; for (var dx=-1; dx <= 2; dx++) { var nx = x+dx; for (var dz=-1; dz <= 2; dz++) { var nz = z+dz; if (g_Map.validH(nx, nz) && !this.checkInArea(areaID, nx, nz) && !saw[nx][nz]) { saw[nx][nz]= 1; dist[nx][nz] = 0; pointQ.push(new PointXZ(nx, nz)); } } } } // do BFS inwards to find distances to edge while(pointQ.length) { var pt = pointQ.shift(); var px = pt.x; var pz = pt.z; var d = dist[px][pz]; // paint if in area if (g_Map.validH(px, pz) && this.checkInArea(areaID, px, pz)) { if (d <= this.blendRadius) { var a = (d-1) / this.blendRadius; newHeight[px][pz] += a*this.elevation + randFloat(-this.roughness,this.roughness); } else { // also happens when blendRadius == 0 newHeight[px][pz] += this.elevation + randFloat(-this.roughness,this.roughness); } } // enqueue neighbours for (var dx=-1; dx <= 1; dx++) { var nx = px+dx; for (var dz=-1; dz <= 1; dz++) { var nz = pz+dz; if (g_Map.validH(nx, nz) && this.checkInArea(areaID, nx, nz) && !saw[nx][nz]) { saw[nx][nz] = 1; dist[nx][nz] = d+1; pointQ.push(new PointXZ(nx, nz)); } } } } length = heightPts.length; // smooth everything out for (var i = 0; i < length; ++i) { var pt = heightPts[i]; var px = pt.x; var pz = pt.z; if (this.checkInArea(areaID, px, pz)) { var sum = 8 * newHeight[px][pz]; var count = 8; for (var dx=-1; dx <= 1; dx++) { var nx = px+dx; for (var dz=-1; dz <= 1; dz++) { var nz = pz+dz; if (g_Map.validH(nx, nz)) { sum += newHeight[nx][nz]; count++; } } } g_Map.height[px][pz] = sum/count; } } }; TILE_CENTERED_HEIGHT_MAP = true; const tGrassSpecific = ["new_alpine_grass_d","new_alpine_grass_d", "new_alpine_grass_e"]; const tGrass = ["new_alpine_grass_d", "new_alpine_grass_b", "new_alpine_grass_e"]; const tGrassMidRange = ["new_alpine_grass_b", "alpine_grass_a"]; const tGrassHighRange = ["new_alpine_grass_a", "alpine_grass_a", "alpine_grass_rocky"]; const tHighRocks = ["alpine_cliff_b", "alpine_cliff_c","alpine_cliff_c", "alpine_grass_rocky"]; const tSnowedRocks = ["alpine_cliff_b", "alpine_cliff_snow"]; const tTopSnow = ["alpine_snow_rocky","alpine_snow_a"]; const tTopSnowOnly = ["alpine_snow_a"]; const tDirtyGrass = ["new_alpine_grass_d","alpine_grass_d","alpine_grass_c", "alpine_grass_b"]; const tLushGrass = ["new_alpine_grass_a","new_alpine_grass_d"]; const tMidRangeCliffs = ["alpine_cliff_b","alpine_cliff_c"]; const tHighRangeCliffs = ["alpine_mountainside","alpine_cliff_snow" ]; const tPass = ["alpine_cliff_b", "alpine_cliff_c", "alpine_grass_rocky", "alpine_grass_rocky", "alpine_grass_rocky"]; const tSand = ["beach_c", "beach_d"]; const tWetSand = ["sand_wet_a", "sand_wet_b"]; const tSandTransition = ["beach_scrub_50_"]; const tWater = ["sand_wet_a","sand_wet_b","sand_wet_b","sand_wet_b"]; const tGrassLandForest = "alpine_forrestfloor"; const tGrassLandForest2 = "alpine_grass_d"; const tForestTransition = ["new_alpine_grass_d", "new_alpine_grass_b","alpine_grass_d"]; const tGrassDForest = "alpine_forrestfloor_snow"; const tCliff = ["alpine_cliff_a", "alpine_cliff_b"]; const tGrassA = "alpine_grass_snow_50"; const tGrassB = ["alpine_grass_snow_50", "alpine_dirt_snow"]; const tGrassC = ["alpine_snow_rocky"]; const tDirt = ["alpine_dirt_snow", "alpine_snow_a"]; const tRoad = "new_alpine_citytile"; const tRoadWild = "new_alpine_citytile"; const tShore = "alpine_shore_rocks_icy"; // gaia entities const oBeech = "gaia/flora_tree_euro_beech"; const oPine = "gaia/flora_tree_aleppo_pine"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oGoat = "gaia/fauna_goat"; const oFish = "gaia/fauna_fish"; const oRabbit = "gaia/fauna_rabbit"; const oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; const oStoneSmall = "gaia/geology_stone_alpine_a"; const oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props const aRain = "actor|particle/rain_shower.xml"; const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; const aGrassShort = "actor|props/flora/grass_soft_large.xml"; const aRockLarge = "actor|geology/stone_granite_med.xml"; const aRockMedium = "actor|geology/stone_granite_med.xml"; const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; const aLillies = "actor|props/flora/water_lillies.xml"; const aBushMedium = "actor|props/flora/bush_medit_me.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const pForestLand = [tGrassLandForest + TERRAIN_SEPARATOR + oPine,tGrassLandForest + TERRAIN_SEPARATOR + oBeech, tGrassLandForest2 + TERRAIN_SEPARATOR + oPine,tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, tGrassLandForest,tGrassLandForest2,tGrassLandForest2,tGrassLandForest2]; const pForestLandLight = [tGrassLandForest + TERRAIN_SEPARATOR + oPine,tGrassLandForest + TERRAIN_SEPARATOR + oBeech, tGrassLandForest2 + TERRAIN_SEPARATOR + oPine,tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, tGrassLandForest,tGrassLandForest2,tForestTransition,tGrassLandForest2, tGrassLandForest,tForestTransition,tGrassLandForest2,tForestTransition, tGrassLandForest2,tGrassLandForest2,tGrassLandForest2,tGrassLandForest2]; const pForestLandVeryLight = [ tGrassLandForest2 + TERRAIN_SEPARATOR + oPine,tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, tForestTransition,tGrassLandForest2,tForestTransition,tForestTransition,tForestTransition, tGrassLandForest,tForestTransition,tGrassLandForest2,tForestTransition, tGrassLandForest2,tGrassLandForest2,tGrassLandForest2,tGrassLandForest2]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clDirt = createTileClass(); var clLush = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clPass = createTileClass(); var clPyrenneans = createTileClass(); var clPass = createTileClass(); var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); // Initial Terrain Creation // I'll use very basic noised sinusoidal functions to give the terrain a way aspect // It looks like we can't go higher than ≈ 75. Given this I'll lower the ground const baseHeight = -6; setWaterHeight(8); // let's choose the angle of the pyreneans var MoutainAngle = randFloat(0,TWO_PI); var lololo = randFloat(-PI/12,-PI/12); // used by oceans var baseHeights = []; for (var ix = 0; ix < mapSize; ix++) { baseHeights.push([]); for (var iz = 0; iz < mapSize; iz++) { if (g_Map.inMapBounds(ix,iz)) { placeTerrain(ix, iz, tGrass); setHeight(ix,iz,baseHeight +randFloat(-1,1) + scaleByMapSize(1,3)*(cos(ix/scaleByMapSize(5,30))+sin(iz/scaleByMapSize(5,30)))); baseHeights[ix].push( baseHeight +randFloat(-1,1) + scaleByMapSize(1,3)*(cos(ix/scaleByMapSize(5,30))+sin(iz/scaleByMapSize(5,30))) ); } else baseHeights[ix].push(-100); } } // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = primeSortPlayers(sortPlayers(playerIDs)); // place players // TODO: sort players by team var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); for (var i = 0; i < numPlayers; i++) { if ( i%2 == 1) playerAngle[i] = MoutainAngle+lololo + PI/2 + i/numPlayers*(PI/3) + (1-i/numPlayers)*(-PI/3); else playerAngle[i] = MoutainAngle + lololo - PI/2 + (i+1)/numPlayers*(PI/3) + (1-(i+1)/numPlayers)*(-PI/3); playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); ix = round(fx); iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 100); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPine, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(30); log ("Creating the pyreneans..."); // This is the basic orientation of the pyreneans var MountainStartX = fractionToTiles(0.5) + cos(MoutainAngle)*fractionToTiles(0.34); var MountainStartZ = fractionToTiles(0.5) + sin(MoutainAngle)*fractionToTiles(0.34); var MountainEndX = fractionToTiles(0.5) - cos(MoutainAngle)*fractionToTiles(0.34); var MountainEndZ = fractionToTiles(0.5) - sin(MoutainAngle)*fractionToTiles(0.34); var MountainHeight = scaleByMapSize(50,65); // Number of peaks var NumOfIterations = scaleByMapSize(100,1000); var randomNess = randFloat(-scaleByMapSize(1,12),scaleByMapSize(1,12)); for (var i = 0; i < NumOfIterations; i++) { RMS.SetProgress(45 * i/NumOfIterations + 30 * (1-i/NumOfIterations)); var position = i/NumOfIterations; var width = scaleByMapSize(15,55); var randHeight2 = randFloat(0,10) + MountainHeight; for (var dist = 0; dist < width*3; dist++) { var okDist = dist/3; var S1x = round((MountainStartX * (1-position) + MountainEndX*position) + randomNess*cos(position*3.14*4) + cos(MoutainAngle+PI/2)*okDist); var S1z = round((MountainStartZ * (1-position) + MountainEndZ*position) + randomNess*sin(position*3.14*4) + sin(MoutainAngle+PI/2)*okDist); var S2x = round((MountainStartX * (1-position) + MountainEndX*position) + randomNess*cos(position*3.14*4) + cos(MoutainAngle-PI/2)*okDist); var S2z = round((MountainStartZ * (1-position) + MountainEndZ*position) + randomNess*sin(position*3.14*4) + sin(MoutainAngle-PI/2)*okDist); // complicated sigmoid // Ranges is 0-1, FormX is 0-1 too. var FormX = (-2*(1-okDist/width)+1.9) - 4*(2*(1-okDist/width)-randFloat(0.9,1.1))*(2*(1-okDist/width)-randFloat(0.9,1.1))*(2*(1-okDist/width)-randFloat(0.9,1.1)); var Formula = (1/(1 + Math.exp(FormX))); // If we're too far from the border, we flatten Formula *= (0.2 - Math.max(0,abs(0.5 - position) - 0.3)) * 5; var randHeight = randFloat(-9,9) * Formula; var height = baseHeights[S1x][S1z]; setHeight(S1x,S1z, height + randHeight2 * Formula + randHeight ); var height = baseHeights[S2x][S2z]; setHeight(S2x,S2z, height + randHeight2 * Formula + randHeight ); if (getHeight(S1x,S1z) > 15) addToClass(S1x,S1z, clPyrenneans); if (getHeight(S2x,S2z) > 15) addToClass(S2x,S2z, clPyrenneans); } } // Allright now slight smoothing (decreasing with height) for (var ix = 1; ix < mapSize-1; ix++) { for (var iz = 1; iz < mapSize-1; iz++) { if (g_Map.inMapBounds(ix,iz) && checkIfInClass(ix,iz,clPyrenneans) ) { var NB = getNeighborsHeight(ix,iz); var index = 9/(1 + Math.max(0,getHeight(ix,iz)/7)); setHeight(ix,iz, (getHeight(ix,iz)*(9-index) + NB*index)/9 ); } } } RMS.SetProgress(48); // Okay so the mountains are pretty much here. // Making the passes var passWidth = scaleByMapSize(15,100) /1.8; var S1x = round((MountainStartX * (0.35) + MountainEndX*0.65) + cos(MoutainAngle+PI/2)*passWidth); var S1z = round((MountainStartZ * (0.35) + MountainEndZ*0.65) + sin(MoutainAngle+PI/2)*passWidth); var S2x = round((MountainStartX * (0.35) + MountainEndX*0.65) + cos(MoutainAngle-PI/2)*passWidth); var S2z = round((MountainStartZ * (0.35) + MountainEndZ*0.65) + sin(MoutainAngle-PI/2)*passWidth); PassMaker(S1x, S1z, S2x, S2z, 4, 7, (getHeight(S1x,S1z) + getHeight(S2x,S2z))/2.0, MountainHeight-25, 2, clPass); S1x = round((MountainStartX * (0.65) + MountainEndX*0.35) + cos(MoutainAngle+PI/2)*passWidth); S1z = round((MountainStartZ * (0.65) + MountainEndZ*0.35) + sin(MoutainAngle+PI/2)*passWidth); S2x = round((MountainStartX * (0.65) + MountainEndX*0.35) + cos(MoutainAngle-PI/2)*passWidth); S2z = round((MountainStartZ * (0.65) + MountainEndZ*0.35) + sin(MoutainAngle-PI/2)*passWidth); PassMaker(S1x, S1z, S2x, S2z, 4, 7, (getHeight(S1x,S1z) + getHeight(S2x,S2z))/2.0, MountainHeight-25, 2, clPass); RMS.SetProgress(50); // Smoothing the mountains for (var ix = 1; ix < mapSize-1; ix++) { for (var iz = 1; iz < mapSize-1; iz++) { if ( g_Map.inMapBounds(ix,iz) && checkIfInClass(ix,iz,clPyrenneans) ) { var NB = getNeighborsHeight(ix,iz); var index = 9/(1 + Math.max(0,(getHeight(ix,iz)-10)/7)); setHeight(ix,iz, (getHeight(ix,iz)*(9-index) + NB*index)/9 ); baseHeights[ix][iz] = (getHeight(ix,iz)*(9-index) + NB*index)/9; } } } log ("creating Oceans"); // ALlright for hacky reasons I can't use a smooth Elevation Painter, that wouldn't work. // I'll use a harsh one, and then smooth it out var OceanX = fractionToTiles(0.5) + cos(MoutainAngle + lololo)*fractionToTiles(0.48); var OceanZ = fractionToTiles(0.5) + sin(MoutainAngle + lololo)*fractionToTiles(0.48); var radius = fractionToTiles(0.18); var size = radius*radius*PI; var placer = new ClumpPlacer(size, 0.9, 0.05, 10, OceanX, OceanZ); var elevationPainter = new ElevationPainter(-22); createArea(placer, [paintClass(clWater),elevationPainter], null); OceanX = fractionToTiles(0.5) + cos(PI + MoutainAngle + lololo)*fractionToTiles(0.48); OceanZ = fractionToTiles(0.5) + sin(PI + MoutainAngle + lololo)*fractionToTiles(0.48); radius = fractionToTiles(0.18); size = radius*radius*PI; placer = new ClumpPlacer(size, 0.9, 0.05, 10, OceanX, OceanZ); elevationPainter = new ElevationPainter(-22); createArea(placer, [paintClass(clWater),elevationPainter], null); // Smoothing around the water, then going a bit random for (var ix = 1; ix < mapSize-1; ix++) { for (var iz = 1; iz < mapSize-1; iz++) { if ( g_Map.inMapBounds(ix,iz) && getTileClass(clWater).countInRadius(ix,iz,5,true) > 0 ) { // Allright smoothing // I'll have to hack again. var averageHeight = 0; var size = 5; if (getTileClass(clPyrenneans).countInRadius(ix,iz,1,true) > 0) size = 1; else if (getTileClass(clPyrenneans).countInRadius(ix,iz,2,true) > 0) size = 2; else if (getTileClass(clPyrenneans).countInRadius(ix,iz,3,true) > 0) size = 3; else if (getTileClass(clPyrenneans).countInRadius(ix,iz,4,true) > 0) size = 4; var todivide = 0; for (var xx = -size; xx <= size;xx++) for (var yy = -size; yy <= size;yy++) { if (g_Map.inMapBounds(ix + xx,iz + yy) && (xx != 0 || yy != 0)){ averageHeight += getHeight(ix + xx,iz + yy) / (abs(xx)+abs(yy)); todivide += 1/(abs(xx)+abs(yy)); } } averageHeight += getHeight(ix,iz)*2; averageHeight /= (todivide+2); setHeight(ix,iz, averageHeight ); //baseHeights[ix][iz] = averageHeight; } if ( g_Map.inMapBounds(ix,iz) && getTileClass(clWater).countInRadius(ix,iz,4,true) > 0 && getTileClass(clWater).countInRadius(ix,iz,4) > 0 ) setHeight(ix,iz, getHeight(ix,iz) + randFloat(-1,1)); } } RMS.SetProgress(55); //create hills log ("Creating hills..."); placer = new ClumpPlacer(scaleByMapSize(60, 120), 0.3, 0.06, 5); painter = new SemiRandomElevationPainter(7, 4,1); var terrainPainter = new TerrainPainter(tGrassSpecific); createAreas( placer, [painter,terrainPainter, paintClass(clHill)], avoidClasses(clWater, 5, clPlayer, 20, clBaseResource, 6, clPyrenneans, 2), scaleByMapSize(5, 35) ); // create forests log("Creating forests..."); var types = [ [tForestTransition,pForestLandVeryLight, pForestLandLight, pForestLand]]; var size = scaleByMapSize(40,115)*PI; var num = floor(scaleByMapSize(8,40) / types.length); for (var i = 0; i < types.length; ++i) { placer = new ClumpPlacer(size, 0.2, 0.1, 1); painter = new LayeredPainter( types[i], [scaleByMapSize(1,2),scaleByMapSize(3,6),scaleByMapSize(3,6)] ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clPyrenneans,0, clForest, 7, clWater, 2), num); } RMS.SetProgress(60); log("Creating lone trees..."); var num = scaleByMapSize(80,400); var group = new SimpleGroup([new SimpleObject(oPine, 1,2, 1,3),new SimpleObject(oBeech, 1,2, 1,3)], true, clForest); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 8,clPyrenneans, 1), num, 20 ); // Painting log("Painting the map"); var terrainGrass = createTerrain(tGrass); var terrainGrassMidRange = createTerrain(tGrassMidRange); var terrainGrassHighRange = createTerrain(tGrassHighRange); var terrainRocks = createTerrain(tHighRocks); var terrainRocksSnow = createTerrain(tSnowedRocks); var terrainTopSnow = createTerrain(tTopSnow); var terrainTopSnowOnly = createTerrain(tTopSnowOnly); var terrainMidRangeCliff = createTerrain(tMidRangeCliffs); var terrainHighRangeCliff = createTerrain(tHighRangeCliffs); var terrainPass = createTerrain(tPass); var terrainSand = createTerrain(tSand); var terrainWetSand = createTerrain(tWetSand); var terrainSandTransition = createTerrain(tSandTransition); var terrainWater = createTerrain(tWater); /* // first pass: who's water? for (var sandx = 0; sandx < mapSize; sandx++) for (var sandz = 0; sandz < mapSize; sandz++) if (getHeight(sandx,sandz) < 0) addToClass(sandx,sandz,clWater); */ // second pass: who's not water for (var x = 0; x < mapSize; x++) { for (var z = 0; z < mapSize; z++) { var height = getHeight(x,z); var heightDiff = getHeightDifference(x,z); if (getTileClass(clPyrenneans).countInRadius(x,z,2,true) > 0) { if (height < 6) { if (heightDiff < 5) terrainGrass.place(x,z); else terrainMidRangeCliff.place(x,z); } else if (height >= 6 && height < 18) { if (heightDiff < 8) terrainGrassMidRange.place(x,z); else terrainMidRangeCliff.place(x,z); } else if (height >= 18 && height < 30) { if (heightDiff < 8) terrainGrassHighRange.place(x,z); else terrainMidRangeCliff.place(x,z); } else if (height >= 30 && height < MountainHeight-20) { if (heightDiff < 8) terrainRocks.place(x,z); else terrainHighRangeCliff.place(x,z); } else if (height >= MountainHeight-20 && height < MountainHeight-10) { if (heightDiff < 7) terrainRocksSnow.place(x,z); else terrainHighRangeCliff.place(x,z); } else if (height >= MountainHeight-10) { if (heightDiff < 6) terrainTopSnowOnly.place(x,z); else terrainTopSnow.place(x,z); } if (height >= 30 && getTileClass(clPass).countInRadius(x,z,2,true) > 0) if (heightDiff < 5) terrainPass.place(x,z); } if (height > -14 && height <= -2 && getTileClass(clWater).countInRadius(x,z,2,true) > 0) { if (heightDiff < 2.5) terrainSand.place(x,z); else terrainMidRangeCliff.place(x,z); } else if (height > -14 && height <= 0 && getTileClass(clWater).countInRadius(x,z,3,true) > 0) { if (heightDiff < 2.5) terrainSandTransition.place(x,z); else terrainMidRangeCliff.place(x,z); } else if (height <= -14) { terrainWater.place(x,z); } } } // create dirt patches log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 20), scaleByMapSize(5, 40), scaleByMapSize(8, 60)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new TerrainPainter(tDirtyGrass); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 3, clForest, 0, clPyrenneans,5, clHill, 0, clDirt, 5, clPlayer, 6), scaleByMapSize(15, 45) ); } // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new TerrainPainter(tLushGrass); createAreas( placer, [painter,paintClass(clLush)], avoidClasses(clWater, 3, clForest, 0, clPyrenneans,5, clHill, 0, clDirt, 5, clPlayer, 6), scaleByMapSize(15, 45) ); } RMS.SetProgress(70); // making more in dirt areas so as to appear different log("Creating small grass tufts..."); var group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clHill, 2, clPlayer, 5, clDirt, 0, clPyrenneans,2), scaleByMapSize(13, 200) ); createObjectGroups(group, 0, stayClasses(clDirt,1), scaleByMapSize(13, 200),10); log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clHill, 2, clPlayer, 5, clDirt, 1, clForest, 0, clPyrenneans,2), scaleByMapSize(13, 200) ); createObjectGroups(group, 0, stayClasses(clDirt,1), scaleByMapSize(13, 200),10); RMS.SetProgress(75); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clPlayer, 1, clPyrenneans, 1), scaleByMapSize(13, 200), 50 ); RMS.SetProgress(80); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 8, clPyrenneans, 1), scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 8, clPyrenneans, 1), scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 8, clRock, 5, clPyrenneans, 1), scaleByMapSize(4,16), 100 ); RMS.SetProgress(85); log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0), scaleByMapSize(16, 262), 50 ); log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0), scaleByMapSize(8, 131), 50 ); RMS.SetProgress(90); log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clPyrenneans, 1, clFood, 15), 3 * numPlayers, 50 ); log("Creating rabbit..."); group = new SimpleGroup( [new SimpleObject(oRabbit, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clPyrenneans, 1, clFood,15), 3 * numPlayers, 50 ); log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)],true, clFood ); -createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clPyrenneans, 1, clFood, 10), randInt(1, 4) * numPlayers + 2, 50 ); +createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clPyrenneans, 1, clFood, 10), randIntInclusive(1, 4) * numPlayers + 2, 50); log("Creating fish..."); group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clFood, 15), stayClasses(clWater, 6)], 20 * numPlayers, 60 ); setSunElevation(randFloat(PI/5, PI / 3)); setSunRotation(randFloat(0, TWO_PI)); setSkySet("cumulus"); setSunColor(0.73,0.73,0.65); setTerrainAmbientColor(0.45,0.45,0.50); setUnitsAmbientColor(0.4,0.4,0.4); setWaterColor(0.263, 0.353, 0.616); setWaterTint(0.104, 0.172, 0.563); setWaterWaviness(5.0); setWaterType("ocean"); setWaterMurkiness(0.83); ExportMap(); function getNeighborsHeight(x1, z1) { var toCheck = [ [-1,-1], [-1,0], [-1,1], [0,1], [1,1], [1,0], [1,-1], [0,-1] ]; var height = 0; for (var i in toCheck) { var xx = x1 + toCheck[i][0]; var zz = z1 + toCheck[i][1]; height += getHeight(round(xx),round(zz)); } height /= 8; return height; } // Taken from Corsica vs Sardinia with tweaks function PassMaker(x1, z1, x2, z2, startWidth, centerWidth, startElevation, centerElevation, smooth, tileclass, terrain) { var mapSize = g_Map.size; var stepNB = sqrt((x2-x1)*(x2-x1) + (z2-z1)*(z2-z1)) + 2; var startHeight = startElevation; var finishHeight = centerElevation; for (var step = 0; step <= stepNB; step+=0.5) { var ix = ((stepNB-step)*x1 + x2*step) / stepNB; var iz = ((stepNB-step)*z1 + z2*step) / stepNB; var width = (abs(step - stepNB/2.0) *startWidth + (stepNB/2 - abs(step - stepNB/2.0)) * centerWidth ) / (stepNB/2); var oldDirection = [x2-x1, z2-z1]; // let's get the perpendicular direction var direction = [ -oldDirection[1],oldDirection[0] ]; if (abs(direction[0]) > abs(direction[1])) { direction[1] = direction[1] / abs(direction[0]); if (direction[0] > 0) direction[0] = 1; else direction[0] = -1; } else { direction[0] = direction[0] / abs(direction[1]); if (direction[1] > 0) direction[1] = 1; else direction[1] = -1; } for (var po = -Math.floor(width/2.0); po <= Math.floor(width/2.0); po+=0.5) { var rx = po*direction[0]; var rz = po*direction[1]; var relativeWidth = abs(po / Math.floor(width/2)); var targetHeight = (abs(step - stepNB/2.0) *startHeight + (stepNB/2 - abs(step - stepNB/2.0)) * finishHeight ) / (stepNB/2); if (round(ix + rx) < mapSize && round(iz + rz) < mapSize && round(ix + rx) >= 0 && round(iz + rz) >= 0) { // smoothing the sides if ( abs(abs(po) - abs(Math.floor(width/2.0))) < smooth) { var localHeight = getHeight(round(ix + rx), round(iz + rz)); var localPart = smooth - abs(abs(po) - abs(Math.floor(width/2.0))); var targetHeight = (localHeight * localPart + targetHeight * (1/localPart) )/ (localPart + 1/localPart); } g_Map.setHeight(round(ix + rx), round(iz + rz), targetHeight); if (tileclass != null) addToClass(round(ix + rx), round(iz + rz), tileclass); if (terrain != null) placeTerrain(round(ix + rx), round(iz + rz), terrain); } } } } // no need for preliminary rounding function getHeightDifference(x1, z1) { x1 = round(x1); z1 = round(z1); var height = getHeight(x1,z1); if (!g_Map.inMapBounds(x1,z1)) return 0; // I wanna store the height difference with any neighbor var toCheck = [ [-1,-1], [-1,0], [-1,1], [0,1], [1,1], [1,0], [1,-1], [0,-1] ]; var diff = 0; var todiv = 0; for (var i in toCheck) { var xx = round(x1 + toCheck[i][0]); var zz = round(z1 + toCheck[i][1]); if (g_Map.inMapBounds(xx,zz)) { diff += abs(getHeight(xx,zz) - height); todiv++; } } if (todiv > 0) diff /= todiv; return diff; } Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js (revision 19443) @@ -1,538 +1,538 @@ const PI = Math.PI; const TWO_PI = 2 * Math.PI; const TERRAIN_SEPARATOR = "|"; const SEA_LEVEL = 20.0; const CELL_SIZE = 4; const HEIGHT_UNITS_PER_METRE = 92; const MIN_MAP_SIZE = 128; const MAX_MAP_SIZE = 512; const MAP_BORDER_WIDTH = 3; const FALLBACK_CIV = "athen"; /** * 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; const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL; // Default angle for buildings const BUILDING_ORIENTATION = - PI / 4; function fractionToTiles(f) { return g_Map.size * f; } function tilesToFraction(t) { return t / g_Map.size; } function fractionToSize(f) { return getMapArea() * f; } function sizeToFraction(s) { return s / getMapArea(); } function scaleByMapSize(min, max) { return min + (max - min) * (g_Map.size - MIN_MAP_SIZE) / (MAX_MAP_SIZE - MIN_MAP_SIZE); } function cos(x) { return Math.cos(x); } function sin(x) { return Math.sin(x); } function abs(x) { return Math.abs(x); } function round(x) { return Math.round(x); } function lerp(a, b, t) { return a + (b-a) * t; } function sqrt(x) { return Math.sqrt(x); } function ceil(x) { return Math.ceil(x); } function floor(x) { return Math.floor(x); } function max(a, b) { return a > b ? a : b; } function min(a, b) { return a < b ? a : b; } /** * Retries the given function with those arguments as often as specified. */ function retryPlacing(placeFunc, placeArgs, retryFactor, amount, getResult) { let maxFail = amount * retryFactor; let results = []; let good = 0; let bad = 0; while (good < amount && bad <= maxFail) { let result = placeFunc(placeArgs); if (result !== undefined) { ++good; if (getResult) results.push(result); } else ++bad; } return getResult ? results : good; } /** * Helper function for randomly placing areas and groups on the map. */ function randomizePlacerCoordinates(placer, halfMapSize) { if (!!g_MapSettings.CircularMap) { // Polar coordinates let r = halfMapSize * Math.sqrt(randFloat()); // uniform distribution let theta = randFloat(0, 2 * PI); placer.x = Math.floor(r * Math.cos(theta)) + halfMapSize; placer.z = Math.floor(r * Math.sin(theta)) + halfMapSize; } else { // Rectangular coordinates - placer.x = randInt(g_Map.size); - placer.z = randInt(g_Map.size); + placer.x = randIntExclusive(0, g_Map.size); + placer.z = randIntExclusive(0, g_Map.size); } } /** * Helper function for randomly placing areas and groups in the given areas. */ function randomizePlacerCoordinatesFromAreas(placer, areas) { let pt = pickRandom(pickRandom(areas).points); placer.x = pt.x; placer.z = pt.z; } /** * 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 (args) { randomizePlacerCoordinates(args.placer, args.halfMapSize); return g_Map.createArea(args.placer, args.painter, args.constraint); }; let args = { "placer": centeredPlacer, "painter": painter, "constraint": constraint, "halfMapSize": g_Map.size / 2 }; return retryPlacing(placeFunc, args, retryFactor, amount, true); } /** * 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) { if (!areas.length) return []; let placeFunc = function (args) { randomizePlacerCoordinatesFromAreas(args.placer, args.areas); return g_Map.createArea(args.placer, args.painter, args.constraint); }; let args = { "placer": centeredPlacer, "painter": painter, "constraint": constraint, "areas": areas, "halfMapSize": g_Map.size / 2 }; return retryPlacing(placeFunc, args, retryFactor, amount, true); } /** * Attempts to place the given number of groups in random places of the map. * Returns the number of actually placed groups. */ function createObjectGroups(placer, player, constraint, amount, retryFactor = 10) { let placeFunc = function (args) { randomizePlacerCoordinates(args.placer, args.halfMapSize); return createObjectGroup(args.placer, args.player, args.constraint); }; let args = { "placer": placer, "player": player, "constraint": constraint, "halfMapSize": g_Map.size / 2 - 3 }; return retryPlacing(placeFunc, args, retryFactor, amount, false); } /** * Attempts to place the given number of groups in random places of the given areas. * Returns the number of actually placed groups. */ function createObjectGroupsByAreas(placer, player, constraint, amount, retryFactor, areas) { if (!areas.length) return 0; let placeFunc = function (args) { randomizePlacerCoordinatesFromAreas(args.placer, args.areas); return createObjectGroup(args.placer, args.player, args.constraint); }; let args = { "placer": placer, "player": player, "constraint": constraint, "areas": areas }; return retryPlacing(placeFunc, args, retryFactor, amount, false); } function createTerrain(terrain) { if (!(terrain instanceof Array)) return createSimpleTerrain(terrain); return new RandomTerrain(terrain.map(t => createTerrain(t))); } function createSimpleTerrain(terrain) { if (typeof(terrain) != "string") throw("createSimpleTerrain expects string as input, received "+terrain); // Split string by pipe | character, this allows specifying terrain + tree type in single string let params = terrain.split(TERRAIN_SEPARATOR, 2); if (params.length != 2) return new SimpleTerrain(terrain); return new SimpleTerrain(params[0], params[1]); } function placeObject(x, z, type, player, angle) { if (g_Map.validT(x, z, MAP_BORDER_WIDTH)) g_Map.addObject(new Entity(type, player, x, z, angle)); } function placeTerrain(x, z, terrain) { // convert terrain param into terrain object g_Map.placeTerrain(x, z, createTerrain(terrain)); } function isCircularMap() { return !!g_MapSettings.CircularMap; } function getMapBaseHeight() { return g_MapSettings.BaseHeight || 0; } function createTileClass() { return g_Map.createTileClass(); } function getTileClass(id) { if (!g_Map.validClass(id)) return undefined; return g_Map.tileClasses[id]; } function createArea(placer, painter, constraint) { return g_Map.createArea(placer, painter, constraint); } function createObjectGroup(placer, player, constraint) { return g_Map.createObjectGroup(placer, player, constraint); } function getMapSize() { return g_Map.size; } function getMapArea() { return g_Map.size * g_Map.size; } function getNumPlayers() { return g_MapSettings.PlayerData.length - 1; } function getCivCode(player) { if (g_MapSettings.PlayerData[player+1].Civ) return g_MapSettings.PlayerData[player+1].Civ; warn("undefined civ specified for player " + (player + 1) + ", falling back to '" + FALLBACK_CIV + "'"); return FALLBACK_CIV; } function areAllies(player1, player2) { if (g_MapSettings.PlayerData[player1+1].Team === undefined || g_MapSettings.PlayerData[player2+1].Team === undefined || g_MapSettings.PlayerData[player2+1].Team == -1 || g_MapSettings.PlayerData[player1+1].Team == -1) return false; return g_MapSettings.PlayerData[player1+1].Team === g_MapSettings.PlayerData[player2+1].Team; } function getPlayerTeam(player) { if (g_MapSettings.PlayerData[player+1].Team === undefined) return -1; return g_MapSettings.PlayerData[player+1].Team; } /** * Sorts an array of player IDs by team index. Players without teams come first. * Randomize order for players of the same team. */ function sortPlayers(playerIndices) { return shuffleArray(playerIndices).sort((p1, p2) => getPlayerTeam(p1 - 1) - getPlayerTeam(p2 - 1)); } function primeSortPlayers(playerIndices) { if (!playerIndices.length) return []; let prime = []; for (let i = 0; i < Math.ceil(playerIndices.length / 2); ++i) { prime.push(playerIndices[i]); prime.push(playerIndices[playerIndices.length - 1 - i]); } return prime; } function getStartingEntities(player) { let civ = getCivCode(player); if (!g_CivData[civ] || !g_CivData[civ].StartEntities || !g_CivData[civ].StartEntities.length) { warn("Invalid or unimplemented civ '"+civ+"' specified, falling back to '" + FALLBACK_CIV + "'"); civ = FALLBACK_CIV; } return g_CivData[civ].StartEntities; } function getHeight(x, z) { return g_Map.getHeight(x, z); } function setHeight(x, z, height) { g_Map.setHeight(x, z, height); } /** * Utility functions for classes */ /** * Add point to given class by id */ function addToClass(x, z, id) { let tileClass = getTileClass(id); if (tileClass !== null) tileClass.add(x, z); } /** * Remove point from the given class by id */ function removeFromClass(x, z, id) { let tileClass = getTileClass(id); if (tileClass !== null) tileClass.remove(x, z); } /** * Create a painter for the given class */ function paintClass(id) { return new TileClassPainter(getTileClass(id)); } /** * Create a painter for the given class */ function unPaintClass(id) { return new TileClassUnPainter(getTileClass(id)); } /** * 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); } /** * Checks if the given tile is in class "id" */ function checkIfInClass(x, z, id) { let tileClass = getTileClass(id); if (tileClass === null) return 0; let members = tileClass.countMembersInRadius(x, z, 1); if (members === null) return 0; return members; } /** * Returns the distance between 2 points */ function getDistance(x1, z1, x2, z2) { return Math.pow(Math.pow(x1 - x2, 2) + Math.pow(z1 - z2, 2), 1/2); } /** * Returns the angle of the vector between point 1 and point 2. * The angle is counterclockwise from the positive x axis. */ function getAngle(x1, z1, x2, z2) { return Math.atan2(z2 - z1, x2 - x1); } /** * Returns the gradient of the line between point 1 and 2 in the form dz/dx */ function getGradient(x1, z1, x2, z2) { if (x1 == x2 && z1 == z2) return 0; return (z1-z2)/(x1-x2); } function getTerrainTexture(x, y) { return g_Map.getTexture(x, y); } Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/placer.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/placer.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/placer.js (revision 19443) @@ -1,582 +1,576 @@ ///////////////////////////////////////////////////////////////////////////////////////// // ClumpPlacer // // Class for generating a roughly circular clump of points // // size: The average number of points in the clump // coherence: How much the radius of the clump varies (1.0 = circle, 0.0 = very random) // smoothness: How smooth the border of the clump is (1.0 = few "peaks", 0.0 = very jagged) // failfraction: Percentage of place attempts allowed to fail (optional) // x, z: Tile coordinates of placer center (optional) // ///////////////////////////////////////////////////////////////////////////////////////// function ClumpPlacer(size, coherence, smoothness, failFraction, x, z) { this.size = size; this.coherence = coherence; this.smoothness = smoothness; this.failFraction = failFraction !== undefined ? failFraction : 0; this.x = x !== undefined ? x : -1; this.z = z !== undefined ? z : -1; } ClumpPlacer.prototype.place = function(constraint) { // Preliminary bounds check if (!g_Map.inMapBounds(this.x, this.z) || !constraint.allows(this.x, this.z)) return undefined; var retVec = []; var size = getMapSize(); var gotRet = new Array(size).fill(0).map(p => new Uint8Array(size)); // booleans var radius = sqrt(this.size / PI); var perim = 4 * radius * 2 * PI; var intPerim = ceil(perim); var ctrlPts = 1 + Math.floor(1.0/Math.max(this.smoothness,1.0/intPerim)); if (ctrlPts > radius * 2 * PI) ctrlPts = Math.floor(radius * 2 * PI) + 1; var noise = new Float32Array(intPerim); //float32 var ctrlCoords = new Float32Array(ctrlPts+1); //float32 var ctrlVals = new Float32Array(ctrlPts+1); //float32 // Generate some interpolated noise for (var i=0; i < ctrlPts; i++) { ctrlCoords[i] = i * perim / ctrlPts; ctrlVals[i] = 2.0*randFloat(); } var c = 0; var looped = 0; for (var i=0; i < intPerim; i++) { if (ctrlCoords[(c+1) % ctrlPts] < i && !looped) { c = (c+1) % ctrlPts; if (c == ctrlPts-1) looped = 1; } // Cubic interpolation of ctrlVals var t = (i - ctrlCoords[c]) / ((looped ? perim : ctrlCoords[(c+1)%ctrlPts]) - ctrlCoords[c]); var v0 = ctrlVals[(c+ctrlPts-1)%ctrlPts]; var v1 = ctrlVals[c]; var v2 = ctrlVals[(c+1)%ctrlPts]; var v3 = ctrlVals[(c+2)%ctrlPts]; var P = (v3 - v2) - (v0 - v1); var Q = v0 - v1 - P; var R = v2 - v0; var S = v1; noise[i] = P*t*t*t + Q*t*t + R*t + S; } var failed = 0; for (var p=0; p < intPerim; p++) { var th = 2 * PI * p / perim; var r = radius * (1 + (1-this.coherence)*noise[p]); var s = sin(th); var c = cos(th); var xx = this.x; var yy = this.z; for (var k=0; k < ceil(r); k++) { var i = Math.floor(xx); var j = Math.floor(yy); if (g_Map.inMapBounds(i, j) && constraint.allows(i, j)) { if (!gotRet[i][j]) { // Only include each point once gotRet[i][j] = 1; retVec.push(new PointXZ(i, j)); } } else failed++; xx += s; yy += c; } } return failed > this.size * this.failFraction ? undefined : retVec; }; ///////////////////////////////////////////////////////////////////////////////////////// // Chain Placer // // Class for generating a more random clump of points it randomly creates circles around the edges of the current clump // // minRadius: minimum radius of the circles // maxRadius: maximum radius of the circles // numCircles: the number of the circles // failfraction: Percentage of place attempts allowed to fail (optional) // x, z: Tile coordinates of placer center (optional) // fcc: Farthest circle center (optional) // q: a list containing numbers. each time if the list still contains values, pops one from the end and uses it as the radius (optional) // ///////////////////////////////////////////////////////////////////////////////////////// function ChainPlacer(minRadius, maxRadius, numCircles, failFraction, x, z, fcc, q) { this.minRadius = minRadius; this.maxRadius = maxRadius; this.numCircles = numCircles; this.failFraction = failFraction !== undefined ? failFraction : 0; this.x = x !== undefined ? x : -1; this.z = z !== undefined ? z : -1; this.fcc = fcc !== undefined ? fcc : 0; this.q = q !== undefined ? q : []; } ChainPlacer.prototype.place = function(constraint) { // Preliminary bounds check if (!g_Map.inMapBounds(this.x, this.z) || !constraint.allows(this.x, this.z)) return undefined; var retVec = []; var size = getMapSize(); var failed = 0, count = 0; var queueEmpty = !this.q.length; var gotRet = new Array(size).fill(0).map(p => new Array(size).fill(-1)); --size; this.minRadius = Math.min(this.maxRadius, Math.max(this.minRadius, 1)); var edges = [[this.x, this.z]]; for (var i = 0; i < this.numCircles; ++i) { var [cx, cz] = pickRandom(edges); if (queueEmpty) - var radius = randInt(this.minRadius, this.maxRadius); + var radius = randIntInclusive(this.minRadius, this.maxRadius); else { var radius = this.q.pop(); queueEmpty = !this.q.length; } var sx = cx - radius, lx = cx + radius; var sz = cz - radius, lz = cz + radius; sx = Math.max(0, sx); sz = Math.max(0, sz); lx = Math.min(lx, size); lz = Math.min(lz, size); var radius2 = radius * radius; var dx, dz; for (var ix = sx; ix <= lx; ++ix) for (var iz = sz; iz <= lz; ++ iz) { dx = ix - cx; dz = iz - cz; if (dx * dx + dz * dz <= radius2) { if (g_Map.inMapBounds(ix, iz) && constraint.allows(ix, iz)) { var state = gotRet[ix][iz]; if (state == -1) { retVec.push(new PointXZ(ix, iz)); gotRet[ix][iz] = -2; } else if (state >= 0) { var s = edges.splice(state, 1); gotRet[ix][iz] = -2; var edgesLength = edges.length; for (var k = state; k < edges.length; ++k) --gotRet[edges[k][0]][edges[k][1]]; } } else ++failed; ++count; } } for (var ix = sx; ix <= lx; ++ix) for (var iz = sz; iz <= lz; ++ iz) { if (this.fcc) if ((this.x - ix) > this.fcc || (ix - this.x) > this.fcc || (this.z - iz) > this.fcc || (iz - this.z) > this.fcc) continue; if (gotRet[ix][iz] == -2) { if (ix > 0) { if (gotRet[ix-1][iz] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } if (iz > 0) { if (gotRet[ix][iz-1] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } if (ix < size) { if (gotRet[ix+1][iz] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } if (iz < size) { if (gotRet[ix][iz+1] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } } } } return failed > count * this.failFraction ? undefined : retVec; }; ///////////////////////////////////////////////////////////////////////////////////////// // RectPlacer // // Class for generating a rectangular block of points // // x1,z1: Top left corner of block // x2,z2: Bottom right corner of block // ///////////////////////////////////////////////////////////////////////////////////////// function RectPlacer(x1, z1, x2, z2) { this.x1 = x1; this.z1 = z1; this.x2 = x2; this.z2 = z2; if (x1 > x2 || z1 > z2) throw("RectPlacer: incorrect bounds on rect"); } RectPlacer.prototype.place = function(constraint) { // Preliminary bounds check if (!g_Map.inMapBounds(this.x1, this.z1) || !constraint.allows(this.x1, this.z1) || !g_Map.inMapBounds(this.x2, this.z2) || !constraint.allows(this.x2, this.z2)) return undefined; var ret = []; var x2 = this.x2; var z2 = this.z2; for (var x=this.x1; x < x2; x++) for (var z=this.z1; z < z2; z++) if (g_Map.inMapBounds(x, z) && constraint.allows(x, z)) ret.push(new PointXZ(x, z)); else return undefined; return ret; }; ///////////////////////////////////////////////////////////////////////////////////////// // ObjectGroupPlacer ///////////////////////////////////////////////////////////////////////////////////////// function ObjectGroupPlacer() {} ///////////////////////////////////////////////////////////////////////////////////////// // SimpleObject // // Class specifying a type of entity that can be placed on the map // // type: The entity's template name // minCount,maxCount: The number of objects to place // minDistance,maxDistance: The distance between placed objects // minAngle,maxAngle: The variation in angle of placed objects (optional) // ///////////////////////////////////////////////////////////////////////////////////////// function SimpleObject(type, minCount, maxCount, minDistance, maxDistance, minAngle, maxAngle) { this.type = type; this.minCount = minCount; this.maxCount = maxCount; this.minDistance = minDistance; this.maxDistance = maxDistance; this.minAngle = minAngle !== undefined ? minAngle : 0; this.maxAngle = maxAngle !== undefined ? maxAngle : 2*PI; if (minCount > maxCount) warn("SimpleObject: minCount should be less than or equal to maxCount"); if (minDistance > maxDistance) warn("SimpleObject: minDistance should be less than or equal to maxDistance"); if (minAngle > maxAngle) warn("SimpleObject: minAngle should be less than or equal to maxAngle"); } SimpleObject.prototype.place = function(cx, cz, player, avoidSelf, constraint, maxFailCount = 20) { var failCount = 0; - var count = randInt(this.minCount, this.maxCount); var resultObjs = []; - for (var i=0; i < count; i++) - { + for (var i = 0; i < randIntInclusive(this.minCount, this.maxCount); ++i) while(true) { var distance = randFloat(this.minDistance, this.maxDistance); var direction = randFloat(0, 2*PI); var x = cx + 0.5 + distance*cos(direction); var z = cz + 0.5 + distance*sin(direction); var fail = false; // reset place failure flag if (!g_Map.validT(x, z)) fail = true; else { if (avoidSelf) { var length = resultObjs.length; for (var i = 0; (i < length) && !fail; i++) { var dx = x - resultObjs[i].position.x; var dy = z - resultObjs[i].position.z; if (dx*dx + dy*dy < 1) fail = true; } } if (!fail) { if (!constraint.allows(Math.floor(x), Math.floor(z))) fail = true; else { var angle = randFloat(this.minAngle, this.maxAngle); resultObjs.push(new Entity(this.type, player, x, z, angle)); break; } } } if (fail) { failCount++; if (failCount > maxFailCount) return undefined; } } - } return resultObjs; }; ///////////////////////////////////////////////////////////////////////////////////////// // RandomObject // // Class specifying entities that can be placed on the map, selected randomly // // types: Array of entity template names // minCount,maxCount: The number of objects to place // minDistance,maxDistance: The distance between placed objects // minAngle,maxAngle: The variation in angle of placed objects (optional) // ///////////////////////////////////////////////////////////////////////////////////////// function RandomObject(types, minCount, maxCount, minDistance, maxDistance, minAngle, maxAngle) { this.types = types; this.minCount = minCount; this.maxCount = maxCount; this.minDistance = minDistance; this.maxDistance = maxDistance; this.minAngle = minAngle !== undefined ? minAngle : 0; this.maxAngle = maxAngle !== undefined ? maxAngle : 2*PI; if (minCount > maxCount) warn("RandomObject: minCount should be less than or equal to maxCount"); if (minDistance > maxDistance) warn("RandomObject: minDistance should be less than or equal to maxDistance"); if (minAngle > maxAngle) warn("RandomObject: minAngle should be less than or equal to maxAngle"); } RandomObject.prototype.place = function(cx, cz, player, avoidSelf, constraint, maxFailCount = 20) { var failCount = 0; - var count = randInt(this.minCount, this.maxCount); var resultObjs = []; - for (var i=0; i < count; i++) - { + for (var i = 0; i < randIntInclusive(this.minCount, this.maxCount); ++i) while(true) { var distance = randFloat(this.minDistance, this.maxDistance); var direction = randFloat(0, 2*PI); var x = cx + 0.5 + distance*cos(direction); var z = cz + 0.5 + distance*sin(direction); var fail = false; // reset place failure flag if (!g_Map.validT(x, z)) fail = true; else { if (avoidSelf) { var length = resultObjs.length; for (var i = 0; (i < length) && !fail; i++) { var dx = x - resultObjs[i].position.x; var dy = z - resultObjs[i].position.z; if (dx*dx + dy*dy < 1) fail = true; } } if (!fail) { if (!constraint.allows(Math.floor(x), Math.floor(z))) fail = true; else { var angle = randFloat(this.minAngle, this.maxAngle); resultObjs.push(new Entity(pickRandom(this.types), player, x, z, angle)); break; } } } if (fail) { failCount++; if (failCount > maxFailCount) return undefined; } } - } return resultObjs; }; ///////////////////////////////////////////////////////////////////////////////////////// // SimpleGroup // // Class for placing groups of different objects // // elements: Array of SimpleObjects // avoidSelf: Objects will not overlap // tileClass: Optional tile class to add with these objects // x,z: Tile coordinates of center of placer // ///////////////////////////////////////////////////////////////////////////////////////// function SimpleGroup(elements, avoidSelf, tileClass, x, z) { this.elements = elements; this.tileClass = tileClass !== undefined ? getTileClass(tileClass) : undefined; this.avoidSelf = avoidSelf !== undefined ? avoidSelf : false; this.x = x !== undefined ? x : -1; this.z = z !== undefined ? z : -1; } SimpleGroup.prototype.place = function(player, constraint) { var resultObjs = []; // Try placement of objects for (let element of this.elements) { var objs = element.place(this.x, this.z, player, this.avoidSelf, constraint); if (objs === undefined) return false; resultObjs = resultObjs.concat(objs); } // Add placed objects to map for (let obj of resultObjs) { if (g_Map.validT(obj.position.x / CELL_SIZE, obj.position.z / CELL_SIZE, MAP_BORDER_WIDTH)) g_Map.addObject(obj); // Convert position to integer number of tiles if (this.tileClass !== undefined) this.tileClass.add(Math.floor(obj.position.x/CELL_SIZE), Math.floor(obj.position.z/CELL_SIZE)); } return true; }; ///////////////////////////////////////////////////////////////////////////////////////// // RandomGroup // // Class for placing group of a random simple object // // elements: Array of SimpleObjects // avoidSelf: Objects will not overlap // tileClass: Optional tile class to add with these objects // x,z: Tile coordinates of center of placer // ///////////////////////////////////////////////////////////////////////////////////////// function RandomGroup(elements, avoidSelf, tileClass, x, z) { this.elements = elements; this.tileClass = tileClass !== undefined ? getTileClass(tileClass) : undefined; this.avoidSelf = avoidSelf !== undefined ? avoidSelf : false; this.x = x !== undefined ? x : -1; this.z = z !== undefined ? z : -1; } RandomGroup.prototype.place = function(player, constraint) { var resultObjs = pickRandom(this.elements).place(this.x, this.z, player, this.avoidSelf, constraint); if (resultObjs === undefined) return false; // Add placed objects to map for (let obj of resultObjs) { g_Map.addObject(obj); // Convert position to integer number of tiles if (this.tileClass !== undefined) this.tileClass.add(Math.floor(obj.position.x/CELL_SIZE), Math.floor(obj.position.z/CELL_SIZE)); } return true; }; Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/wall_builder.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/wall_builder.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/wall_builder.js (revision 19443) @@ -1,1032 +1,1032 @@ //////////////////////////////////////////////////////////////////// // This file contains functionality to place walls on random maps // //////////////////////////////////////////////////////////////////// // To do: // Check if all wall placement methods work with wall elements with entity === undefined (some still might raise errors in that case) // Rename wall elements to fit the entity names so that entity = "structures/" + "civ + "_" + wallElement.type in the common case (as far as possible) // Perhaps add Roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength // Perhaps add further wall elements cornerInHalf, cornerOutHalf (banding PI/4) and adjust default fortress types to better fit in the octagonal territory of a civil center // Perhaps swap angle and width in WallElement class(?) definition // Adjust argument order to be always the same: // Coordinates (center/start/target) // Wall element arguments (wall/wallPart/fortressType/cornerElement) // playerId (optional, default is 0/gaia) // wallStyle (optional, default is the players civ/"palisades for gaia") // angle/orientation (optional, default is 0) // other (all optional) arguments especially those hard to define (wallPartsAssortment, maybe make an own function for it) // Some arguments don't clearly match to this concept: // endWithFirst (wall or other) // skipFirstWall (wall or other) // gateOccurence (wall or other) // numCorners (wall or other) // skipFirstWall (wall or other) // maxAngle (angle or other) // maxBendOff (angle or other, unused ATM!!!) // irregularity // maxTrys // Add treasures to wall style "others" // Adjust documentation // Perhaps rename "endLeft" to "start" and "endRight" to "end" // ?Use available civ-type wall elements rather than palisades: Remove "endLeft" and "endRight" as default wall elements and adjust default palisade fortress types? // ?Remove "endRight", "endLeft" and adjust generic fortress types palisades? // ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads? // ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending? ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // WallElement class definition // // Concept: If placed unrotated the wall's course is towards positive Y (top) with "outside" right (+X) and "inside" left (-X) like unrotated entities has their drop-points right (in rmgen) // The course of the wall will be changed by corners (bending != 0) and so the "inside"/"outside" direction // // type Descriptive string, example: "wallLong". NOTE: Not really needed. Mainly for custom wall elements and to get the wall element type in code // entity Optional. Template name string of the entity to be placed, example: "structures/cart_wall_long". Default is undefined (No entity placed) // angle Optional. The angle (float) added to place the entity so "outside" is right when the wall element is placed unrotated. Default is 0 // width Optional. How far this wall element lengthens the wall (float), if unrotated the Y space needed. Default is 0 // indent Optional. The lateral indentation of the entity, drawn "inside" (positive values) or pushed "outside" (negative values). Default is 0 // bending Optional. How the course of the wall is changed after this element, positive is bending "in"/left/counter clockwise (like entity placement) // NOTE: Bending is not supported by all placement functions (see there) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function WallElement(type, entity, angle, width, indent, bending) { this.type = type; // Default wall element type documentation: // Lengthening straight blocking (mainly left/right symmetric) wall elements (Walls and wall fortifications) // "wall" A blocking straight wall element that mainly lengthens the wall, self-explanatory // "wallShort" self-explanatory // "wallLong" self-explanatory // "tower" A blocking straight wall element with damage potential (but for palisades) that slightly lengthens the wall, example: wall tower, palisade tower(No attack) // "wallFort" A blocking straight wall element with massive damage potential that lengthens the wall, example: fortress, palisade fort // Lengthening straight non/custom blocking (mainly left/right symmetric) wall elements (Gates and entries) // "gate" A blocking straight wall element with passability determined by owner, example: gate (Functionality not yet implemented) // "entry" A non-blocking straight wall element (same width as gate) but without an actual template or just a flag/column/obelisk // "entryTower" A non-blocking straight wall element (same width as gate) represented by a single (maybe indented) template, example: defence tower, wall tower, outpost, watchtower // "entryFort" A non-blocking straight wall element represented by a single (maybe indented) template, example: fortress, palisade fort // Bending wall elements (Wall corners) // "cornerIn" A wall element bending the wall by PI/2 "inside" (left, +, see above), example: wall tower, palisade curve // "cornerOut" A wall element bending the wall by PI/2 "outside" (right, -, see above), example: wall tower, palisade curve // "cornerHalfIn" A wall element bending the wall by PI/4 "inside" (left, +, see above), example: wall tower, palisade curve. NOTE: Not yet implemented // "cornerHalfOut" A wall element bending the wall by PI/4 "outside" (right, -, see above), example: wall tower, palisade curve. NOTE: Not yet implemented // Zero length straight indented (mainly left/right symmetric) wall elements (Outposts/watchtowers and non-defensive base structures) // "outpost" A zero-length wall element without bending far indented so it stands outside the wall, example: outpost, defence tower, watchtower // "house" A zero-length wall element without bending far indented so it stands inside the wall that grants population bonus, example: house, hut, longhouse // "barracks" A zero-length wall element without bending far indented so it stands inside the wall that grants unit production, example: barracks, tavern, ... this.entity = entity; this.angle = angle !== undefined ? angle : 0; this.width = width !== undefined ? width : 0; this.indent = indent !== undefined ? indent : 0; this.bending = bending !== undefined ? bending : 0; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Fortress class definition // // A "fortress" here is a closed wall build of multiple wall elements attached together defined in Fortress.wall // It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles) // // type Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements // wall Optional. Array of wall element strings. Can be set afterwards. Default is an epty array. // Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"] // centerToFirstElement Optional. Object with properties "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function Fortress(type, wall, centerToFirstElement) { this.type = type; // Only usefull to get the type of the actual fortress this.wall = wall !== undefined ? wall : []; this.centerToFirstElement = undefined; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // wallStyles data structure for default wall styles // // A wall style is an associative array with all wall elements of that style in it associated with the wall element type string // wallStyles holds all the wall styles within an associative array with the civ string or another descriptive strings as key // Examples: "athen", "rome_siege", "palisades", "fence", "road" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// var wallStyles = {}; // Generic civ dependent wall style definition. "rome_siege" needs some tweek... var wallScaleByType = { "athen": 1.5, "brit": 1.5, "cart": 1.8, "gaul": 1.5, "iber": 1.5, "mace": 1.5, "maur": 1.5, "pers": 1.5, "ptol": 1.5, "rome": 1.5, "sele": 1.5, "spart": 1.5, "rome_siege": 1.5 }; for (var style in wallScaleByType) { var civ = style; if (style == "rome_siege") civ = "rome"; wallStyles[style] = { // Default wall elements "tower": new WallElement("tower", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]), "endLeft": new WallElement("endLeft", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]), // Same as tower. To be compatible with palisades... "endRight": new WallElement("endRight", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]), // Same as tower. To be compatible with palisades... "cornerIn": new WallElement("cornerIn", "structures/" + style + "_wall_tower", 5/4*PI, 0, 0.35 * wallScaleByType[style], PI/2), // 2^0.5 / 4 ~= 0.35 ~= 1/3 "cornerOut": new WallElement("cornerOut", "structures/" + style + "_wall_tower", 3/4*PI, 0.71 * wallScaleByType[style], 0, -PI/2), // 2^0.5 / 2 ~= 0.71 ~= 2/3 "wallShort": new WallElement("wallShort", "structures/" + style + "_wall_short", 0, 2*wallScaleByType[style]), "wall": new WallElement("wall", "structures/" + style + "_wall_medium", 0, 4*wallScaleByType[style]), "wallMedium": new WallElement("wall", "structures/" + style + "_wall_medium", 0, 4*wallScaleByType[style]), "wallLong": new WallElement("wallLong", "structures/" + style + "_wall_long", 0, 6*wallScaleByType[style]), // Gate and entrance wall elements "gate": new WallElement("gate", "structures/" + style + "_wall_gate", PI, 6*wallScaleByType[style]), "entry": new WallElement("entry", undefined, 0, 6*wallScaleByType[style]), "entryTower": new WallElement("entryTower", "structures/" + civ + "_defense_tower", PI, 6*wallScaleByType[style], -4*wallScaleByType[style]), "entryFort": new WallElement("entryFort", "structures/" + civ + "_fortress", 0, 8*wallScaleByType[style], 6*wallScaleByType[style]), // Defensive wall elements with 0 width outside the wall "outpost": new WallElement("outpost", "structures/" + civ + "_outpost", PI, 0, -4*wallScaleByType[style]), "defenseTower": new WallElement("defenseTower", "structures/" + civ + "_defense_tower", PI, 0, -4*wallScaleByType[style]), // Base buildings wall elements with 0 width inside the wall "barracks": new WallElement("barracks", "structures/" + civ + "_barracks", PI, 0, 4.5*wallScaleByType[style]), "civilCentre": new WallElement("civilCentre", "structures/" + civ + "_civil_centre", PI, 0, 4.5*wallScaleByType[style]), "farmstead": new WallElement("farmstead", "structures/" + civ + "_farmstead", PI, 0, 4.5*wallScaleByType[style]), "field": new WallElement("field", "structures/" + civ + "_field", PI, 0, 4.5*wallScaleByType[style]), "fortress": new WallElement("fortress", "structures/" + civ + "_fortress", PI, 0, 4.5*wallScaleByType[style]), "house": new WallElement("house", "structures/" + civ + "_house", PI, 0, 4.5*wallScaleByType[style]), "market": new WallElement("market", "structures/" + civ + "_market", PI, 0, 4.5*wallScaleByType[style]), "storehouse": new WallElement("storehouse", "structures/" + civ + "_storehouse", PI, 0, 4.5*wallScaleByType[style]), "temple": new WallElement("temple", "structures/" + civ + "_temple", PI, 0, 4.5*wallScaleByType[style]), // Generic space/gap wall elements "space1": new WallElement("space1", undefined, 0, 1*wallScaleByType[style]), "space2": new WallElement("space2", undefined, 0, 2*wallScaleByType[style]), "space3": new WallElement("space3", undefined, 0, 3*wallScaleByType[style]), "space4": new WallElement("space4", undefined, 0, 4*wallScaleByType[style]) }; } // Add wall fortresses for all generic styles wallStyles.athen.wallFort = new WallElement("wallFort", "structures/athen_fortress", 2*PI/2, 5.1, 1.9); wallStyles.brit.wallFort = new WallElement("wallFort", "structures/brit_fortress", PI, 2.8); wallStyles.cart.wallFort = new WallElement("wallFort", "structures/cart_fortress", PI, 5.1, 1.6); wallStyles.gaul.wallFort = new WallElement("wallFort", "structures/gaul_fortress", PI, 4.2, 1.5); wallStyles.iber.wallFort = new WallElement("wallFort", "structures/iber_fortress", PI, 5, 0.2); wallStyles.mace.wallFort = new WallElement("wallFort", "structures/mace_fortress", 2*PI/2, 5.1, 1.9); wallStyles.maur.wallFort = new WallElement("wallFort", "structures/maur_fortress", PI, 5.5); wallStyles.pers.wallFort = new WallElement("wallFort", "structures/pers_fortress", PI, 5.6, 1.9); wallStyles.ptol.wallFort = new WallElement("wallFort", "structures/ptol_fortress", 2*PI/2, 5.1, 1.9); wallStyles.rome.wallFort = new WallElement("wallFort", "structures/rome_fortress", PI, 6.3, 2.1); wallStyles.sele.wallFort = new WallElement("wallFort", "structures/sele_fortress", 2*PI/2, 5.1, 1.9); wallStyles.spart.wallFort = new WallElement("wallFort", "structures/spart_fortress", 2*PI/2, 5.1, 1.9); // Adjust "rome_siege" style wallStyles.rome_siege.wallFort = new WallElement("wallFort", "structures/rome_army_camp", PI, 7.2, 2); wallStyles.rome_siege.entryFort = new WallElement("entryFort", "structures/rome_army_camp", PI, 12, 7); wallStyles.rome_siege.house = new WallElement("house", "structures/rome_tent", PI, 0, 4); // Add special wall styles not well to implement generic (and to show how custom styles can be added) wallScaleByType.palisades = 0.55; let gate = new WallElement("gate", "other/palisades_rocks_gate", PI, 3.6); wallStyles.palisades = { "wall": new WallElement("wall", "other/palisades_rocks_medium", 0, 2.3), "wallMedium": new WallElement("wall", "other/palisades_rocks_medium", 0, 2.3), "wallLong": new WallElement("wall", "other/palisades_rocks_long", 0, 3.5), "wallShort": new WallElement("wall", "other/palisades_rocks_short", 0, 1.2), "tower": new WallElement("tower", "other/palisades_rocks_tower", -PI/2, 0.7), "wallFort": new WallElement("wallFort", "other/palisades_rocks_fort", PI, 1.7), "gate": gate, "entry": new WallElement("entry", undefined, gate.angle, gate.width), "entryTower": new WallElement("entryTower", "other/palisades_rocks_watchtower", 0, gate.width, -3), "entryFort": new WallElement("entryFort", "other/palisades_rocks_fort", PI, 6, 3), "cornerIn": new WallElement("cornerIn", "other/palisades_rocks_curve", 3*PI/4, 2.1, 0.7, PI/2), "cornerOut": new WallElement("cornerOut", "other/palisades_rocks_curve", 5*PI/4, 2.1, -0.7, -PI/2), "outpost": new WallElement("outpost", "other/palisades_rocks_outpost", PI, 0, -2), "house": new WallElement("house", "other/celt_hut", PI, 0, 5), "barracks": new WallElement("barracks", "structures/gaul_tavern", PI, 0, 5), "endRight": new WallElement("endRight", "other/palisades_rocks_end", -PI/2, 0.2), "endLeft": new WallElement("endLeft", "other/palisades_rocks_end", PI/2, 0.2) }; // NOTE: This is not a wall style in the common sense. Use with care! wallStyles.road = { "short": new WallElement("road", "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5), "long": new WallElement("road", "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5), // Correct width by -2*indent to fit xStraicht/corner "cornerLeft": new WallElement("road", "actor|props/special/eyecandy/road_temperate_corner.xml", -PI/2, 4.5-2*1.25, 1.25, PI/2), "cornerRight": new WallElement("road", "actor|props/special/eyecandy/road_temperate_corner.xml", 0, 4.5-2*1.25, -1.25, -PI/2), "curveLeft": new WallElement("road", "actor|props/special/eyecandy/road_temperate_curve_small.xml", -PI/2, 4.5+2*0.2, -0.2, PI/2), "curveRight": new WallElement("road", "actor|props/special/eyecandy/road_temperate_curve_small.xml", 0, 4.5+2*0.2, 0.2, -PI/2), "start": new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2), "end": new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2), "xStraight": new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0, 4.5), "xLeft": new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0, 4.5, 0, PI/2), "xRight": new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0, 4.5, 0, -PI/2), "tLeft": new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25), "tRight": new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0, 4.5, -1.25), }; // NOTE: This is not a wall style in the common sense. Use with care! wallStyles.other = { "fence": new WallElement("fence", "other/fence_long", -PI/2, 3.1), "fence_medium": new WallElement("fence", "other/fence_long", -PI/2, 3.1), "fence_short": new WallElement("fence_short", "other/fence_short", -PI/2, 1.5), "fence_stone": new WallElement("fence_stone", "other/fence_stone", -PI/2, 2.5), "palisade": new WallElement("palisade", "other/palisades_rocks_short", 0, 1.2), "column": new WallElement("column", "other/column_doric", 0, 1), "obelisk": new WallElement("obelisk", "other/obelisk", 0, 2), "spike": new WallElement("spike", "other/palisades_angle_spike", -PI/2, 1), "bench": new WallElement("bench", "other/bench", PI/2, 1.5), "benchForTable": new WallElement("benchForTable", "other/bench", 0, 0.5), "table": new WallElement("table", "other/table_rectangle", 0, 1), "table_square": new WallElement("table_square", "other/table_square", PI/2, 1), "flag": new WallElement("flag", "special/rallypoint", PI, 1), "standing_stone": new WallElement("standing_stone", "gaia/special_ruins_standing_stone", PI, 1), "settlement": new WallElement("settlement", "gaia/special_settlement", PI, 6), "gap": new WallElement("gap", undefined, 0, 2), "gapSmall": new WallElement("gapSmall", undefined, 0, 1), "gapLarge": new WallElement("gapLarge", undefined, 0, 4), "cornerIn": new WallElement("cornerIn", undefined, 0, 0, 0, PI/2), "cornerOut": new WallElement("cornerOut", undefined, 0, 0, 0, -PI/2) }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // fortressTypes data structure for some default fortress types // // A fortress type is just an instance of the Fortress class with actually something in it // fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size) // Examples: "tiny", "veryLarge" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// var fortressTypes = {}; { let wallParts = { "tiny": ["gate", "tower", "wallShort", "cornerIn", "wallShort", "tower"], "small": ["gate", "tower", "wall", "cornerIn", "wall", "tower"], "medium": ["gate", "tower", "wallLong", "cornerIn", "wallLong", "tower"], "normal": ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wall", "cornerIn", "wall", "tower"], "large": ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"], "veryLarge": ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wall", "cornerIn", "wall", "tower"], "giant": ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"] }; for (let type in wallParts) { fortressTypes[type] = new Fortress(type); let wp = wallParts[type]; fortressTypes[type].wall = wp.concat(wp, wp, wp); } } // Setup some better looking semi default fortresses for "palisades" style for (let type in fortressTypes) { var newKey = type + "Palisades"; var oldWall = fortressTypes[type].wall; fortressTypes[newKey] = new Fortress(newKey); var fillTowersBetween = ["wallShort", "wall", "wallLong", "endLeft", "endRight", "cornerIn", "cornerOut"]; for (var j = 0; j < oldWall.length; j++) { fortressTypes[newKey].wall.push(oldWall[j]); // Only works if the first element is not in fillTowersBetween (e.g. entry or gate like it should be) if (j+1 < oldWall.length) if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means "exists" here fortressTypes[newKey].wall.push("tower"); } } // Setup some balanced (to civ type fortresses) semi default fortresses for "palisades" style // TODO // Add some "fortress types" for roads (will only work with style "road") { // ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"]; let roadTypes = { "road01": ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"], "road02": ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"], "road03": ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"], "road04": ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short", "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"], "road05": ["start", "tLeft", "short", "xRight", "curveLeft", "xRight", "tRight", "cornerLeft", "tRight", "curveLeft", "short", "tRight", "cornerLeft", "xRight", "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"], }; for (let type in roadTypes) fortressTypes[type] = new Fortress(type, roadTypes[type]); } /////////////////////////////// // Define some helper functions /////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // getWallAlignment // // Returns a list of objects containing all information to place all the wall elements entities with placeObject (but the player ID) // Placing the first wall element at startX/startY placed with an angle given by orientation // An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function getWallAlignment(startX, startY, wall, style, orientation) { // Graciously handle arguments if (wall === undefined) wall = []; if (!wallStyles.hasOwnProperty(style)) { warn("Function getWallAlignment: Unknown style: " + style + ' (falling back to "athen")'); style = "athen"; } orientation = orientation || 0; var alignment = []; var wallX = startX; var wallY = startY; for (var i = 0; i < wall.length; i++) { var element = wallStyles[style][wall[i]]; if (element === undefined && i == 0) warn("No valid wall element: " + wall[i]); // Indentation var placeX = wallX - element.indent * cos(orientation); var placeY = wallY - element.indent * sin(orientation); // Add wall elements entity placement arguments to the alignment alignment.push({ "x": placeX, "y": placeY, "entity": element.entity, "angle": orientation + element.angle }); // Preset vars for the next wall element if (i+1 < wall.length) { orientation += element.bending; var nextElement = wallStyles[style][wall[i+1]]; if (nextElement === undefined) warn("No valid wall element: " + wall[i+1]); var distance = (element.width + nextElement.width)/2; // Corrections for elements with indent AND bending var indent = element.indent; var bending = element.bending; if (bending !== 0 && indent !== 0) { // Indent correction to adjust distance distance += indent*sin(bending); // Indent correction to normalize indentation wallX += indent * cos(orientation); wallY += indent * sin(orientation); } // Set the next coordinates of the next element in the wall without indentation adjustment wallX -= distance * sin(orientation); wallY += distance * cos(orientation); } } return alignment; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // getCenterToFirstElement // // Center calculation works like getting the center of mass assuming all wall elements have the same "weight" // // It returns the vector from the center to the first wall element // Used to get centerToFirstElement of fortresses by default ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function getCenterToFirstElement(alignment) { var centerToFirstElement = {"x": 0, "y": 0}; for (var i = 0; i < alignment.length; i++) { centerToFirstElement.x -= alignment[i].x/alignment.length; centerToFirstElement.y -= alignment[i].y/alignment.length; } return centerToFirstElement; } ////////////////////////////////////////////////////////////////// // getWallLength // // NOTE: Does not support bending wall elements like corners! // e.g. used by placeIrregularPolygonalWall ////////////////////////////////////////////////////////////////// function getWallLength(wall, style) { // Graciously handle arguments if (wall === undefined) wall = []; if (!wallStyles.hasOwnProperty(style)) { warn("Function getWallLength: Unknown style: " + style + ' (falling back to "athen")'); style = "athen"; } var length = 0; for (var i = 0; i < wall.length; i++) length += wallStyles[style][wall[i]].width; return length; } ///////////////////////////////////////////// // Define the different wall placer functions ///////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeWall // // Places a wall with wall elements attached to another like determined by WallElement properties. // // startX, startY Where the first wall element should be placed // wall Array of wall element type strings. Example: ["endLeft", "wallLong", "tower", "wallLong", "endRight"] // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia // playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) // orientation Optional. Angle the first wall element is placed. Default is 0 // 0 means "outside" or "front" of the wall is right (positive X) like placeObject // It will then be build towards top/positive Y (if no bending wall elements like corners are used) // Raising orientation means the wall is rotated counter-clockwise like placeObject ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeWall(startX, startY, wall, style, playerId, orientation) { // Graciously handle arguments if (wall === undefined) wall = []; playerId = playerId || 0; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId-1); } orientation = orientation || 0; // Get wall alignment var AM = getWallAlignment(startX, startY, wall, style, orientation); // Place the wall for (var iWall = 0; iWall < wall.length; iWall++) { var entity = AM[iWall].entity; if (entity !== undefined) placeObject(AM[iWall].x, AM[iWall].y, entity, playerId, AM[iWall].angle); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeCustomFortress // // Place a fortress (mainly a closed wall build like placeWall) centered at centerX/centerY // The fortress wall should always start with the main entrance (like "entry" or "gate") to get the orientation right (like placeObject) // // fortress An instance of Fortress with a wall defined // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia // playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) // orientation Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is BUILDING_ORIENTATION ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeCustomFortress(centerX, centerY, fortress, style, playerId = 0, orientation = BUILDING_ORIENTATION) { // Graciously handle arguments fortress = fortress || fortressTypes.medium; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId-1); } // Calculate center if fortress.centerToFirstElement is undefined (default) var centerToFirstElement = fortress.centerToFirstElement; if (centerToFirstElement === undefined) centerToFirstElement = getCenterToFirstElement(getWallAlignment(0, 0, fortress.wall, style)); // Placing the fortress wall var startX = centerX + centerToFirstElement.x * cos(orientation) - centerToFirstElement.y * sin(orientation); var startY = centerY + centerToFirstElement.y * cos(orientation) + centerToFirstElement.x * sin(orientation); placeWall(startX, startY, fortress.wall, style, playerId, orientation); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeFortress // // Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeFortress(centerX, centerY, type, style, playerId, orientation) { // Graciously handle arguments type = type || "medium"; playerId = playerId || 0; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId-1); } orientation = orientation || 0; // Call placeCustomFortress with the given arguments placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeLinearWall // // Places a straight wall from a given coordinate to an other repeatedly using the wall parts. // // startX/startY Coordinate of the approximate beginning of the wall (Not the place of the first wall element) // targetX/targetY Coordinate of the approximate ending of the wall (Not the place of the last wall element) // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"] // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia // playerId Optional. Integer number of the player. Default is 0 (gaia) // endWithFirst Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true // // TODO: Maybe add angle offset for more generic looking? ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId, endWithFirst) { // Setup optional arguments to the default wallPart = wallPart || ["tower", "wallLong"]; playerId = playerId || 0; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId-1); } endWithFirst = typeof endWithFirst == "undefined" ? true : endWithFirst; // Check arguments for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) { var bending = wallStyles[style][wallPart[elementIndex]].bending; if (bending != 0) warn("Bending is not supported by placeLinearWall but a bending wall element is used: " + wallPart[elementIndex] + " -> wallStyles[style][wallPart[elementIndex]].entity"); } // Setup number of wall parts var totalLength = getDistance(startX, startY, targetX, targetY); var wallPartLength = 0; for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) wallPartLength += wallStyles[style][wallPart[elementIndex]].width; var numParts = 0; if (endWithFirst) numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength); else numParts = ceil(totalLength / wallPartLength); // Setup scale factor var scaleFactor = 1; if (endWithFirst) scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width); else scaleFactor = totalLength / (numParts * wallPartLength); // Setup angle var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed... var placeAngle = wallAngle - PI/2; // Place wall entities var x = startX; var y = startY; for (var partIndex = 0; partIndex < numParts; partIndex++) { for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) { var wallEle = wallStyles[style][wallPart[elementIndex]]; // Width correction x += scaleFactor * wallEle.width/2 * cos(wallAngle); y += scaleFactor * wallEle.width/2 * sin(wallAngle); // Indent correction var placeX = x - wallEle.indent * sin(wallAngle); var placeY = y + wallEle.indent * cos(wallAngle); // Placement var entity = wallEle.entity; if (entity !== undefined) placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle); x += scaleFactor * wallEle.width/2 * cos(wallAngle); y += scaleFactor * wallEle.width/2 * sin(wallAngle); } } if (endWithFirst) { var wallEle = wallStyles[style][wallPart[0]]; x += scaleFactor * wallEle.width/2 * cos(wallAngle); y += scaleFactor * wallEle.width/2 * sin(wallAngle); var entity = wallEle.entity; if (entity !== undefined) placeObject(x, y, entity, playerId, placeAngle + wallEle.angle); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeCircularWall // // Place a circular wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius // The wall can be opened forming more an arc than a circle if maxAngle < 2*PI // The orientation then determines where this open part faces (0 means right like unrotated building's drop-points) // // centerX/Y Coordinates of the circle's center // radius How wide the circle should be (approximate, especially if maxBendOff != 0) // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"] // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia // playerId Optional. Integer number of the player. Default is 0 (gaia) // orientation Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0 // maxAngle Optional. How far the wall should circumvent the center. Default is 2*PI (full circle) // endWithFirst Optional. Boolean. If true the 1st wall element in the wallPart array will finalize the wall. Default is false for full circles, else true // maxBendOff Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle) // // NOTE: Don't use wall elements with bending like corners! // TODO: Perhaps add eccentricity and maxBendOff functionality (untill now an unused argument) // TODO: Perhaps add functionality for spirals ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff) { // Setup optional arguments to the default wallPart = wallPart || ["tower", "wallLong"]; playerId = playerId || 0; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId-1); } orientation = orientation || 0; maxAngle = maxAngle || 2*PI; if (endWithFirst === undefined) endWithFirst = maxAngle < 2*PI - 0.001; // Can this be done better? maxBendOff = maxBendOff || 0; // Check arguments if (maxBendOff > PI/2 || maxBendOff < 0) warn("placeCircularWall maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff); for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) { var bending = wallStyles[style][wallPart[elementIndex]].bending; if (bending != 0) warn("Bending is not supported by placeCircularWall but a bending wall element is used: " + wallPart[elementIndex]); } // Setup number of wall parts var totalLength = maxAngle * radius; var wallPartLength = 0; for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) wallPartLength += wallStyles[style][wallPart[elementIndex]].width; var numParts = 0; if (endWithFirst) numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength); else numParts = ceil(totalLength / wallPartLength); // Setup scale factor var scaleFactor = 1; if (endWithFirst) scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width); else scaleFactor = totalLength / (numParts * wallPartLength); // Place wall entities var actualAngle = orientation + (2*PI - maxAngle) / 2; var x = centerX + radius*cos(actualAngle); var y = centerY + radius*sin(actualAngle); for (var partIndex = 0; partIndex < numParts; partIndex++) for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) { var wallEle = wallStyles[style][wallPart[elementIndex]]; // Width correction var addAngle = scaleFactor * wallEle.width / radius; var targetX = centerX + radius * cos(actualAngle + addAngle); var targetY = centerY + radius * sin(actualAngle + addAngle); var placeX = x + (targetX - x)/2; var placeY = y + (targetY - y)/2; var placeAngle = actualAngle + addAngle/2; // Indent correction placeX -= wallEle.indent * cos(placeAngle); placeY -= wallEle.indent * sin(placeAngle); // Placement var entity = wallEle.entity; if (entity !== undefined) placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle); // Prepare for the next wall element actualAngle += addAngle; x = centerX + radius*cos(actualAngle); y = centerY + radius*sin(actualAngle); } if (endWithFirst) { var wallEle = wallStyles[style][wallPart[0]]; var addAngle = scaleFactor * wallEle.width / radius; var targetX = centerX + radius * cos(actualAngle + addAngle); var targetY = centerY + radius * sin(actualAngle + addAngle); var placeX = x + (targetX - x)/2; var placeY = y + (targetY - y)/2; var placeAngle = actualAngle + addAngle/2; placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placePolygonalWall // // Place a polygonal wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius // // centerX/Y Coordinates of the polygon's center // radius How wide the circle should be in which the polygon fits // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["wallLong", "tower"] // cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower" // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia // playerId Optional. Integer number of the player. Default is 0 (gaia) // orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right) // numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory) // skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true // // NOTE: Don't use wall elements with bending like corners! // TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement // TODO: Check some arguments // TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall = true) { // Setup optional arguments to the default wallPart = wallPart || ["wallLong", "tower"]; cornerWallElement = cornerWallElement || "tower"; // Don't use wide elements for this. Not supported well... playerId = playerId || 0; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId-1); } orientation = orientation || 0; numCorners = numCorners || 8; // Setup angles var angleAdd = 2*PI/numCorners; var angleStart = orientation - angleAdd/2; // Setup corners var corners = []; for (var i = 0; i < numCorners; i++) corners.push([centerX + radius*cos(angleStart + i*angleAdd), centerY + radius*sin(angleStart + i*angleAdd)]); // Place Corners and walls for (var i = 0; i < numCorners; i++) { var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY); placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner); if (!skipFirstWall || i != 0) placeLinearWall( // Adjustment to the corner element width (approximately) corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // startX corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // startY corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // targetX corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // targetY wallPart, style, playerId); } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeIrregularPolygonalWall // // Place an irregular polygonal wall of some wall parts to choose from around centerX/centerY with the given radius // // centerX/Y Coordinates of the polygon's center // radius How wide the circle should be in which the polygon fits // cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower" // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia // playerId Optional. Integer number of the player. Default is 0 (gaia) // orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right) // numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory) // irregularity Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5 // skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true // wallPartsAssortment Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^ // // NOTE: wallPartsAssortment is put to the end because it's hardest to set // NOTE: Don't use wall elements with bending like corners! // TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement // TODO: Check some arguments // TODO: Perhaps add eccentricity //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment) { // Setup optional arguments playerId = playerId || 0; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId-1); } // Generating a generic wall part assortment with each wall part including 1 gate lengthened by walls and towers // NOTE: It might be a good idea to write an own function for that... var defaultWallPartsAssortment = [["wallShort"], ["wall"], ["wallLong"], ["gate", "tower", "wallShort"]]; var centeredWallPart = ["gate"]; var extandingWallPartAssortment = [["tower", "wallLong"], ["tower", "wall"]]; defaultWallPartsAssortment.push(centeredWallPart); for (var i = 0; i < extandingWallPartAssortment.length; i++) { var wallPart = centeredWallPart; for (var j = 0; j < radius; j++) { if (j%2 == 0) wallPart = wallPart.concat(extandingWallPartAssortment[i]); else { extandingWallPartAssortment[i].reverse(); wallPart = extandingWallPartAssortment[i].concat(wallPart); extandingWallPartAssortment[i].reverse(); } defaultWallPartsAssortment.push(wallPart); } } // Setup optional arguments to the default wallPartsAssortment = wallPartsAssortment || defaultWallPartsAssortment; cornerWallElement = cornerWallElement || "tower"; // Don't use wide elements for this. Not supported well... style = style || "palisades"; playerId = playerId || 0; orientation = orientation || 0; - numCorners = numCorners || randInt(5, 7); + numCorners = numCorners || randIntInclusive(5, 7); irregularity = irregularity || 0.5; skipFirstWall = skipFirstWall || false; // Setup angles var angleToCover = 2*PI; var angleAddList = []; for (var i = 0; i < numCorners; i++) { // Randomize covered angles. Variety scales down with raising angle though... angleAddList.push(angleToCover/(numCorners-i) * (1 + randFloat(-irregularity, irregularity))); angleToCover -= angleAddList[angleAddList.length - 1]; } // Setup corners var corners = []; var angleActual = orientation - angleAddList[0]/2; for (var i = 0; i < numCorners; i++) { corners.push([centerX + radius*cos(angleActual), centerY + radius*sin(angleActual)]); if (i < numCorners - 1) angleActual += angleAddList[i+1]; } // Setup best wall parts for the different walls (a bit confusing naming...) var wallPartLengths = []; var maxWallPartLength = 0; for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++) { var length = wallPartLengths[partIndex]; wallPartLengths.push(getWallLength(wallPartsAssortment[partIndex], style)); if (length > maxWallPartLength) maxWallPartLength = length; } var wallPartList = []; // This is the list of the wall parts to use for the walls between the corners, not to confuse with wallPartsAssortment! for (var i = 0; i < numCorners; i++) { var bestWallPart = []; // This is a simpel wall part not a wallPartsAssortment! var bestWallLength = 99999999; // NOTE: This is not exactly like the length the wall will be in the end. Has to be tweaked... var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]); var numWallParts = ceil(wallLength/maxWallPartLength); for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++) { var linearWallLength = numWallParts*wallPartLengths[partIndex]; if (linearWallLength < bestWallLength && linearWallLength > wallLength) { bestWallPart = wallPartsAssortment[partIndex]; bestWallLength = linearWallLength; } } wallPartList.push(bestWallPart); } // Place Corners and walls for (var i = 0; i < numCorners; i++) { var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY); placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner); if (!skipFirstWall || i != 0) placeLinearWall( // Adjustment to the corner element width (approximately) corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[i]/2), // startX corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[i]/2), // startY corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY wallPartList[i], style, playerId, false); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeGenericFortress // // Places a generic fortress with towers at the edges connected with long walls and gates (entries until gates work) // This is the default Iberian civ bonus starting wall // // centerX/Y The approximate center coordinates of the fortress // radius The approximate radius of the wall to be placed // playerId Optional. Integer number of the player. Default is 0 (gaia) // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia // irregularity Optional. Float between 0 (circle) and 1 (very spiky), default is 1/2 // gateOccurence Optional. Integer number, every n-th walls will be a gate instead. Default is 3 // maxTrys Optional. How often the function tries to find a better fitting shape at max. Default is 100 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeGenericFortress(centerX, centerY, radius, playerId, style, irregularity, gateOccurence, maxTrys) { // Setup optional arguments radius = radius || 20; playerId = playerId || 0; if (!wallStyles.hasOwnProperty(style)) { if (playerId == 0) style = style || "palisades"; else style = getCivCode(playerId - 1); } irregularity = irregularity || 1/2; gateOccurence = gateOccurence || 3; maxTrys = maxTrys || 100; // Setup some vars var startAngle = randFloat(0, 2*PI); var actualOffX = radius*cos(startAngle); var actualOffY = radius*sin(startAngle); var actualAngle = startAngle; var pointDistance = wallStyles[style].wallLong.width + wallStyles[style].tower.width; // Searching for a well fitting point derivation var tries = 0; var bestPointDerivation = undefined; var minOverlap = 1000; var overlap = undefined; while (tries < maxTrys && minOverlap > wallStyles[style].tower.width / 10) { var pointDerivation = []; var distanceToTarget = 1000; var targetReached = false; while (!targetReached) { var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance); var tmpAngle = getAngle(actualOffX, actualOffY, (radius + indent)*cos(actualAngle + (pointDistance / radius)), (radius + indent)*sin(actualAngle + (pointDistance / radius))); actualOffX += pointDistance*cos(tmpAngle); actualOffY += pointDistance*sin(tmpAngle); actualAngle = getAngle(0, 0, actualOffX, actualOffY); pointDerivation.push([actualOffX, actualOffY]); distanceToTarget = getDistance(actualOffX, actualOffY, pointDerivation[0][0], pointDerivation[0][1]); var numPoints = pointDerivation.length; if (numPoints > 3 && distanceToTarget < pointDistance) // Could be done better... { targetReached = true; overlap = pointDistance - getDistance(pointDerivation[numPoints - 1][0], pointDerivation[numPoints - 1][1], pointDerivation[0][0], pointDerivation[0][1]); if (overlap < minOverlap) { minOverlap = overlap; bestPointDerivation = pointDerivation; } } } tries++; } log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries"); // Place wall for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++) { var startX = centerX + bestPointDerivation[pointIndex][0]; var startY = centerY + bestPointDerivation[pointIndex][1]; var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0]; var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1]; var angle = getAngle(startX, startY, targetX, targetY); var wallElement = "wallLong"; if ((pointIndex + 1) % gateOccurence == 0) wallElement = "gate"; var entity = wallStyles[style][wallElement].entity; if (entity) { placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY entity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle); } // Place tower var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0]; var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1]; var angle = getAngle(startX, startY, targetX, targetY); placeObject( centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style].tower.entity, playerId, angle - PI/2 + wallStyles[style].tower.angle); } } Index: ps/trunk/binaries/data/mods/public/maps/random/sahel_watering_holes.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/sahel_watering_holes.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/sahel_watering_holes.js (revision 19443) @@ -1,548 +1,548 @@ RMS.LoadLibrary("rmgen"); const tGrass = "savanna_grass_a"; const tForestFloor = "savanna_forestfloor_a"; const tCliff = "savanna_cliff_b"; const tDirtRocksA = "savanna_dirt_rocks_c"; const tDirtRocksB = "savanna_dirt_rocks_a"; const tDirtRocksC = "savanna_dirt_rocks_b"; const tHill = "savanna_cliff_a"; const tRoad = "savanna_tile_a_red"; const tRoadWild = "savanna_tile_a_red"; const tGrassPatch = "savanna_grass_b"; const tShoreBlend = "savanna_riparian"; const tShore = "savanna_riparian_bank"; const tWater = "savanna_riparian_wet"; // gaia entities const oBaobab = "gaia/flora_tree_baobab"; const oFig = "gaia/flora_tree_fig"; const oBerryBush = "gaia/flora_bush_berry"; const oWildebeest = "gaia/fauna_wildebeest"; const oFish = "gaia/fauna_fish"; const oGazelle = "gaia/fauna_gazelle"; const oElephant = "gaia/fauna_elephant_african_bush"; const oGiraffe = "gaia/fauna_giraffe"; const oZebra = "gaia/fauna_zebra"; const oStoneLarge = "gaia/geology_stonemine_desert_quarry"; const oStoneSmall = "gaia/geology_stone_savanna_small"; const oMetalLarge = "gaia/geology_metal_savanna_slabs"; // decorative props const aGrass = "actor|props/flora/grass_savanna.xml"; const aGrassShort = "actor|props/flora/grass_medit_field.xml"; const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; const aLillies = "actor|props/flora/reeds_pond_lush_b.xml"; const aRockLarge = "actor|geology/stone_savanna_med.xml"; const aRockMedium = "actor|geology/stone_savanna_med.xml"; const aBushMedium = "actor|props/flora/bush_desert_dry_a.xml"; const aBushSmall = "actor|props/flora/bush_dry_a.xml"; const pForest = [tForestFloor + TERRAIN_SEPARATOR + oBaobab, tForestFloor + TERRAIN_SEPARATOR + oBaobab, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clShallows = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 5; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(12, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oBaobab, num, num, 0,3)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(20); //create rivers log ("Creating rivers..."); for (var m = 0; m < numPlayers; m++) { var tang = startAngle + (m + 0.5) * TWO_PI / numPlayers; placer = new ClumpPlacer(floor(PI*scaleByMapSize(10,50)*scaleByMapSize(10,50)/3), 0.95, 0.6, 10, fractionToTiles(0.5 + 0.15*cos(tang)), fractionToTiles(0.5 + 0.15*sin(tang))); var painter = new LayeredPainter([tShore, tWater, tWater], [1, 3]); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -4, 4); createArea(placer, [painter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 5)); var placer = new PathPlacer(fractionToTiles(0.5 + 0.15*cos(tang)), fractionToTiles(0.5 + 0.15*sin(tang)), fractionToTiles(0.5 + 0.49*cos(tang)), fractionToTiles(0.5 + 0.49*sin(tang)), scaleByMapSize(10,50), 0.2, 3*(scaleByMapSize(1,4)), 0.2, 0.05); var terrainPainter = new LayeredPainter( [tShore, tWater, tWater], // terrains [1, 3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type -4, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 5)); placer = new ClumpPlacer(floor(PI*scaleByMapSize(10,50)*scaleByMapSize(10,50)/5), 0.95, 0.6, 10, fractionToTiles(0.5 + 0.49*cos(tang)), fractionToTiles(0.5 + 0.49*sin(tang))); var painter = new LayeredPainter([tWater, tWater], [1]); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -4, 4); createArea(placer, [painter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 5)); } for (var i = 0; i < numPlayers; i++) { if (i+1 == numPlayers) { passageMaker( round(fractionToTiles(playerX[i])), round(fractionToTiles(playerZ[i])), round(fractionToTiles(playerX[0])), round(fractionToTiles(playerZ[0])), 6, -2, -2, 4, clShallows, undefined, -4); // create animals in shallows log("Creating animals in shallows..."); var group = new SimpleGroup( [new SimpleObject(oElephant, 2,3, 0,4)], true, clFood, round((fractionToTiles(playerX[i]) + fractionToTiles(playerX[0]))/2), round((fractionToTiles(playerZ[i]) + fractionToTiles(playerZ[0]))/2) ); createObjectGroup(group, 0); var group = new SimpleGroup( [new SimpleObject(oWildebeest, 5,6, 0,4)], true, clFood, round((fractionToTiles(playerX[i]) + fractionToTiles(playerX[0]))/2), round((fractionToTiles(playerZ[i]) + fractionToTiles(playerZ[0]))/2) ); createObjectGroup(group, 0); } else { passageMaker( fractionToTiles(playerX[i]), fractionToTiles(playerZ[i]), fractionToTiles(playerX[i+1]), fractionToTiles(playerZ[i+1]), 6, -2, -2, 4, clShallows, undefined, -4); // create animals in shallows log("Creating animals in shallows..."); var group = new SimpleGroup( [new SimpleObject(oElephant, 2,3, 0,4)], true, clFood, round((fractionToTiles(playerX[i]) + fractionToTiles(playerX[i+1]))/2), round((fractionToTiles(playerZ[i]) + fractionToTiles(playerZ[i+1]))/2) ); createObjectGroup(group, 0); var group = new SimpleGroup( [new SimpleObject(oWildebeest, 5,6, 0,4)], true, clFood, round((fractionToTiles(playerX[i]) + fractionToTiles(playerX[i+1]))/2), round((fractionToTiles(playerZ[i]) + fractionToTiles(playerZ[i+1]))/2) ); createObjectGroup(group, 0); } } paintTerrainBasedOnHeight(-6, 2, 1, tWater); // create bumps log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, avoidClasses(clWater, 2, clPlayer, 20), scaleByMapSize(100, 200) ); // create hills log("Creating hills..."); placer = new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1); terrainPainter = new LayeredPainter( [tGrass, tCliff, tHill], // terrains [1, 2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 35, 3); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 20, clHill, 15, clWater, 3), scaleByMapSize(1, 4) * numPlayers ); // calculate desired number of trees for map (based on size) var MIN_TREES = 160; var MAX_TREES = 900; var P_FOREST = 0.02; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [ [[tForestFloor, tGrass, pForest], [tForestFloor, pForest]] ]; // some variation var size = numForest / (0.5 * scaleByMapSize(2,8) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ClumpPlacer(numForest / num, 0.1, 0.1, 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clForest, 10, clHill, 0, clWater, 2), num ); } RMS.SetProgress(50); // create dirt patches log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter( [[tGrass,tDirtRocksA],[tDirtRocksA,tDirtRocksB], [tDirtRocksB,tDirtRocksC]], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 3, clForest, 0, clHill, 0, clPlayer, 20), scaleByMapSize(15, 45) ); } // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new TerrainPainter(tGrassPatch); createAreas( placer, painter, avoidClasses(clWater, 3, clForest, 0, clHill, 0, clPlayer, 20), scaleByMapSize(15, 45) ); } RMS.SetProgress(55); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), scaleByMapSize(4,16), 100 ); RMS.SetProgress(65); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(16, 262), 50 ); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(8, 131), 50 ); RMS.SetProgress(70); // create wildebeest log("Creating wildebeest..."); group = new SimpleGroup( [new SimpleObject(oWildebeest, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), 3 * numPlayers, 50 ); RMS.SetProgress(75); // create gazelle log("Creating gazelle..."); group = new SimpleGroup( [new SimpleObject(oGazelle, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), 3 * numPlayers, 50 ); // create elephant log("Creating elephant..."); group = new SimpleGroup( [new SimpleObject(oElephant, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), 3 * numPlayers, 50 ); // create giraffe log("Creating giraffe..."); group = new SimpleGroup( [new SimpleObject(oGiraffe, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), 3 * numPlayers, 50 ); // create zebra log("Creating zebra..."); group = new SimpleGroup( [new SimpleObject(oZebra, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), 3 * numPlayers, 50 ); // create fish log("Creating fish..."); group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clFood, 20), stayClasses(clWater, 6)], 25 * numPlayers, 60 ); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); RMS.SetProgress(85); // create straggler trees log("Creating straggler trees..."); var types = [oBaobab, oBaobab, oBaobab, oFig]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), num ); } var planetm = 4; //create small grass tufts log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clHill, 2, clPlayer, 2), planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(90); // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clForest, 0), planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(95); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clHill, 1, clPlayer, 1), planetm * scaleByMapSize(13, 200), 50 ); setSkySet("sunny"); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 5, PI / 4)); setWaterColor(0.478,0.42,0.384); // greyish setWaterTint(0.58,0.22,0.067); // reddish setWaterMurkiness(0.87); setWaterWaviness(0.5); setWaterType("clap"); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/african_plains.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/african_plains.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/african_plains.js (revision 19443) @@ -1,357 +1,357 @@ RMS.LoadLibrary("rmgen"); var tPrimary = ["savanna_grass_a"]; var tForestFloor = "savanna_forestfloor_a"; var tCliff = ["savanna_cliff_a", "savanna_cliff_a_red", "savanna_cliff_b", "savanna_cliff_b_red"]; var tSecondary = "savanna_grass_b"; var tGrassShrubs = ["savanna_shrubs_a"]; var tGrass = ["savanna_grass_a_wetseason", "savanna_grass_b_wetseason"]; var tDirt = "savanna_dirt_a"; var tDirt2 = "savanna_dirt_a_red"; var tDirt3 = "savanna_dirt_b"; var tDirt4 = "savanna_dirt_rocks_a"; var tCitytiles = "savanna_tile_a"; var tShore = "savanna_riparian_bank"; var tWater = "savanna_riparian_wet"; // gaia entities var oBaobab = "gaia/flora_tree_baobab"; var oPalm = "gaia/flora_tree_senegal_date_palm"; var oBerryBush = "gaia/flora_bush_berry"; var oWildebeest = "gaia/fauna_wildebeest"; var oZebra = "gaia/fauna_zebra"; var oRhino = "gaia/fauna_rhino"; var oLion = "gaia/fauna_lion"; var oLioness = "gaia/fauna_lioness"; var oHawk = "gaia/fauna_hawk"; var oGiraffe = "gaia/fauna_giraffe"; var oGiraffe2 = "gaia/fauna_giraffe_infant"; var oGazelle = "gaia/fauna_gazelle"; var oElephant = "gaia/fauna_elephant_african_bush"; var oElephant2 = "gaia/fauna_elephant_african_infant"; var oCrocodile = "gaia/fauna_crocodile"; var oFish = "gaia/fauna_fish"; var oStoneSmall = "gaia/geology_stone_savanna_small"; var oMetalLarge = "gaia/geology_metal_savanna_slabs"; // decorative props var aBush = "actor|props/flora/bush_medit_sm_dry.xml"; var aRock = "actor|geology/stone_savanna_med.xml"; const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPalm, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); RMS.SetProgress(20); var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); // Cover the ground with the primary terrain chosen in the beginning for (var ix = 0; ix < mapSize; ++ix) for (var iz = 0; iz < mapSize; ++iz) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); placeTerrain(ix, iz, tPrimary); } // Randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; ++i) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); // Place players var playerX = []; var playerZ = []; var playerAngle = []; var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; ++i) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35 * cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35 * sin(playerAngle[i]); } for (var i = 0; i < numPlayers; ++i) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); var radius = scaleByMapSize(15,25); // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tPrimary,tCitytiles], [1]); createArea(placer, painter, null); placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while (abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); createStoneMineFormation(mX, mZ, tDirt4); addToClass(mX, mZ, clPlayer); // create starting trees var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oBaobab, 2,7)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } RMS.SetProgress(20); createHills([tDirt2, tCliff, tGrassShrubs], avoidClasses(clPlayer, 35, clForest, 20, clHill, 20, clWater, 2), clHill, scaleByMapSize(5, 8)); RMS.SetProgress(30); var lakeAreas = []; var playerConstraint = new AvoidTileClassConstraint(clPlayer, 20); var waterConstraint = new AvoidTileClassConstraint(clWater, 8); for (var x = 0; x < mapSize; ++x) for (var z = 0; z < mapSize; ++z) if (playerConstraint.allows(x, z) && waterConstraint.allows(x, z)) lakeAreas.push([x, z]); log("Creating water holes..."); placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), floor(scaleByMapSize(60, 100)), 5); var terrainPainter = new LayeredPainter( [tShore, tWater], // terrains [1] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -5, 7); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 22, clWater, 8, clHill, 2), scaleByMapSize(2, 5) ); RMS.SetProgress(45); paintTerrainBasedOnHeight(3, floor(scaleByMapSize(20, 40)), 0, tCliff); paintTerrainBasedOnHeight(floor(scaleByMapSize(20, 40)), 100, 3, tGrass); createBumps(avoidClasses(clWater, 2, clPlayer, 20)); createForests( [tPrimary, tForestFloor, tForestFloor, pForest, pForest], avoidClasses(clPlayer, 20, clForest, 20, clHill, 0, clWater, 2), clForest, 1.0 ); log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tDirt,tDirt3], [tDirt2,tDirt4]], [2], avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12) ); log("Creating shrubs..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tGrassShrubs, avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12) ); log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tSecondary, avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12) ); RMS.SetProgress(60); log("Creating stone mines..."); createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clWater, 4, clForest, 4, clPlayer, 20, clRock, 10, clHill, 4) ); log("Creating metal mines..."); createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clWater, 4, clForest, 4, clPlayer, 20, clMetal, 18, clRock, 5, clHill, 4), clMetal ); RMS.SetProgress(70); createDecoration( [ [new SimpleObject(aBush, 1,3, 0,1)], [new SimpleObject(aRock, 1,2, 0,1)] ], [ scaleByMapSize(8, 131), scaleByMapSize(8, 131), ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0) ); RMS.SetProgress(75); log("Creating giraffes..."); group = new SimpleGroup( [new SimpleObject(oGiraffe, 2,4, 0,4), new SimpleObject(oGiraffe2, 0,2, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clPlayer, 20, clFood, 11, clHill, 4), scaleByMapSize(4,12), 50 ); log("Creating elephants..."); group = new SimpleGroup( [new SimpleObject(oElephant, 2,4, 0,4), new SimpleObject(oElephant2, 0,2, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clPlayer, 20, clFood, 11, clHill, 4), scaleByMapSize(4,12), 50 ); log("Creating lions..."); group = new SimpleGroup( [new SimpleObject(oLion, 0,1, 0,4), new SimpleObject(oLioness, 2,3, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clPlayer, 20, clFood, 11, clHill, 4), scaleByMapSize(4,12), 50 ); createFood( [ [new SimpleObject(oHawk, 1,1, 0,3)], [new SimpleObject(oGazelle, 3,5, 0,3)], [new SimpleObject(oZebra, 3,5, 0,3)], [new SimpleObject(oWildebeest, 4,6, 0,3)], [new SimpleObject(oRhino, 1,1, 0,3)] ], [ 3 * numPlayers, 3 * numPlayers, 3 * numPlayers, 3 * numPlayers, 3 * numPlayers, ], avoidClasses(clFood, 20, clWater, 5, clHill, 2, clPlayer, 16) ); createFood( [ [new SimpleObject(oCrocodile, 2,3, 0,3)] ], [ 3 * numPlayers, ], stayClasses(clWater, 6) ); createFood( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(1, 4) * numPlayers + 2 + randIntInclusive(1, 4) * numPlayers + 2 ], avoidClasses(clWater, 3, clForest, 2, clPlayer, 20, clHill, 3, clFood, 10) ); createFood( [ [new SimpleObject(oFish, 2,3, 0,2)] ], [ 15 * numPlayers ], [avoidClasses(clFood, 20), stayClasses(clWater, 6)] ); RMS.SetProgress(85); createStragglerTrees( [oBaobab], avoidClasses(clWater, 5, clForest, 2, clHill, 3, clPlayer, 12, clMetal, 4, clRock, 4) ); setPPEffect("hdr"); setPPSaturation(0.48); setPPContrast(0.53); setPPBloom(0.12); setFogThickness(0.25); setFogFactor(0.25); setFogColor(0.8, 0.7, 0.5); setSkySet("sunny"); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 4, PI / 2)); setWaterColor(0.223, 0.247, 0.2); // dark majestic blue setWaterTint(0.462, 0.756, 0.566); // light blue setWaterMurkiness(5.92); setWaterWaviness(0); setWaterType("clap"); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/alpine_lakes.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/alpine_lakes.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/alpine_lakes.js (revision 19443) @@ -1,411 +1,411 @@ RMS.LoadLibrary("rmgen"); // late spring if (randBool()) { setFogThickness(0.26); setFogFactor(0.4); setPPEffect("hdr"); setPPSaturation(0.48); setPPContrast(0.53); setPPBloom(0.12); var tPrimary = ["alpine_dirt_grass_50"]; var tForestFloor = "alpine_forrestfloor"; var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; var tSecondary = "alpine_grass_rocky"; var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; var tSnowLimited = ["alpine_snow_rocky"]; var tDirt = "alpine_dirt"; var tRoad = "new_alpine_citytile"; var tRoadWild = "new_alpine_citytile"; var tShore = "alpine_shore_rocks_grass_50"; var tWater = "alpine_shore_rocks"; // gaia entities var oPine = "gaia/flora_tree_pine"; var oBerryBush = "gaia/flora_bush_berry"; var oDeer = "gaia/fauna_deer"; var oFish = "gaia/fauna_fish"; var oRabbit = "gaia/fauna_rabbit"; var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; var oStoneSmall = "gaia/geology_stone_alpine_a"; var oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props var aGrass = "actor|props/flora/grass_soft_small_tall.xml"; var aGrassShort = "actor|props/flora/grass_soft_large.xml"; var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; var aBushMedium = "actor|props/flora/bush_medit_me.xml"; var aBushSmall = "actor|props/flora/bush_medit_sm.xml"; } else //winter { setFogFactor(0.35); setFogThickness(0.19); setPPSaturation(0.37); setPPEffect("hdr"); var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; var tForestFloor = "alpine_forrestfloor_snow"; var tCliff = ["alpine_cliff_snow"]; var tSecondary = "alpine_grass_snow_50"; var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; var tDirt = "alpine_dirt"; var tRoad = "new_alpine_citytile"; var tRoadWild = "new_alpine_citytile"; var tShore = "alpine_shore_rocks_icy"; var tWater = "alpine_shore_rocks"; // gaia entities var oPine = "gaia/flora_tree_pine_w"; var oBerryBush = "gaia/flora_bush_berry"; var oDeer = "gaia/fauna_deer"; var oFish = "gaia/fauna_fish"; var oRabbit = "gaia/fauna_rabbit"; var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; var oStoneSmall = "gaia/geology_stone_alpine_a"; var oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; var aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; var aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; } //other constants const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); //cover the ground with the primary terrain chosen in the beginning for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); placeTerrain(ix, iz, tPrimary); } } // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 100); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPine, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(20); // create hills log("Creating hills..."); createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 8), clHill, scaleByMapSize(10, 40) * numPlayers, floor(scaleByMapSize(40, 60)), floor(scaleByMapSize(4, 5)), floor(scaleByMapSize(7, 15)), floor(scaleByMapSize(5, 15))); RMS.SetProgress(30); var lakeAreas = []; var playerConstraint = new AvoidTileClassConstraint(clPlayer, 20); var waterConstraint = new AvoidTileClassConstraint(clWater, 8); for (var x = 0; x < mapSize; ++x) for (var z = 0; z < mapSize; ++z) if (playerConstraint.allows(x, z) && waterConstraint.allows(x, z)) lakeAreas.push([x, z]); var chosenPoint; var lakeAreaLen; // create lakes log("Creating lakes..."); var numLakes = scaleByMapSize(5, 16); for (var i = 0; i < numLakes; ++i) { lakeAreaLen = lakeAreas.length; if (!lakeAreaLen) break; chosenPoint = pickRandom(lakeAreas); placer = new ChainPlacer(1, floor(scaleByMapSize(4, 8)), floor(scaleByMapSize(40, 180)), 0.7, chosenPoint[0], chosenPoint[1]); var terrainPainter = new LayeredPainter( [tShore, tWater, tWater], // terrains [1, 3] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -5, 5); var newLake = createAreas( placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 20, clWater, 8), 1, 1 ); if (newLake && newLake.length) { var n = 0; for (var j = 0; j < lakeAreaLen; ++j) { var x = lakeAreas[j][0], z = lakeAreas[j][1]; if (playerConstraint.allows(x, z) && waterConstraint.allows(x, z)) lakeAreas[n++] = lakeAreas[j]; } lakeAreas.length = n; } } paintTerrainBasedOnHeight(3, floor(scaleByMapSize(20, 40)), 0, tCliff); paintTerrainBasedOnHeight(floor(scaleByMapSize(20, 40)), 100, 3, tSnowLimited); // create bumps createBumps(avoidClasses(clWater, 2, clPlayer, 20)); // create forests createForests( [tPrimary, tForestFloor, tForestFloor, pForest, pForest], avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), clForest, 1.0 ); RMS.SetProgress(60); // create dirt patches log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], [2], avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12) ); // create grass patches log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tSecondary, avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12) ); RMS.SetProgress(65); log("Creating stone mines..."); // create stone quarries createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1) ); log("Creating metal mines..."); // create large metal quarries createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), clMetal ); RMS.SetProgress(70); // create decoration 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), scaleByMapSize(13, 200), scaleByMapSize(13, 200), scaleByMapSize(13, 200) ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0) ); RMS.SetProgress(75); // create animals createFood ( [ [new SimpleObject(oDeer, 5,7, 0,4)], [new SimpleObject(oRabbit, 2,3, 0,2)] ], [ 3 * numPlayers, 3 * numPlayers ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20) ); // create fruits createFood ( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(1, 4) * numPlayers + 2 + randIntInclusive(1, 4) * numPlayers + 2 ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10) ); // create fish createFood ( [ [new SimpleObject(oFish, 2,3, 0,2)] ], [ 15 * numPlayers ], [avoidClasses(clFood, 20), stayClasses(clWater, 6)] ); RMS.SetProgress(85); // create straggler trees var types = [oPine]; createStragglerTrees(types, avoidClasses(clWater, 5, clForest, 3, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6)); setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 5, PI / 3)); setWaterColor(0.0, 0.047, 0.286); // dark majestic blue setWaterTint(0.471, 0.776, 0.863); // light blue setWaterMurkiness(0.82); setWaterWaviness(3.0); setWaterType("clap"); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/alpine_valley.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/alpine_valley.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/alpine_valley.js (revision 19443) @@ -1,639 +1,639 @@ RMS.LoadLibrary("rmgen"); TILE_CENTERED_HEIGHT_MAP = true; // late spring if (randBool()) { var tPrimary = ["alpine_dirt_grass_50"]; var tForestFloor = "alpine_forrestfloor"; var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; var tSecondary = "alpine_grass_rocky"; var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; var tSnowLimited = ["alpine_snow_rocky"]; var tDirt = "alpine_dirt"; var tRoad = "new_alpine_citytile"; var tRoadWild = "new_alpine_citytile"; var tShore = "alpine_shore_rocks_grass_50"; var tWater = "alpine_shore_rocks"; // gaia entities var oPine = "gaia/flora_tree_pine"; var oBerryBush = "gaia/flora_bush_berry"; var oDeer = "gaia/fauna_deer"; var oRabbit = "gaia/fauna_rabbit"; var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; var oStoneSmall = "gaia/geology_stone_alpine_a"; var oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props var aGrass = "actor|props/flora/grass_soft_small_tall.xml"; var aGrassShort = "actor|props/flora/grass_soft_large.xml"; var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; var aBushMedium = "actor|props/flora/bush_medit_me.xml"; var aBushSmall = "actor|props/flora/bush_medit_sm.xml"; } else //winter { var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; var tForestFloor = "alpine_forrestfloor_snow"; var tCliff = ["alpine_cliff_snow"]; var tSecondary = "alpine_grass_snow_50"; var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; var tDirt = "alpine_dirt"; var tRoad = "new_alpine_citytile"; var tRoadWild = "new_alpine_citytile"; var tShore = "alpine_shore_rocks_icy"; var tWater = "alpine_shore_rocks"; // gaia entities var oPine = "gaia/flora_tree_pine_w"; var oBerryBush = "gaia/flora_bush_berry"; var oDeer = "gaia/fauna_deer"; var oRabbit = "gaia/fauna_rabbit"; var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; var oStoneSmall = "gaia/geology_stone_alpine_a"; var oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; var aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; var aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; } //other constants const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); //cover the ground with the primary terrain chosen in the beginning for (var ix = 0; ix < mapSize; ix++) for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); placeTerrain(ix, iz, tPrimary); } // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); // place players var playerX = []; var playerZ = []; var playerAngle = []; var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); ix = round(fx); iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 100); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPine, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(20); //place the mountains var points = []; var edgesConncetedToPoints = []; //we want the points near the start locations be the first ones. hence we use two "for" blocks for (var i = 0; i < numPlayers; ++i) { playerAngle[i] = startAngle + (i+0.5)*TWO_PI/numPlayers; points.push([round(fractionToTiles(0.5 + 0.49 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.49 * sin(playerAngle[i])))]); } //the order of the other points doesn't matter for (var i = 0; i < numPlayers; ++i) { playerAngle[i] = startAngle + (i+0.7)*TWO_PI/numPlayers; points.push([round(fractionToTiles(0.5 + 0.34 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.34 * sin(playerAngle[i])))]); playerAngle[i] = startAngle + (i+0.3)*TWO_PI/numPlayers; points.push([round(fractionToTiles(0.5 + 0.34 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.34 * sin(playerAngle[i])))]); playerAngle[i] = startAngle + (i+0.5)*TWO_PI/numPlayers; points.push([round(fractionToTiles(0.5 + 0.18 * cos(playerAngle[i]))), round(fractionToTiles(0.5 + 0.18 * sin(playerAngle[i])))]); } //add the center of the map points.push([round(fractionToTiles(0.5)), round(fractionToTiles(0.5))]); var numPoints = numPlayers * 4 + 1; for (var i = 0; i < numPoints; ++i) edgesConncetedToPoints.push(0); //we are making a planar graph where every edge is a straight line. var possibleEdges = []; //add all of the possible combinations for (var i = 0; i < numPoints; ++i) for (var j = numPlayers; j < numPoints; ++j) if (j > i) possibleEdges.push([i,j]); //we need a matrix so that we can prevent the mountain ranges from bocking a player var matrix = []; for (var i = 0; i < numPoints; ++i) { matrix.push([]); for (var j = 0; j < numPoints; ++j) matrix[i].push(i < numPlayers && j < numPlayers && i != j && (i == j - 1 || i == j + 1)) } //find and place the edges while (possibleEdges.length) { - var index = randInt(0, possibleEdges.length - 1); + var index = randIntExclusive(0, possibleEdges.length); //ensure that a point is connected to a maximum of 3 others if (edgesConncetedToPoints[possibleEdges[index][0]] > 2 || edgesConncetedToPoints[possibleEdges[index][1]] > 2) { possibleEdges.splice(index,1); continue; } //we don't want ranges that are longer than half of the map's size if ((((points[possibleEdges[index][0]][0] - points[possibleEdges[index][1]][0]) * (points[possibleEdges[index][0]][0] - points[possibleEdges[index][1]][0])) + ((points[possibleEdges[index][0]][1] - points[possibleEdges[index][1]][1]) * (points[possibleEdges[index][0]][1] - points[possibleEdges[index][1]][1]))) > mapArea) { possibleEdges.splice(index,1); continue; } //dfs var q = [possibleEdges[index][0]]; matrix[possibleEdges[index][0]][possibleEdges[index][1]] = true; matrix[possibleEdges[index][1]][possibleEdges[index][0]] = true; var selected, accept = true, tree = [], backtree = []; while (q.length > 0) { selected = q.shift(); if (tree.indexOf(selected) == -1) { tree.push(selected); backtree.push(-1); } for (var i = 0; i < numPoints; ++i) if (matrix[selected][i]) { if (i == backtree[tree.lastIndexOf(selected)]) continue; if (tree.indexOf(i) == -1) { tree.push(i); backtree.push(selected); q.unshift(i); } else { accept = false; matrix[possibleEdges[index][0]][possibleEdges[index][1]] = false; matrix[possibleEdges[index][1]][possibleEdges[index][0]] = false; break; } } } if (!accept) { possibleEdges.splice(index,1); continue; } var ix = points[possibleEdges[index][0]][0]; var iz = points[possibleEdges[index][0]][1]; var ix2 = points[possibleEdges[index][1]][0]; var iz2 = points[possibleEdges[index][1]][1]; var placer = new PathPlacer(ix, iz, ix2, iz2, scaleByMapSize(9,15), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0.1, 0.1); var terrainPainter = new LayeredPainter( [tCliff, tPrimary], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 30, // elevation 2 // blend radius ); accept = createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 20)); if (accept == null) { matrix[possibleEdges[index][0]][possibleEdges[index][1]] = false; matrix[possibleEdges[index][1]][possibleEdges[index][0]] = false; possibleEdges.splice(index,1); continue; } else { placer = new ClumpPlacer(floor(PI*scaleByMapSize(9,15)*scaleByMapSize(9,15)/4), 0.95, 0.6, 10, ix, iz); var terrainPainter = new LayeredPainter( [tCliff, tPrimary], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 30, // elevation 2 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 5)); placer = new ClumpPlacer(floor(PI*scaleByMapSize(9,15)*scaleByMapSize(9,15)/4), 0.95, 0.6, 10, ix2, iz2); var terrainPainter = new LayeredPainter( [tCliff, tPrimary], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 30, // elevation 2 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 5)); } for (var i = 0; i < possibleEdges.length; ++i) { if (possibleEdges[index][0] != possibleEdges[i][0] && possibleEdges[index][1] != possibleEdges[i][0] && possibleEdges[index][0] != possibleEdges[i][1] && possibleEdges[index][1] != possibleEdges[i][1]) { if (checkIfIntersect (points[possibleEdges[index][0]][0], points[possibleEdges[index][0]][1], points[possibleEdges[index][1]][0], points[possibleEdges[index][1]][1], points[possibleEdges[i][0]][0], points[possibleEdges[i][0]][1], points[possibleEdges[i][1]][0], points[possibleEdges[i][1]][1], scaleByMapSize(9,15) + scaleByMapSize(10,15))) { possibleEdges.splice(i,1); --i; if (index > i) --index; } } else if (((possibleEdges[index][0] == possibleEdges[i][0] && possibleEdges[index][1] != possibleEdges[i][1]) || (possibleEdges[index][1] == possibleEdges[i][0] && possibleEdges[index][0] != possibleEdges[i][1])) && distanceOfPointFromLine(points[possibleEdges[index][0]][0],points[possibleEdges[index][0]][1], points[possibleEdges[index][1]][0], points[possibleEdges[index][1]][1],points[possibleEdges[i][1]][0], points[possibleEdges[i][1]][1]) < scaleByMapSize(9,15) + scaleByMapSize(10,15)) { possibleEdges.splice(i,1); --i; if (index > i) --index; } else if (((possibleEdges[index][0] == possibleEdges[i][1] && possibleEdges[index][1] != possibleEdges[i][0]) || (possibleEdges[index][1] == possibleEdges[i][1] && possibleEdges[index][0] != possibleEdges[i][0])) && distanceOfPointFromLine(points[possibleEdges[index][0]][0],points[possibleEdges[index][0]][1], points[possibleEdges[index][1]][0], points[possibleEdges[index][1]][1],points[possibleEdges[i][0]][0], points[possibleEdges[i][0]][1]) < scaleByMapSize(9,15) + scaleByMapSize(10,15)) { possibleEdges.splice(i,1); --i; if (index > i) --index; } } edgesConncetedToPoints[possibleEdges[index][0]] += 1; edgesConncetedToPoints[possibleEdges[index][1]] += 1; possibleEdges.splice(index,1); } paintTerrainBasedOnHeight(3.1, 29, 0, tCliff); paintTerrainBasedOnHeight(29, 30, 3, tSnowLimited); log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, avoidClasses(clPlayer, 10), scaleByMapSize(100, 200) ); RMS.SetProgress(40); log("Creating hills..."); placer = new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, 1); var terrainPainter = new LayeredPainter( [tCliff, tSnowLimited], // terrains [2] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 30, 2); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 20, clHill, 14), scaleByMapSize(10, 80) * numPlayers ); RMS.SetProgress(50); // calculate desired number of trees for map (based on size) var MIN_TREES = 500; var MAX_TREES = 3000; var P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); log("Creating forests..."); var types = [ [[tForestFloor, tPrimary, pForest], [tForestFloor, pForest]] ]; // some variation var size = numForest / (scaleByMapSize(2,8) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ClumpPlacer(numForest / num, 0.1, 0.1, 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 12, clForest, 10, clHill, 0), num ); } RMS.SetProgress(60); log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter( [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45) ); } log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new TerrainPainter(tSecondary); createAreas( placer, painter, avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45) ); } RMS.SetProgress(65); log("Creating stone mines..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(4,16), 100 ); log("Creating small stone mines..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), scaleByMapSize(4,16), 100 ); RMS.SetProgress(70); log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(16, 262), 50 ); log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(8, 131), 50 ); RMS.SetProgress(75); log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); log("Creating rabbit..."); group = new SimpleGroup( [new SimpleObject(oRabbit, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); RMS.SetProgress(85); log("Creating straggler trees..."); var types = [oPine, oPine]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), num ); } log("Creating small grass tufts..."); var planetm = 1; group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0), planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(90); log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(95); log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), planetm * scaleByMapSize(13, 200), 50 ); setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 5, PI / 3)); setWaterColor(0.0, 0.047, 0.286); // dark majestic blue setWaterTint(0.471, 0.776, 0.863); // light blue setWaterMurkiness(0.72); setWaterWaviness(2.0); setWaterType("lake"); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/anatolian_plateau.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/anatolian_plateau.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/anatolian_plateau.js (revision 19443) @@ -1,381 +1,381 @@ RMS.LoadLibrary("rmgen"); const tGrass = ["steppe_grass_a", "steppe_grass_b", "steppe_grass_c", "steppe_grass_d"]; const tForestFloor = "steppe_grass_c"; const tGrassA = "steppe_grass_b"; const tGrassB = "steppe_grass_c"; const tGrassC = ["steppe_grass_b", "steppe_grass_c", "steppe_grass_d"]; const tGrassD = "steppe_grass_a"; const tDirt = ["steppe_dirt_a", "steppe_dirt_b"]; const tRoad = "road_stones"; const tRoadWild = "road_stones"; const tShoreBlend = "desert_shore_stones"; const tShore = "dirta"; const tWater = "desert_sand_wet"; // gaia entities const oPoplar = "gaia/flora_tree_poplar_lombardy"; const oBush = "gaia/flora_bush_temperate"; const oBerryBush = "gaia/flora_bush_berry"; const oRabbid = "gaia/fauna_rabbit"; const oSheep = "gaia/fauna_sheep"; const oStoneLarge = "gaia/geology_stonemine_medit_quarry"; const oStoneSmall = "gaia/geology_stone_mediterranean"; const oMetalLarge = "gaia/geology_metal_mediterranean_slabs"; // decorative props const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; const aGrassShort = "actor|props/flora/grass_soft_large.xml"; const aRockLarge = "actor|geology/stone_granite_med.xml"; const aRockMedium = "actor|geology/stone_granite_med.xml"; const aBushMedium = "actor|props/flora/bush_medit_me.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPoplar, tForestFloor]; log("Initializing map..."); InitMap(); var numPlayers = getNumPlayers(); var mapSize = getMapSize(); var mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 100); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPoplar, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(20); // create bumps log("Creating bumps..."); placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(2, 5)), 0.5); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, avoidClasses(clPlayer, 13), scaleByMapSize(300, 800) ); // calculate desired number of trees for map (based on size) var MIN_TREES = 220; var MAX_TREES = 1000; var P_FOREST = 0.65; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [[[tForestFloor, tGrass, pForest], [tForestFloor, pForest]]]; // some variation var size = numForest / (scaleByMapSize(2,8) * numPlayers); var num = 4 * floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(2, 3)), 4, 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 13, clForest, 20, clHill, 1), num ); } RMS.SetProgress(50); // create grass patches log("Creating grass patches..."); createLayeredPatches( [scaleByMapSize(5, 48), scaleByMapSize(6, 84), scaleByMapSize(8, 128)], [[tGrass,tGrassA,tGrassC],[tGrass,tGrassA,tGrassC], [tGrass,tGrassA,tGrassC]], [1,1], avoidClasses(clForest, 0, clHill, 0, clDirt, 2, clPlayer, 10), scaleByMapSize(50, 70), clDirt ); // create dirt patches log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(5, 32), scaleByMapSize(6, 48), scaleByMapSize(7, 80)], [tGrassD ,tDirt], [1], avoidClasses(clForest, 0, clHill, 0, clDirt, 2, clPlayer, 10), scaleByMapSize(50, 90), clDirt ); RMS.SetProgress(55); // create big patches log("Creating big patches..."); createLayeredPatches( [scaleByMapSize(10, 60), scaleByMapSize(15, 90), scaleByMapSize(20, 120)], [tGrassB ,tGrassA], [1], avoidClasses(clHill, 0, clPlayer, 8), scaleByMapSize(30, 90), clDirt ); RMS.SetProgress(55); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(1,4), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(1,4), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), scaleByMapSize(2,8), 100 ); RMS.SetProgress(65); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 0), scaleByMapSize(16, 262), 50 ); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 0), scaleByMapSize(8, 131), 50 ); RMS.SetProgress(70); // create rabbid log("Creating rabbid..."); group = new SimpleGroup( [new SimpleObject(oRabbid, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 6 * numPlayers, 50 ); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); RMS.SetProgress(75); // create sheep log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oSheep, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); RMS.SetProgress(85); // create straggler trees log("Creating straggler trees..."); var types = [oBush, oPoplar]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clForest, 1, clHill, 1, clPlayer, 13, clMetal, 6, clRock, 6), num ); } // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), scaleByMapSize(13, 200) ); RMS.SetProgress(95); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), scaleByMapSize(13, 200), 50 ); setFogThickness(0.1); setFogFactor(0.2); setPPEffect("hdr"); setPPSaturation(0.45); setPPContrast(0.62); setPPBloom(0.2); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/archipelago.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/archipelago.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/archipelago.js (revision 19443) @@ -1,335 +1,335 @@ RMS.LoadLibrary("rmgen"); TILE_CENTERED_HEIGHT_MAP = true; var random_terrain = randomizeBiome(); const tMainTerrain = rBiomeT1(); const tForestFloor1 = rBiomeT2(); const tForestFloor2 = rBiomeT3(); const tCliff = rBiomeT4(); const tTier1Terrain = rBiomeT5(); const tTier2Terrain = rBiomeT6(); const tTier3Terrain = rBiomeT7(); const tHill = rBiomeT8(); const tTier4Terrain = rBiomeT9(); const tRoad = rBiomeT10(); const tRoadWild = rBiomeT11(); const tTier5Terrain = rBiomeT12(); const tShoreBlend = rBiomeT13(); const tShore = rBiomeT14(); const tWater = rBiomeT15(); // gaia entities const oTree1 = rBiomeE1(); const oTree2 = rBiomeE2(); const oTree3 = rBiomeE3(); const oTree4 = rBiomeE4(); const oTree5 = rBiomeE5(); const oFruitBush = rBiomeE6(); const oMainHuntableAnimal = rBiomeE8(); const oFish = rBiomeE9(); const oSecondaryHuntableAnimal = rBiomeE10(); const oStoneLarge = rBiomeE11(); const oStoneSmall = rBiomeE12(); const oMetalLarge = rBiomeE13(); const oWood = "gaia/special_treasure_wood"; // decorative props const aGrass = rBiomeA1(); const aGrassShort = rBiomeA2(); const aReeds = rBiomeA3(); const aLillies = rBiomeA4(); const aRockLarge = rBiomeA5(); const aRockMedium = rBiomeA6(); const aBushMedium = rBiomeA7(); const aBushSmall = rBiomeA8(); const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clLand = createTileClass(); var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(22,31); var shoreRadius = 4; var elevation = 3; var hillSize = PI * radius * radius; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // create the main island var placer = new ChainPlacer(2, floor(scaleByMapSize(5, 10)), floor(scaleByMapSize(25, 60)), 1, ix, iz, 0, [floor(radius)]); var terrainPainter = new LayeredPainter( [tMainTerrain , tMainTerrain, tMainTerrain], // terrains [1, shoreRadius] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type elevation, // elevation shoreRadius // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clPlayer)], null); placeCivDefaultEntities(fx, fz, id, { 'iberWall': 'towers' }); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create woods var bbAngle = randFloat(0, TWO_PI); var bbDist = 13; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); group = new SimpleGroup( [new SimpleObject(oWood, 14,14, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = floor(hillSize / 100); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oTree1, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } log("Creating islands..."); placer = new ChainPlacer(floor(scaleByMapSize(4, 8)), floor(scaleByMapSize(8, 14)), floor(scaleByMapSize(25, 60)), 0.07, undefined, undefined, scaleByMapSize(30,70)); terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 3, 4); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clLand)], null, - scaleByMapSize(1, 5)*randInt(5,10) + scaleByMapSize(1, 5) * randIntInclusive(5, 10) ); paintTerrainBasedOnHeight(2.4, 3.4, 3, tMainTerrain); paintTerrainBasedOnHeight(1, 3, 0, tShore); paintTerrainBasedOnHeight(-8, 1, 2, tWater); //creating the city patches for the players for (var i = 0; i < numPlayers; i++) { var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // create the city patch var cityRadius = radius/3; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); } createBumps([avoidClasses(clPlayer, 10), stayClasses(clLand, 5)]); if (randBool()) createHills([tMainTerrain, tCliff, tHill], [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], clHill, scaleByMapSize(1, 4) * numPlayers); else createMountains(tCliff, [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], clHill, scaleByMapSize(1, 4) * numPlayers); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], [avoidClasses(clPlayer, 20, clForest, 17, clHill, 0), stayClasses(clLand, 4)], clForest, 1.0, random_terrain ); RMS.SetProgress(50); 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, 3, clPlayer, 12), stayClasses(clLand, 7)] ); log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tTier4Terrain, [avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 12), stayClasses(clLand, 7)] ); RMS.SetProgress(55); log("Creating stone mines..."); createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], [avoidClasses(clForest, 1, clPlayer, 7, clRock, 10, clHill, 1), stayClasses(clLand, 6)] ); log("Creating metal mines..."); createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], [avoidClasses(clForest, 1, clPlayer, 7, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 6)], clMetal ); RMS.SetProgress(65); log("Creating decoration..."); var planetm = random_terrain == g_BiomeTropic ? 8 : 1; 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [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)] ); RMS.SetProgress(70); log("Creating animals..."); createFood ( [ [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)] ], [ 3 * numPlayers, 3 * numPlayers ], [avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20), stayClasses(clLand, 3)] ); RMS.SetProgress(75); log("Creating fruits..."); createFood ( [ [new SimpleObject(oFruitBush, 5,7, 0,4)] ], [ 3 * numPlayers ], [avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 10), stayClasses(clLand, 3)] ); RMS.SetProgress(80); log("Creating fish..."); createFood ( [ [new SimpleObject(oFish, 2,3, 0,2)] ], [ 25 * numPlayers ], avoidClasses(clLand, 3, clPlayer, 2, clFood, 20) ); RMS.SetProgress(85); log("Creating straggler trees..."); var types = [oTree1, oTree2, oTree4, oTree3]; // some variation createStragglerTrees(types, [avoidClasses(clForest, 7, clHill, 1, clPlayer, 3, clMetal, 6, clRock, 6), stayClasses(clLand, 7)]); setWaterWaviness(4.0); setWaterType("ocean"); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/ardennes_forest.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ardennes_forest.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/ardennes_forest.js (revision 19443) @@ -1,628 +1,628 @@ RMS.LoadLibrary("rmgen"); log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const tGrass = ["new_alpine_grass_b", "new_alpine_grass_c", "new_alpine_grass_d"]; const tPineForestFloor = "temp_forestfloor_pine"; const tForestFloor = [tPineForestFloor, tPineForestFloor, "alpine_dirt_grass_50"]; const tCliff = ["alpine_cliff_c", "alpine_cliff_c", "alpine_grass_rocky"]; const tCity = ["new_alpine_citytile", "new_alpine_grass_dirt_a"]; const tGrassPatch = ["alpine_grass_a", "alpine_grass_b"]; const oBoar = "gaia/fauna_boar"; const oDeer = "gaia/fauna_deer"; const oBear = "gaia/fauna_bear"; const oPig = "gaia/fauna_pig"; const oBerryBush = "gaia/flora_bush_berry"; const oMetalSmall = "gaia/geology_metal_alpine"; const oMetalLarge = "gaia/geology_metal_temperate_slabs"; const oStoneSmall = "gaia/geology_stone_alpine_a"; const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; const oOak = "gaia/flora_tree_oak"; const oOakLarge = "gaia/flora_tree_oak_large"; const oPine = "gaia/flora_tree_pine"; const oAleppoPine = "gaia/flora_tree_aleppo_pine"; const aTreeA = "actor|flora/trees/oak.xml"; const aTreeB = "actor|flora/trees/oak_large.xml"; const aTreeC = "actor|flora/trees/pine.xml"; const aTreeD = "actor|flora/trees/aleppo_pine.xml"; const aTrees = [aTreeA, aTreeB, aTreeC, aTreeD]; const aGrassLarge = "actor|props/flora/grass_soft_large.xml"; const aWoodLarge = "actor|props/special/eyecandy/wood_pile_1_b.xml"; const aWoodA = "actor|props/special/eyecandy/wood_sm_pile_a.xml"; const aWoodB = "actor|props/special/eyecandy/wood_sm_pile_b.xml"; const aBarrel = "actor|props/special/eyecandy/barrel_a.xml"; const aWheel = "actor|props/special/eyecandy/wheel_laying.xml"; const aCeltHomestead = "actor|structures/celts/homestead.xml"; const aCeltHouse = "actor|structures/celts/house.xml"; const aCeltLongHouse = "actor|structures/celts/longhouse.xml"; var pForest = [ tPineForestFloor+TERRAIN_SEPARATOR+oOak, tForestFloor, tPineForestFloor+TERRAIN_SEPARATOR+oPine, tForestFloor, tPineForestFloor+TERRAIN_SEPARATOR+oAleppoPine, tForestFloor, tForestFloor ]; // create tile classes var clPlayer = createTileClass(); var clPath = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clForestJoin = createTileClass(); var clWater = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clPlayable = createTileClass(); var clHillDeco = createTileClass(); // Create central dip var centerX = fractionToTiles(0.5); var centerZ = fractionToTiles(0.5); var placer = new ClumpPlacer(scaleByMapSize(mapSize * 70, mapSize * 300), 0.94, 0.05, 0.1, centerX, centerZ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, 30, 3 ); var painter = new LayeredPainter( [tCliff, tGrass], // terrains [3] // widths ); createArea(placer, [painter, elevationPainter], null); RMS.SetProgress(5); // Find all hills var noise0 = new Noise2D(20); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var h = getHeight(ix,iz); if(h > 40){ addToClass(ix,iz,clHill); // Add hill noise var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); var n = (noise0.get(x,z) - 0.5) * 40; setHeight(ix, iz, h + n); } } } // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat() * 2 * PI; for (var i=0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*2*PI/numPlayers; playerX[i] = 0.5 + 0.3*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.3*sin(playerAngle[i]); } function distanceToPlayers(x, z) { var r = 10000; for (var i = 0; i < numPlayers; i++) { var dx = x - playerX[i]; var dz = z - playerZ[i]; r = min(r, dx*dx + dz*dz); } return sqrt(r); } function playerNearness(x, z) { var d = fractionToTiles(distanceToPlayers(x,z)); if (d < 13) { return 0; } else if (d < 19) { return (d-13)/(19-13); } else { return 1; } } RMS.SetProgress(10); for (var i=0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // create starting units placeCivDefaultEntities(fx, fz, id); var citySize = 250; var placer = new ClumpPlacer(citySize, 0.95, 0.3, 0.1, ix, iz); createArea(placer, [paintClass(clPlayer)], null); // Create the city patch var placer = new ClumpPlacer(citySize * 0.4, 0.6, 0.05, 10, ix, iz); var painter = new TerrainPainter([tCity]); createArea(placer, painter, null); // Create starter animals placeDefaultChicken(fx, fz, clBaseResource, undefined, oPig); // Create starter berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); group = new SimpleGroup( [new SimpleObject(oBerryBush, 3,3, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // Create starter metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = bbDist + 4; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // Create starter stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oOak, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } RMS.SetProgress(30); log("Creating hills..."); var sizes = [scaleByMapSize(50, 800), scaleByMapSize(50, 400), scaleByMapSize(10, 30), scaleByMapSize(10, 30)]; for (var i = 0; i < sizes.length; i++) { var placer = new ClumpPlacer(sizes[i], 0.1, 0.2, 0.1); var painter = new LayeredPainter( [tCliff, [tForestFloor, tForestFloor, tCliff]], // terrains [2] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, 50, sizes[i] < 50 ? 2 : 4 ); var mountains = createAreas( placer, [painter, paintClass(clHill), elevationPainter], avoidClasses(clPlayer, 8, clBaseResource, 2, clHill, 5), scaleByMapSize(1, 4) ); if(sizes[i] > 100 && mountains.length > 0) { var placer = new ClumpPlacer(sizes[i] * 0.3, 0.94, 0.05, 0.1); var elevationPainter = new SmoothElevationPainter( ELEVATION_MODIFY, 10, 3 ); var painter = new LayeredPainter( [tCliff, tForestFloor], // terrains [2] // widths ); createAreasInAreas( placer, [painter, elevationPainter], stayClasses(clHill, 4), mountains.length * 2, 20, mountains ); } var placer = new ClumpPlacer(sizes[i], 0.1, 0.2, 0.1); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, 10, 2 ); var ravine = createAreas( placer, [painter, paintClass(clHill), elevationPainter], avoidClasses(clPlayer, 6, clBaseResource, 2, clHill, 5), scaleByMapSize(1, 3) ); if(sizes[i] > 150 && ravine.length > 0) { // Place huts in ravines var group = new RandomGroup( [ new SimpleObject(aCeltHouse, 0,1, 4,5), new SimpleObject(aCeltLongHouse, 1,1, 4,5) ], true, clHillDeco); createObjectGroupsByAreas( group, 0, [avoidClasses(clHillDeco, 3), stayClasses(clHill, 3)], ravine.length * 5, 20, ravine ); var group = new RandomGroup( [ new SimpleObject(aCeltHomestead, 1,1, 1,1) ], true, clHillDeco); createObjectGroupsByAreas( group, 0, [avoidClasses(clHillDeco, 5), stayClasses(clHill, 4)], ravine.length * 2, 100, ravine ); // Place noise var placer = new ClumpPlacer(sizes[i] * 0.3, 0.94, 0.05, 0.1); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, 2, 2 ); var painter = new LayeredPainter( [tCliff, tForestFloor], // terrains [2] // widths ); createAreasInAreas( placer, [painter, elevationPainter], [avoidClasses(clHillDeco, 2), stayClasses(clHill, 0)], ravine.length * 2, 20, ravine ); var placer = new ClumpPlacer(sizes[i] * 0.1, 0.3, 0.05, 0.1); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, 40, 2 ); var painter = new LayeredPainter( [tCliff, tForestFloor], // terrains [2] // widths ); createAreasInAreas( placer, [painter, paintClass(clHill), elevationPainter], [avoidClasses(clHillDeco, 2), borderClasses(clHill, 15, 1)], ravine.length * 2, 50, ravine ); } RMS.SetProgress(30 + (20 * (i / sizes.length))); } RMS.SetProgress(50); var explorableArea = {}; explorableArea.points = []; var playerClass = getTileClass(clPlayer); var hillDecoClass = getTileClass(clHillDeco); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var h = getHeight(ix,iz); if(h > 15 && h < 45 && playerClass.countMembersInRadius(ix, iz, 1) == 0) { // explorable area var pt = {}; pt.x = ix; pt.z = iz; explorableArea.points.push(pt); } if (h > 35 && g_Map.validT(ix, iz) && randBool(0.1) || h < 15 && g_Map.validT(ix, iz) && randBool(0.05) && hillDecoClass.countMembersInRadius(ix, iz, 1) == 0) placeObject(ix + randFloat(0, 1), iz + randFloat(0, 1), pickRandom(aTrees), 0, randFloat(0, 2 * PI)); } } RMS.SetProgress(55); // Add some general noise - after placing height dependant trees for (var ix = 0; ix < mapSize; ix++) { var x = ix / (mapSize + 1.0); for (var iz = 0; iz < mapSize; iz++) { var z = iz / (mapSize + 1.0); var h = getHeight(ix,iz); var pn = playerNearness(x,z); var n = (noise0.get(x,z) - 0.5) * 10; setHeight(ix, iz, h + (n * pn)); } } RMS.SetProgress(60); // Calculate desired number of trees for map (based on size) const MIN_TREES = 400; const MAX_TREES = 6000; const P_FOREST = 0.8; const P_FOREST_JOIN = 0.25; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST * (1.0 - P_FOREST_JOIN); var numForestJoin = totalTrees * P_FOREST * P_FOREST_JOIN; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var num = numForest / (scaleByMapSize(6,16) * numPlayers); placer = new ClumpPlacer(numForest / num, 0.1, 0.1, 1); painter = new TerrainPainter(pForest); createAreasInAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 5, clBaseResource, 4, clForest, 6, clHill, 4), num, 100, [explorableArea] ); var num = numForestJoin / (scaleByMapSize(4,6) * numPlayers); placer = new ClumpPlacer(numForestJoin / num, 0.1, 0.1, 1); painter = new TerrainPainter(pForest); createAreasInAreas( placer, [painter, paintClass(clForest), paintClass(clForestJoin)], [avoidClasses(clPlayer, 5, clBaseResource, 4, clForestJoin, 5, clHill, 4), borderClasses(clForest, 1, 4)], num, 100, [explorableArea] ); RMS.SetProgress(70); // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter( [[tGrass,tGrassPatch],[tGrassPatch,tGrass], [tGrass,tGrassPatch]], // terrains [1,1] // widths ); createAreas( placer, painter, avoidClasses(clForest, 0, clHill, 2, clPlayer, 5), scaleByMapSize(15, 45) ); } // create chopped forest patches log("Creating chopped forest patches..."); var sizes = [scaleByMapSize(20, 120)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new TerrainPainter(tForestFloor); createAreas( placer, painter, avoidClasses(clForest, 1, clHill, 2, clPlayer, 5), scaleByMapSize(4, 12) ); } RMS.SetProgress(75); log("Creating stone mines..."); // create stone quarries var group = new SimpleGroup([new SimpleObject(oStoneSmall, 1,2, 0,4), new SimpleObject(oStoneLarge, 0,1, 0,4)], true, clRock); createObjectGroupsByAreas(group, 0, [avoidClasses(clHill, 4, clForest, 2, clPlayer, 20, clRock, 10)], scaleByMapSize(6,20), 100, [explorableArea] ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroupsByAreas(group, 0, [avoidClasses(clHill, 4, clForest, 2, clPlayer, 20, clRock, 10)], scaleByMapSize(6,20), 100, [explorableArea] ); log("Creating metal mines..."); // create metal quarries group = new SimpleGroup([new SimpleObject(oMetalSmall, 1,2, 0,4), new SimpleObject(oMetalLarge, 0,1, 0,4)], true, clMetal); createObjectGroupsByAreas(group, 0, [avoidClasses(clHill, 4, clForest, 2, clPlayer, 20, clMetal, 10, clRock, 5)], scaleByMapSize(6,20), 100, [explorableArea] ); RMS.SetProgress(80); // create wildlife log("Creating wildlife..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroupsByAreas(group, 0, avoidClasses(clHill, 2, clForest, 0, clPlayer, 0, clBaseResource, 20), 3 * numPlayers, 100, [explorableArea] ); group = new SimpleGroup( [new SimpleObject(oBoar, 2,3, 0,5)], true, clFood ); createObjectGroupsByAreas(group, 0, avoidClasses(clHill, 2, clForest, 0, clPlayer, 0, clBaseResource, 15), numPlayers, 50, [explorableArea] ); group = new SimpleGroup( [new SimpleObject(oBear, 1,1, 0,4)], false, clFood ); createObjectGroupsByAreas(group, 0, avoidClasses(clHill, 2, clForest, 0, clPlayer, 20), scaleByMapSize(3, 12), 200, [explorableArea] ); RMS.SetProgress(85); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - randInt(3, 12) * numPlayers + 2, 50 + randIntInclusive(3, 12) * numPlayers + 2, 50 ); log("Creating decorative props..."); group = new SimpleGroup( [ new SimpleObject(aWoodA, 1,2, 0,1), new SimpleObject(aWoodB, 1,3, 0,1), new SimpleObject(aWheel, 0,2, 0,1), new SimpleObject(aWoodLarge, 0,1, 0,1), new SimpleObject(aBarrel, 0,2, 0,1) ], true ); createObjectGroupsByAreas( group, 0, avoidClasses(clForest, 0), scaleByMapSize(5, 50), 50, [explorableArea] ); RMS.SetProgress(90); // create straggler trees log("Creating straggler trees..."); var types = [oOak, oOakLarge, oPine, oAleppoPine]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroupsByAreas(group, 0, avoidClasses(clForest, 4, clHill, 5, clPlayer, 10, clBaseResource, 2, clMetal, 5, clRock, 5), num, 20, [explorableArea] ); } RMS.SetProgress(95); // create grass tufts log("Creating grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassLarge, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroupsByAreas(group, 0, avoidClasses(clHill, 2, clPlayer, 2), scaleByMapSize(50, 300), 20, [explorableArea] ); setTerrainAmbientColor(0.44,0.51,0.56); setUnitsAmbientColor(0.44,0.51,0.56); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/atlas_mountains.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/atlas_mountains.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/atlas_mountains.js (revision 19443) @@ -1,334 +1,334 @@ RMS.LoadLibrary("rmgen"); // terrain textures const tGrass = ["medit_rocks_grass_shrubs", "medit_rocks_shrubs"]; const tForestFloor = "medit_grass_field_dry"; const tCliff = "medit_cliff_italia"; const tHill = ["medit_rocks_grass", "medit_rocks_grass_shrubs", "medit_rocks_shrubs"]; const tGrassDirt = "medit_rocks_grass"; const tDirt = "medit_dirt"; const tRoad = "medit_city_tile"; const tRoadWild = "medit_city_tile"; const tGrass2 = "medit_rocks_grass_shrubs"; const tGrassPatch = "medit_grass_wild"; const tShoreBlend = "medit_sand"; const tShore = "medit_sand"; const tWater = "medit_sand"; // gaia entities const oCarob = "gaia/flora_tree_carob"; const oAleppoPine = "gaia/flora_tree_aleppo_pine"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oSheep = "gaia/fauna_sheep"; const oStoneLarge = "gaia/geology_stonemine_medit_quarry"; const oStoneSmall = "gaia/geology_stone_mediterranean"; const oMetalLarge = "gaia/geology_metal_mediterranean_slabs"; const oWood = "gaia/special_treasure_wood"; const oFood = "gaia/special_treasure_food_bin"; // decorative props 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.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const aCarob = "actor|flora/trees/carob.xml"; const aAleppoPine = "actor|flora/trees/aleppo_pine.xml"; // terrain + entity (for painting) const pForest1 = [tForestFloor + TERRAIN_SEPARATOR + oCarob, tForestFloor]; const pForest2 = [tForestFloor + TERRAIN_SEPARATOR + oAleppoPine, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clTreasure = createTileClass(); var clGrass = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 4; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oCarob, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(10); // create bumps createBumps(avoidClasses(clPlayer, 9)); createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 8), clHill, scaleByMapSize(20, 120)); RMS.SetProgress(25); // create forests createForests( [tGrass, tForestFloor, tForestFloor, pForest1, pForest2], avoidClasses(clPlayer, 20, clForest, 14, clHill, 1), clForest, 0.6, 0 ); RMS.SetProgress(40); // create dirt patches log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [tGrassDirt,tDirt], [2], avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 10) ); // create grass patches log("Creating grass patches..."); createLayeredPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], [tGrass2,tGrassPatch], [1], avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 10, clGrass, 15) ); RMS.SetProgress(50); log("Creating stone mines..."); // create stone quarries createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2) ); log("Creating metal mines..."); // create large metal quarries createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), clMetal ); RMS.SetProgress(60); // create decoration 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), scaleByMapSize(13, 200), scaleByMapSize(13, 200), scaleByMapSize(13, 200) ], avoidClasses(clForest, 0, clPlayer, 0, clHill, 0) ); RMS.SetProgress(75); // create animals createFood ( [ [new SimpleObject(oSheep, 5,7, 0,4)], [new SimpleObject(oDeer, 2,3, 0,2)] ], [ 3 * numPlayers, 3 * numPlayers ] ); // create fruits createFood ( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(3, 12) * numPlayers + 2 + randIntInclusive(3, 12) * numPlayers + 2 ], avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10) ); // create food treasures log("Creating food treasures..."); group = new SimpleGroup( [new SimpleObject(oFood, 2,3, 0,2)], true, clTreasure ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 18, clHill, 1, clFood, 5), 3 * numPlayers, 50 ); // create wood treasures log("Creating food treasures..."); group = new SimpleGroup( [new SimpleObject(oWood, 2,3, 0,2)], true, clTreasure ); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 18, clHill, 1), 3 * numPlayers, 50 ); RMS.SetProgress(80); // create straggler trees var types = [oCarob, oAleppoPine]; // some variation createStragglerTrees(types, avoidClasses(clForest, 1, clHill, 1, clPlayer, 10, clMetal, 6, clRock, 6, clTreasure, 4)); // create hill trees log("Creating hill trees..."); var types = [aCarob, aAleppoPine]; // some variation var num = floor(0.2 * g_numStragglerTrees / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, stayClasses(clHill, 2), num ); } setFogFactor(0.2); setFogThickness(0.14); setPPEffect("hdr"); setPPContrast(0.45); setPPSaturation(0.56); setPPBloom(0.1); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/belgian_uplands.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/belgian_uplands.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/belgian_uplands.js (revision 19443) @@ -1,456 +1,456 @@ // Prepare progress calculation var timeArray = []; timeArray.push(new Date().getTime()); // Importing rmgen libraries RMS.LoadLibrary("rmgen"); RMS.LoadLibrary("heightmap"); log("Initializing map..."); InitMap(); var numPlayers = getNumPlayers(); var mapSize = getMapSize(); // Function to apply a heightmap function setReliefmap(reliefmap) { // g_Map.height = reliefmap; for (var x = 0; x <= mapSize; x++) for (var y = 0; y <= mapSize; y++) setHeight(x, y, reliefmap[x][y]); } // Set target min and max height depending on map size to make average stepness the same on all map sizes var heightRange = {"min": MIN_HEIGHT * mapSize / 8192, "max": MAX_HEIGHT * mapSize / 8192}; // Set average water coverage var averageWaterCoverage = 1/3; // NOTE: Since errosion is not predictable actual water coverage might differ much with the same value if (mapSize < 200) // Sink the waterlevel on tiny maps to ensure enough space averageWaterCoverage = 2/3 * averageWaterCoverage; var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); var waterHeightAdjusted = waterHeight + MIN_HEIGHT; setWaterHeight(waterHeight); ////////// // Prepare terrain texture by height placement ////////// var textueByHeight = []; // Deep water textueByHeight.push({"upperHeightLimit": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_sea_rocks"}); // Medium deep water (with fish) var terrains = ["temp_sea_weed"]; terrains = terrains.concat(terrains, terrains, terrains, terrains); terrains = terrains.concat(terrains, terrains, terrains, terrains); terrains.push("temp_sea_weed|gaia/fauna_fish"); textueByHeight.push({"upperHeightLimit": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "terrain": terrains}); // Flat Water textueByHeight.push({"upperHeightLimit": heightRange.min + 3/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_mud_a"}); // Water surroundings/bog (with stone/metal some rabits and bushes) var terrains = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"]; terrains = terrains.concat(terrains, terrains, terrains, terrains, terrains); terrains = ["temp_plants_bog|gaia/flora_bush_temperate"].concat(terrains, terrains); terrains = ["temp_dirt_gravel_plants|gaia/geology_metal_temperate", "temp_dirt_gravel_plants|gaia/geology_stone_temperate", "temp_plants_bog|gaia/fauna_rabbit"].concat(terrains, terrains); terrains = ["temp_plants_bog_aut|gaia/flora_tree_dead"].concat(terrains, terrains); textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 1/6 * (heightRange.max - waterHeightAdjusted), "terrain": terrains}); // Juicy grass near bog textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 2/6 * (heightRange.max - waterHeightAdjusted), "terrain": ["temp_grass", "temp_grass_d", "temp_grass_long_b", "temp_grass_plants"]}); // Medium level grass // var testActor = "actor|geology/decal_stone_medit_a.xml"; textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 3/6 * (heightRange.max - waterHeightAdjusted), "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_mossy"]}); // Long grass near forest border textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 4/6 * (heightRange.max - waterHeightAdjusted), "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]}); // Forest border (With wood/food plants/deer/rabits) var terrains = ["temp_grass_plants|gaia/flora_tree_euro_beech", "temp_grass_mossy|gaia/flora_tree_poplar", "temp_grass_mossy|gaia/flora_tree_poplar_lombardy", "temp_grass_long|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_badlands", "temp_grass_long|gaia/flora_tree_apple", "temp_grass_clovers|gaia/flora_bush_berry", "temp_grass_clovers_2|gaia/flora_bush_grapes", "temp_grass_plants|gaia/fauna_deer", "temp_grass_long_b|gaia/fauna_rabbit"]; var numTerrains = terrains.length; for (var i = 0; i < numTerrains; i++) terrains.push("temp_grass_plants"); textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 5/6 * (heightRange.max - waterHeightAdjusted), "terrain": terrains}); // Unpassable woods textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 6/6 * (heightRange.max - waterHeightAdjusted), "terrain": ["temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine", "temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine", "temp_mud_plants|gaia/flora_tree_dead", "temp_plants_bog|gaia/flora_tree_oak_large", "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", "temp_forestfloor_autumn|gaia/flora_tree_carob"]}); var minTerrainDistToBorder = 3; // Time check 1 timeArray.push(new Date().getTime()); RMS.SetProgress(5); // START THE GIANT WHILE LOOP: // - Generate Heightmap // - Search valid start position tiles // - Choose a good start position derivation (largest distance between closest players) // - Restart the loop if start positions are invalid or two players are to close to each other var goodStartPositionsFound = false; var minDistBetweenPlayers = 16 + mapSize / 16; // Don't set this higher than 25 for tiny maps! It will take forever with 8 players! var enoughTiles = false; var tries = 0; while (!goodStartPositionsFound) { tries++; log("Starting giant while loop try " + tries); // Generate reliefmap var myReliefmap = deepcopy(g_Map.height); setRandomHeightmap(heightRange.min, heightRange.max, myReliefmap); for (var i = 0; i < 50 + mapSize/4; i++) // Cycles depend on mapsize (more cycles -> bigger structures) globalSmoothHeightmap(0.8, myReliefmap); rescaleHeightmap(heightRange.min, heightRange.max, myReliefmap); setReliefmap(myReliefmap); // Find good start position tiles var startPositions = []; var possibleStartPositions = []; var neededDistance = 7; var distToBorder = 2 * neededDistance; // Has to be greater than neededDistance! Otherwise the check if low/high ground is near will fail... var lowerHeightLimit = textueByHeight[3].upperHeightLimit; var upperHeightLimit = textueByHeight[6].upperHeightLimit; // Check for valid points by height for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; x++) for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; y++) { var actualHeight = getHeight(x, y); if (actualHeight > lowerHeightLimit && actualHeight < upperHeightLimit) { // Check for points within a valid area by height (rectangular since faster) var isPossible = true; for (var offX = - neededDistance; offX <= neededDistance; offX++) for (var offY = - neededDistance; offY <= neededDistance; offY++) { var testHeight = getHeight(x + offX, y + offY); if (testHeight <= lowerHeightLimit || testHeight >= upperHeightLimit) { isPossible = false; break; } } if (isPossible) possibleStartPositions.push([x, y]); // placeTerrain(x, y, "blue"); // For debug reasons. Plz don't remove. // Only works properly for 1 loop } } // Trying to reduce the number of possible start locations... // Reduce to tiles in a circle of mapSize / 2 distance to the center (to avoid players placed in corners) var possibleStartPositionsTemp = []; var maxDistToCenter = mapSize / 2; for (var i = 0; i < possibleStartPositions.length; i++) { var deltaX = possibleStartPositions[i][0] - mapSize / 2; var deltaY = possibleStartPositions[i][1] - mapSize / 2; var distToCenter = Math.pow(Math.pow(deltaX, 2) + Math.pow(deltaY, 2), 1/2); if (distToCenter < maxDistToCenter) possibleStartPositionsTemp.push(possibleStartPositions[i]); // placeTerrain(possibleStartPositions[i][0], possibleStartPositions[i][1], "purple"); // Only works properly for 1 loop } possibleStartPositions = deepcopy(possibleStartPositionsTemp); // Reduce to tiles near low and high ground (Rectangular check since faster) to make sure each player has access to all resource types. var possibleStartPositionsTemp = []; var maxDistToResources = distToBorder; // Has to be <= distToBorder! var minNumLowTiles = 10; var minNumHighTiles = 10; for (var i = 0; i < possibleStartPositions.length; i++) { var numLowTiles = 0; var numHighTiles = 0; for (var dx = - maxDistToResources; dx < maxDistToResources; dx++) { for (var dy = - maxDistToResources; dy < maxDistToResources; dy++) { var testHeight = getHeight(possibleStartPositions[i][0] + dx, possibleStartPositions[i][1] + dy); if (testHeight < lowerHeightLimit) numLowTiles++; if (testHeight > upperHeightLimit) numHighTiles++; if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles) break; } if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles) break; } if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles) possibleStartPositionsTemp.push(possibleStartPositions[i]); // placeTerrain(possibleStartPositions[i][0], possibleStartPositions[i][1], "red"); // Only works properly for 1 loop } possibleStartPositions = deepcopy(possibleStartPositionsTemp); if(possibleStartPositions.length > numPlayers) enoughTiles = true; else { enoughTiles = false; log("possibleStartPositions.length < numPlayers, possibleStartPositions.length = " + possibleStartPositions.length + ", numPlayers = " + numPlayers); } // Find a good start position derivation if (enoughTiles) { // Get some random start location derivations. NOTE: Itterating over all possible derivations is just to much (valid points ** numPlayers) var maxTries = 100000; // floor(800000 / (Math.pow(numPlayers, 2) / 2)); var possibleDerivations = []; for (var i = 0; i < maxTries; i++) { var vector = []; for (var p = 0; p < numPlayers; p++) - vector.push(randInt(possibleStartPositions.length)); + vector.push(randIntExclusive(0, possibleStartPositions.length)); possibleDerivations.push(vector); } // Choose the start location derivation with the greatest minimum distance between players var maxMinDist = 0; for (var d = 0; d < possibleDerivations.length; d++) { var minDist = 2 * mapSize; for (var p1 = 0; p1 < numPlayers - 1; p1++) { for (var p2 = p1 + 1; p2 < numPlayers; p2++) { if (p1 != p2) { var StartPositionP1 = possibleStartPositions[possibleDerivations[d][p1]]; var StartPositionP2 = possibleStartPositions[possibleDerivations[d][p2]]; var actualDist = Math.pow(Math.pow(StartPositionP1[0] - StartPositionP2[0], 2) + Math.pow(StartPositionP1[1] - StartPositionP2[1], 2), 1/2); if (actualDist < minDist) minDist = actualDist; if (minDist < maxMinDist) break; } } if (minDist < maxMinDist) break; } if (minDist > maxMinDist) { maxMinDist = minDist; var bestDerivation = possibleDerivations[d]; } } if (maxMinDist > minDistBetweenPlayers) { goodStartPositionsFound = true; log("Exiting giant while loop after " + tries + " tries with a minimum player distance of " + maxMinDist); } else log("maxMinDist <= " + minDistBetweenPlayers + ", maxMinDist = " + maxMinDist); } // End of derivation check } // END THE GIANT WHILE LOOP // Time check 2 timeArray.push(new Date().getTime()); RMS.SetProgress(60); //////// // Paint terrain by height and add props //////// var propDensity = 1; // 1 means as determined in the loop, less for large maps as set below if (mapSize > 500) propDensity = 1/4; else if (mapSize > 400) propDensity = 3/4; for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++) { for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; y++) { var textureMinHeight = heightRange.min; for (var i = 0; i < textueByHeight.length; i++) { if (getHeight(x, y) >= textureMinHeight && getHeight(x, y) <= textueByHeight[i].upperHeightLimit) { placeTerrain(x, y, textueByHeight[i].terrain); // Add some props at... if (i == 0) // ...deep water { if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/pond_lillies_large.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|props/flora/water_lillies.xml", 0, randFloat(0, 2*PI)); } if (i == 1) // ...medium water (with fish) { if (randBool(propDensity / 200)) placeObject(x, y, "actor|props/flora/pond_lillies_large.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/water_lillies.xml", 0, randFloat(0, 2*PI)); } if (i == 2) // ...low water/mud { if (randBool(propDensity / 200)) placeObject(x, y, "actor|props/flora/water_log.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/water_lillies.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|geology/highland_c.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 20)) placeObject(x, y, "actor|props/flora/reeds_pond_lush_b.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 10)) placeObject(x, y, "actor|props/flora/reeds_pond_lush_a.xml", 0, randFloat(0, 2*PI)); } if (i == 3) // ...water suroundings/bog { if (randBool(propDensity / 200)) placeObject(x, y, "actor|props/flora/water_log.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|geology/highland_c.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|props/flora/reeds_pond_lush_a.xml", 0, randFloat(0, 2*PI)); } if (i == 4) // ...low height grass { if (randBool(propDensity / 800)) placeObject(x, y, "actor|props/flora/grass_field_flowering_tall.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 400)) placeObject(x, y, "actor|geology/gray_rock1.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 200)) placeObject(x, y, "actor|props/flora/bush_tempe_sm_lush.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/bush_tempe_b.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|props/flora/grass_soft_small_tall.xml", 0, randFloat(0, 2*PI)); } if (i == 5) // ...medium height grass { if (randBool(propDensity / 800)) placeObject(x, y, "actor|geology/decal_stone_medit_a.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 400)) placeObject(x, y, "actor|props/flora/decals_flowers_daisies.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 200)) placeObject(x, y, "actor|props/flora/bush_tempe_underbrush.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/grass_soft_small_tall.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|props/flora/grass_temp_field.xml", 0, randFloat(0, 2*PI)); } if (i == 6) // ...high height grass { if (randBool(propDensity / 400)) placeObject(x, y, "actor|geology/stone_granite_boulder.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 200)) placeObject(x, y, "actor|props/flora/foliagebush.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/bush_tempe_underbrush.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|props/flora/grass_soft_small_tall.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 20)) placeObject(x, y, "actor|props/flora/ferns.xml", 0, randFloat(0, 2*PI)); } if (i == 7) // ...forest border (with wood/food plants/deer/rabits) { if (randBool(propDensity / 400)) placeObject(x, y, "actor|geology/highland_c.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 200)) placeObject(x, y, "actor|props/flora/bush_tempe_a.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/ferns.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|props/flora/grass_soft_tuft_a.xml", 0, randFloat(0, 2*PI)); } if (i == 8) // ...woods { if (randBool(propDensity / 200)) placeObject(x, y, "actor|geology/highland2_moss.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 100)) placeObject(x, y, "actor|props/flora/grass_soft_tuft_a.xml", 0, randFloat(0, 2*PI)); else if (randBool(propDensity / 40)) placeObject(x, y, "actor|props/flora/ferns.xml", 0, randFloat(0, 2*PI)); } break; } else textureMinHeight = textueByHeight[i].upperHeightLimit; } } } // Time check 3 timeArray.push(new Date().getTime()); RMS.SetProgress(90); //////// // Place players and start resources //////// for (var p = 0; p < numPlayers; p++) { var actualX = possibleStartPositions[bestDerivation[p]][0]; var actualY = possibleStartPositions[bestDerivation[p]][1]; placeCivDefaultEntities(actualX, actualY, p + 1, { "iberWall": false }); // Place some start resources var uDist = 8; var uSpace = 1; for (var j = 1; j <= 4; ++j) { var uAngle = BUILDING_ORIENTATION - PI * (2-j) / 2; var count = 4; for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = actualX + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = actualY + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); if (j % 2 == 0) placeObject(ux, uz, "gaia/flora_bush_berry", 0, randFloat(0, 2*PI)); else placeObject(ux, uz, "gaia/flora_tree_cypress", 0, randFloat(0, 2*PI)); } } } // Export map data ExportMap(); // Time check 7 timeArray.push(new Date().getTime()); // Calculate progress percentage with the time checks var generationTime = timeArray[timeArray.length - 1] - timeArray[0]; log("Total generation time (ms): " + generationTime); for (var i = 0; i < timeArray.length; i++) { var timeSinceStart = timeArray[i] - timeArray[0]; var progressPercentage = 100 * timeSinceStart / generationTime; log("Time check " + i + ": Progress (%): " + progressPercentage); } Index: ps/trunk/binaries/data/mods/public/maps/random/caledonian_meadows.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/caledonian_meadows.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/caledonian_meadows.js (revision 19443) @@ -1,778 +1,778 @@ RMS.LoadLibrary("rmgen"); RMS.LoadLibrary("heightmap"); InitMap(); /** * Start Timer */ let genStartTime = new Date().getTime(); /** * Returns an approximation of the heights of the tiles between the vertices, a tile centered heightmap * A tile centered heightmap is one smaller in width and height than an ordinary heightmap * It is meant to e.g. texture a map by height (x/y coordinates correspond to those of the terrain texture map) * Don't use this to override g_Map height (Potentially breaks the map)! * @param {array} [heightmap=g_Map.height] - A reliefmap the tile centered version should be build from */ function getTileCenteredHeightmap(heightmap = g_Map.height) { let max_x = heightmap.length - 1; let max_y = heightmap[0].length - 1; let tchm = []; for (let x = 0; x < max_x; ++x) { tchm[x] = new Float32Array(max_y); for (let y = 0; y < max_y; ++y) tchm[x][y] = 0.25 * (heightmap[x][y] + heightmap[x + 1][y] + heightmap[x][y + 1] + heightmap[x + 1][y + 1]); } return tchm; } /** * Returns an inclination map corresponding to the tiles between the heightmaps vertices: * array of heightmap width-1 arrays of height-1 vectors (associative arrays) of the from: * {"x": x_slope, "y": y_slope] so a 2D Vector pointing to the hightest incline (with the length the incline in the vectors direction) * The x and y coordinates of a tile in the terrain texture map correspond to those of the inclination map * @param {array} [heightmap=g_Map.height] - The reliefmap the inclination map is to be generated from */ function getInclineMap(heightmap) { heightmap = (heightmap || g_Map.height); let max_x = heightmap.length - 1; let max_y = heightmap[0].length - 1; let inclineMap = []; for (let x = 0; x < max_x; ++x) { inclineMap[x] = []; for (let y = 0; y < max_y; ++y) { let dx = heightmap[x + 1][y] - heightmap[x][y]; let dy = heightmap[x][y + 1] - heightmap[x][y]; let next_dx = heightmap[x + 1][y + 1] - heightmap[x][y + 1]; let next_dy = heightmap[x + 1][y + 1] - heightmap[x + 1][y]; inclineMap[x][y] = {"x": 0.5 * (dx + next_dx), "y": 0.5 * (dy + next_dy)}; } } return inclineMap; } /** * Returns a slope map (same form as the a heightmap with one less width and height) * Not normalized. Only returns the steepness (float), not the direction of incline. * The x and y coordinates of a tile in the terrain texture map correspond to those of the slope map * @param {array} [inclineMap=getInclineMap(g_Map.height)] - A map with the absolute inclination for each tile */ function getSlopeMap(inclineMap = getInclineMap(g_Map.height)) { let max_x = inclineMap.length; let slopeMap = []; for (let x = 0; x < max_x; ++x) { let max_y = inclineMap[x].length; slopeMap[x] = new Float32Array(max_y); for (let y = 0; y < max_y; ++y) slopeMap[x][y] = Math.pow(inclineMap[x][y].x * inclineMap[x][y].x + inclineMap[x][y].y * inclineMap[x][y].y, 0.5); } return slopeMap; } /** * Returns the order to go through the points for the shortest closed path (array of indices) * @param {array} [points] - Points to be sorted of the form {"x": x_value, "y": y_value} */ function getOrderOfPointsForShortestClosePath(points) { let order = []; let distances = []; if (points.length <= 3) { for (let i = 0; i < points.length; ++i) order.push(i); return order; } // Just add the first 3 points let pointsToAdd = deepcopy(points); for (let i = 0; i < 3; ++i) { order.push(i); pointsToAdd.shift(i); if (i) distances.push(getDistance(points[order[i]].x, points[order[i]].y, points[order[i - 1]].x, points[order[i - 1]].y)); } distances.push(getDistance( points[order[0]].x, points[order[0]].y, points[order[order.length - 1]].x, points[order[order.length - 1]].y)); // Add remaining points so the path lengthens the least let numPointsToAdd = pointsToAdd.length; for (let i = 0; i < numPointsToAdd; ++i) { let indexToAddTo = undefined; let minEnlengthen = Infinity; let minDist1 = 0; let minDist2 = 0; for (let k = 0; k < order.length; ++k) { let dist1 = getDistance(pointsToAdd[0].x, pointsToAdd[0].y, points[order[k]].x, points[order[k]].y); let dist2 = getDistance(pointsToAdd[0].x, pointsToAdd[0].y, points[order[(k + 1) % order.length]].x, points[order[(k + 1) % order.length]].y); let enlengthen = dist1 + dist2 - distances[k]; if (enlengthen < minEnlengthen) { indexToAddTo = k; minEnlengthen = enlengthen; minDist1 = dist1; minDist2 = dist2; } } order.splice(indexToAddTo + 1, 0, i + 3); distances.splice(indexToAddTo, 1, minDist1, minDist2); pointsToAdd.shift(); } return order; } /** * Drags a path to a target height smoothing it at the edges and return some points along the path. */ function placeRandomPathToHeight( start, target, targetHeight, tileClass = undefined, texture = "road_rome_a", width = 10, distance = 4, strength = 0.08, heightmap = g_Map.height) { let pathPoints = []; let position = deepcopy(start); while (true) { rectangularSmoothToHeight(position, width, width, targetHeight, strength, heightmap); if (texture) { if (tileClass !== undefined) createArea(new ClumpPlacer(0.3 * width * width, 1, 1, 1, floor(position.x), floor(position.y)), [new TerrainPainter(texture), paintClass(tileClass)]); else createArea(new ClumpPlacer(0.3 * width * width, 1, 1, 1, floor(position.x), floor(position.y)), new TerrainPainter(texture)); } pathPoints.push({ "x": position.x, "y": position.y, "dist": distance }); // Check for distance to target and setup for next loop if needed if (getDistance(position.x, position.y, target.x, target.y) < distance / 2) break; let angleToTarget = getAngle(position.x, position.y, target.x, target.y); let angleOff = PI * (randFloat() - 0.5); position.x += distance * cos(angleToTarget + angleOff); position.y += distance * sin(angleToTarget + angleOff); } return pathPoints; } function getGrad(wrapped = true, scalarField = g_Map.height) { let vectorField = []; let max_x = scalarField.length; let max_y = scalarField[0].length; if (!wrapped) { max_x -= 1; max_y -= 1; } for (let x = 0; x < max_x; ++x) { vectorField.push([]); for (let y = 0; y < max_y; ++y) vectorField[x].push({"x": scalarField[(x + 1) % max_x][y] - scalarField[x][y], "y": scalarField[x][(y + 1) % max_y] - scalarField[x][y]}); } return vectorField; } function splashErodeMap(strength = 1, heightmap = g_Map.height) { let max_x = heightmap.length; let max_y = heightmap[0].length; let dHeight = getGrad(heightmap); for (let x = 0; x < max_x; ++x) { let next_x = (x + 1) % max_x; let prev_x = (x + max_x - 1) % max_x; for (let y = 0; y < max_y; ++y) { let next_y = (y + 1) % max_y; let prev_y = (y + max_y - 1) % max_y; let slopes = [- dHeight[x][y].x, - dHeight[x][y].y, dHeight[prev_x][y].x, dHeight[x][prev_y].y]; let sumSlopes = 0; for (let i = 0; i < slopes.length; ++i) if (slopes[i] > 0) sumSlopes += slopes[i]; let drain = []; for (let i = 0; i < slopes.length; ++i) { drain.push(0); if (slopes[i] > 0) drain[i] += min(strength * slopes[i] / sumSlopes, slopes[i]); } let sumDrain = 0; for (let i = 0; i < drain.length; ++i) sumDrain += drain[i]; // Apply changes to maps heightmap[x][y] -= sumDrain; heightmap[next_x][y] += drain[0]; heightmap[x][next_y] += drain[1]; heightmap[prev_x][y] += drain[2]; heightmap[x][prev_y] += drain[3]; } } } /** * Meant to place e.g. resource spots within a height range * @param {array} [heightRange] - The height range in which to place the entities (An associative array with keys "min" and "max" each containing a float) * @param {array} [avoidPoints=[]] - An array of objects of the form {"x": int, "y": int, "dist": int}, points that will be avoided in the given dist e.g. start locations * @param {object} [avoidClass=undefined] - TileClass to be avoided * @param {integer} [minDistance=30] - How many tile widths the entities to place have to be away from each other, start locations and the map border * @param {array} [heightmap=g_Map.height] - The reliefmap the entities should be distributed on * @param {integer} [maxTries=2 * g_Map.size] - How often random player distributions are rolled to be compared (256 to 1024) * @param {boolean} [isCircular=g_MapSettings.CircularMap] - If the map is circular or rectangular */ function getPointsByHeight(heightRange, avoidPoints = [], avoidClass = undefined, minDistance = 20, maxTries = 2 * g_Map.size, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap) { let points = []; let placements = deepcopy(avoidPoints); let validVertices = []; let r = 0.5 * (heightmap.length - 1); // Map center x/y as well as radius let avoidMap; if (avoidClass !== undefined) avoidMap = g_Map.tileClasses[avoidClass].inclusionCount; for (let x = minDistance; x < heightmap.length - minDistance; ++x) { for (let y = minDistance; y < heightmap[0].length - minDistance; ++y) { if (avoidClass !== undefined && // Avoid adjecting tiles in avoidClass (avoidMap[max(x - 1, 0)][y] > 0 || avoidMap[x][max(y - 1, 0)] > 0 || avoidMap[min(x + 1, avoidMap.length - 1)][y] > 0 || avoidMap[x][min(y + 1, avoidMap[0].length - 1)] > 0)) continue; if (heightmap[x][y] > heightRange.min && heightmap[x][y] < heightRange.max && // Has correct height (!isCircular || r - getDistance(x, y, r, r) >= minDistance)) // Enough distance to map border validVertices.push({ "x": x, "y": y , "dist": minDistance}); } } for (let tries = 0; tries < maxTries; ++tries) { let point = pickRandom(validVertices); if (placements.every(p => getDistance(p.x, p.y, point.x, point.y) > max(minDistance, p.dist))) { points.push(point); placements.push(point); } if (tries != 0 && tries % 100 == 0) // Time Check log(points.length + " points found after " + tries + " tries after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); } return points; } /** * Design resource spots */ // Mines let decorations = [ "actor|geology/gray1.xml", "actor|geology/gray_rock1.xml", "actor|geology/highland1.xml", "actor|geology/highland2.xml", "actor|geology/highland3.xml", "actor|geology/highland_c.xml", "actor|geology/highland_d.xml", "actor|geology/highland_e.xml", "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml" ]; function placeMine(point, centerEntity) { placeObject(point.x, point.y, centerEntity, 0, randFloat(0, TWO_PI)); - let quantity = randInt(11, 23); + let quantity = randIntInclusive(11, 23); let dAngle = TWO_PI / quantity; for (let i = 0; i < quantity; ++i) { let angle = i * dAngle + randFloat(0, dAngle); let dist = randFloat(2, 5); placeObject(point.x + dist * Math.cos(angle), point.y + dist * Math.sin(angle), pickRandom(decorations), 0, randFloat(0, 2 * PI)); } } // Food, fences with domestic animals wallStyles.other.sheepIn = new WallElement("sheepIn", "gaia/fauna_sheep", PI / 4, -1.5, 0.75, PI/2); wallStyles.other.foodBin = new WallElement("foodBin", "gaia/special_treasure_food_bin", PI/2, 1.5); wallStyles.other.sheep = new WallElement("sheep", "gaia/fauna_sheep", 0, 0, 0.75); wallStyles.other.farm = new WallElement("farm", "structures/brit_farmstead", PI, 0, -3); let fences = [ new Fortress("fence", ["foodBin", "farm", "bench", "sheepIn", "fence", "sheepIn", "fence", "sheepIn", "fence"]), new Fortress("fence", ["foodBin", "farm", "fence", "sheepIn", "fence", "sheepIn", "bench", "sheep", "fence", "sheepIn", "fence"]), new Fortress("fence", [ "foodBin", "farm", "cornerIn", "bench", "cornerOut", "fence_short", "sheepIn", "fence", "sheepIn", "fence", "sheepIn", "fence_short", "sheep", "fence" ]), new Fortress("fence", [ "foodBin", "farm", "cornerIn", "fence_short", "cornerOut", "bench", "sheepIn", "fence", "sheepIn", "fence", "sheepIn", "fence_short", "sheep", "fence" ]), new Fortress("fence", [ "foodBin", "farm", "fence", "sheepIn", "bench", "sheep", "fence", "sheepIn", "fence_short", "sheep", "fence", "sheepIn", "fence_short", "sheep", "fence" ]) ]; let num = fences.length; for (let i = 0; i < num; ++i) fences.push(new Fortress("fence", deepcopy(fences[i].wall).reverse())); // Groves, only Wood let groveEntities = ["gaia/flora_bush_temperate", "gaia/flora_tree_euro_beech"]; let groveActors = [ "actor|geology/highland1_moss.xml", "actor|geology/highland2_moss.xml", "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml" ]; let clGrove = createTileClass(); function placeGrove(point) { placeObject(point.x, point.y, pickRandom(["structures/gaul_outpost", "gaia/flora_tree_oak_new"]), 0, randFloat(0, 2 * PI)); let quantity = randIntInclusive(20, 30); let dAngle = TWO_PI / quantity; for (let i = 0; i < quantity; ++i) { let angle = dAngle * randFloat(i, i+1); let dist = randFloat(2, 5); let objectList = groveEntities; if (i % 3 == 0) objectList = groveActors; let x = point.x + dist * Math.cos(angle); let y = point.y + dist * Math.sin(angle); placeObject(x, y, pickRandom(objectList), 0, randFloat(0, 2 * PI)); createArea(new ClumpPlacer(5, 1, 1, 1, floor(x), floor(y)), [new TerrainPainter("temp_grass_plants"), paintClass(clGrove)]); } } // Camps with fire and gold treasure function placeCamp(point, centerEntity = "actor|props/special/eyecandy/campfire.xml", otherEntities = ["gaia/special_treasure_metal", "gaia/special_treasure_standing_stone", "units/brit_infantry_slinger_b", "units/brit_infantry_javelinist_b", "units/gaul_infantry_slinger_b", "units/gaul_infantry_javelinist_b", "units/gaul_champion_fanatic", "actor|props/special/common/waypoint_flag.xml", "actor|props/special/eyecandy/barrel_a.xml", "actor|props/special/eyecandy/basket_celt_a.xml", "actor|props/special/eyecandy/crate_a.xml", "actor|props/special/eyecandy/dummy_a.xml", "actor|props/special/eyecandy/handcart_1.xml", "actor|props/special/eyecandy/handcart_1_broken.xml", "actor|props/special/eyecandy/sack_1.xml", "actor|props/special/eyecandy/sack_1_rough.xml" ] ) { placeObject(point.x, point.y, centerEntity, 0, randFloat(0, TWO_PI)); - let quantity = randInt(5, 11); + let quantity = randIntInclusive(5, 11); let dAngle = TWO_PI / quantity; for (let i = 0; i < quantity; ++i) { let angle = i * dAngle + randFloat(0, dAngle); let dist = randFloat(1, 3); placeObject(point.x + dist * Math.cos(angle), point.y + dist * Math.sin(angle), pickRandom(otherEntities), 0, randFloat(0, 2 * PI)); } } function placeStartLocationResources(point, foodEntities = ["gaia/flora_bush_berry", "gaia/fauna_chicken", "gaia/fauna_chicken"]) { let currentAngle = randFloat(0, TWO_PI); // Stone and chicken let dAngle = TWO_PI * 2 / 9; let angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4); let dist = 12; let x = point.x + dist * Math.cos(angle); let y = point.y + dist * Math.sin(angle); placeMine({ "x": x, "y": y }, "gaia/geology_stonemine_temperate_quarry"); currentAngle += dAngle; // Wood let quantity = 80; dAngle = TWO_PI / quantity / 3; for (let i = 0; i < quantity; ++i) { angle = currentAngle + randFloat(0, dAngle); dist = randFloat(10, 15); let objectList = groveEntities; if (i % 2 == 0) objectList = groveActors; x = point.x + dist * Math.cos(angle); y = point.y + dist * Math.sin(angle); placeObject(x, y, pickRandom(objectList), 0, randFloat(0, 2 * PI)); createArea(new ClumpPlacer(5, 1, 1, 1, floor(x), floor(y)), [new TerrainPainter("temp_grass_plants"), paintClass(clGrove)]); currentAngle += dAngle; } // Metal and chicken dAngle = TWO_PI * 2 / 9; angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4); dist = 13; x = point.x + dist * Math.cos(angle); y = point.y + dist * Math.sin(angle); placeMine({ "x": x, "y": y }, "gaia/geology_metal_temperate_slabs"); currentAngle += dAngle; // Berries quantity = 15; dAngle = TWO_PI / quantity * 2 / 9; for (let i = 0; i < quantity; ++i) { angle = currentAngle + randFloat(0, dAngle); dist = randFloat(10, 15); x = point.x + dist * Math.cos(angle); y = point.y + dist * Math.sin(angle); placeObject(x, y, pickRandom(foodEntities), 0, randFloat(0, 2 * PI)); currentAngle += dAngle; } } log("Functions loaded after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check /** * Environment settings */ setBiome(g_BiomeAlpine); g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0.01 }; g_Environment.Water.WaterBody.Colour = { "r" : 0.3, "g" : 0.05, "b" : 0.1, "a" : 0.1 }; g_Environment.Water.WaterBody.Murkiness = 0.4; /** * Base terrain shape generation and settings */ // Height range by map size let heightScale = (g_Map.size + 256) / 768 / 4; let heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale }; // Water coverage let averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value let waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine let waterHeightAdjusted = waterHeight + MIN_HEIGHT; // Water height in RMGEN setWaterHeight(waterHeight); // Generate base terrain shape let medH = (heightRange.min + heightRange.max) / 2; let initialHeightmap = [[medH, medH], [medH, medH]]; setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8); // Apply simple erosion for (let i = 0; i < 5; ++i) splashErodeMap(0.1); // Final rescale rescaleHeightmap(heightRange.min, heightRange.max); RMS.SetProgress(25); /** * Prepare terrain texture placement */ let heighLimits = [ heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), // 1 Medium Water heightRange.min + (waterHeightAdjusted - heightRange.min), // 2 Shallow water waterHeightAdjusted + 1/8 * (heightRange.max - waterHeightAdjusted), // 3 Shore waterHeightAdjusted + 2/8 * (heightRange.max - waterHeightAdjusted), // 4 Low ground waterHeightAdjusted + 3/8 * (heightRange.max - waterHeightAdjusted), // 5 Player and path height waterHeightAdjusted + 4/8 * (heightRange.max - waterHeightAdjusted), // 6 High ground waterHeightAdjusted + 5/8 * (heightRange.max - waterHeightAdjusted), // 7 Lower forest border waterHeightAdjusted + 6/8 * (heightRange.max - waterHeightAdjusted), // 8 Forest waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border waterHeightAdjusted + (heightRange.max - waterHeightAdjusted)]; // 10 Hilltop let playerHeight = (heighLimits[4] + heighLimits[5]) / 2; // Average player height // Texture and actor presets let myBiome = []; myBiome.push({ // 0 Deep water "texture": ["shoreline_stoney_a"], "actor": [["gaia/fauna_fish", "actor|geology/stone_granite_boulder.xml"], 0.02], "textureHS": ["alpine_mountainside"], "actorHS": [["gaia/fauna_fish"], 0.1] }); myBiome.push({ // 1 Medium Water "texture": ["shoreline_stoney_a", "alpine_shore_rocks"], "actor": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], 0.03], "textureHS": ["alpine_mountainside"], "actorHS": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], 0.0] }); myBiome.push({ // 2 Shallow water "texture": ["alpine_shore_rocks"], "actor": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_large.xml", "actor|geology/stone_granite_med.xml", "actor|props/flora/reeds_pond_lush_b.xml"], 0.2], "textureHS": ["alpine_mountainside"], "actorHS": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_med.xml"], 0.1] }); myBiome.push({ // 3 Shore "texture": ["alpine_shore_rocks_grass_50", "alpine_grass_rocky"], "actor": [["gaia/flora_tree_pine", "gaia/flora_bush_badlands", "actor|geology/highland1_moss.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml"], 0.3], "textureHS": ["alpine_mountainside"], "actorHS": [["actor|props/flora/grass_soft_tuft_a.xml"], 0.1] }); myBiome.push({ // 4 Low ground "texture": ["alpine_dirt_grass_50", "alpine_grass_rocky"], "actor": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], "textureHS": ["alpine_grass_rocky"], "actorHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml"], 0.1] }); myBiome.push({ // 5 Player and path height "texture": ["new_alpine_grass_c", "new_alpine_grass_b", "new_alpine_grass_d"], "actor": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], "textureHS": ["alpine_grass_rocky"], "actorHS": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml"], 0.1] }); myBiome.push({ // 6 High ground "texture": ["new_alpine_grass_a", "alpine_grass_rocky"], "actor": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml", "actor|props/flora/bush_highlands.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], "textureHS": ["alpine_grass_rocky"], "actorHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml"], 0.1] }); myBiome.push({ // 7 Lower forest border "texture": ["new_alpine_grass_mossy", "alpine_grass_rocky"], "actor": [["gaia/flora_tree_pine", "gaia/flora_tree_oak", "actor|props/flora/grass_tufts_a.xml", "gaia/flora_bush_berry", "actor|geology/highland2_moss.xml", "gaia/fauna_goat", "actor|props/flora/bush_tempe_underbrush.xml"], 0.3], "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|props/flora/grass_tufts_a.xml", "actor|geology/highland2_moss.xml"], 0.1] }); myBiome.push({ // 8 Forest "texture": ["alpine_forrestfloor"], "actor": [["gaia/flora_tree_pine", "gaia/flora_tree_pine", "gaia/flora_tree_pine", "gaia/flora_tree_pine", "actor|geology/highland2_moss.xml", "actor|props/flora/bush_highlands.xml"], 0.5], "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|geology/highland2_moss.xml", "actor|geology/stone_granite_med.xml"], 0.1] }); myBiome.push({ // 9 Upper forest border "texture": ["alpine_forrestfloor_snow", "new_alpine_grass_dirt_a"], "actor": [["gaia/flora_tree_pine", "actor|geology/snow1.xml"], 0.3], "textureHS": ["alpine_cliff_b"], "actorHS": [["actor|geology/stone_granite_med.xml", "actor|geology/snow1.xml"], 0.1] }); myBiome.push({ // 10 Hilltop "texture": ["alpine_cliff_a", "alpine_cliff_snow"], "actor": [["actor|geology/highland1.xml"], 0.05], "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|geology/highland1.xml"], 0.0] }); log("Terrain shape generation and texture presets after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check /** * Get start locations */ let startLocations = getStartLocationsByHeightmap({ "min": heighLimits[4], "max": heighLimits[5] }, 1000, 30); // Sort start locations to form a "ring" let startLocationOrder = getOrderOfPointsForShortestClosePath(startLocations); let newStartLocations = []; for (let i = 0; i < startLocations.length; ++i) newStartLocations.push(startLocations[startLocationOrder[i]]); startLocations = newStartLocations; // Sort players by team let playerIDs = []; let teams = []; for (let i = 0; i < g_MapSettings.PlayerData.length - 1; ++i) { playerIDs.push(i+1); let t = g_MapSettings.PlayerData[i + 1].Team; if (teams.indexOf(t) == -1 && t !== undefined) teams.push(t); } playerIDs = sortPlayers(playerIDs); // Minimize maximum distance between players within a team if (teams.length) { let minDistance = Infinity; let bestShift; for (let s = 0; s < playerIDs.length; ++s) { let maxTeamDist = 0; for (let pi = 0; pi < playerIDs.length - 1; ++pi) { let p1 = playerIDs[(pi + s) % playerIDs.length] - 1; let t1 = getPlayerTeam(p1); if (teams.indexOf(t1) === -1) continue; for (let pj = pi + 1; pj < playerIDs.length; ++pj) { let p2 = playerIDs[(pj + s) % playerIDs.length] - 1; let t2 = getPlayerTeam(p2); if (t2 != t1) continue; let l1 = startLocations[pi]; let l2 = startLocations[pj]; let dist = getDistance(l1.x, l1.y, l2.x, l2.y); if (dist > maxTeamDist) maxTeamDist = dist; } } if (maxTeamDist < minDistance) { minDistance = maxTeamDist; bestShift = s; } } if (bestShift) { let newPlayerIDs = []; for (let i = 0; i < playerIDs.length; ++i) newPlayerIDs.push(playerIDs[(i + bestShift) % playerIDs.length]); playerIDs = newPlayerIDs; } } log("Start location chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check RMS.SetProgress(30); /** * Add paths */ let tchm = getTileCenteredHeightmap(); // Calculate tileCenteredHeightMap (This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false) let pathPoints = []; let clPath = createTileClass(); for (let i = 0; i < startLocations.length; ++i) { let start = startLocations[i]; let target = startLocations[(i + 1) % startLocations.length]; pathPoints = pathPoints.concat(placeRandomPathToHeight(start, target, playerHeight, clPath)); } log("Paths placed after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check RMS.SetProgress(45); /** * Get resource spots after players start locations calculation */ let avoidPoints = deepcopy(startLocations); for (let i = 0; i < avoidPoints.length; ++i) avoidPoints[i].dist = 30; let resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, clPath); log("Resource spots chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check RMS.SetProgress(55); /** * Divide tiles in areas by height and avoid paths */ let areas = []; for (let h = 0; h < heighLimits.length; ++h) areas.push([]); for (let x = 0; x < tchm.length; ++x) { for (let y = 0; y < tchm[0].length; ++y) { if (g_Map.tileClasses[clPath].inclusionCount[x][y] > 0) // Avoid paths continue; let minHeight = heightRange.min; for (let h = 0; h < heighLimits.length; ++h) { if (tchm[x][y] >= minHeight && tchm[x][y] <= heighLimits[h]) { areas[h].push({ "x": x, "y": y }); break; } else minHeight = heighLimits[h]; } } } /** * Get max slope of each area */ let slopeMap = getSlopeMap(); // Calculate slope map let minSlope = []; let maxSlope = []; for (let h = 0; h < heighLimits.length; ++h) { minSlope[h] = Infinity; maxSlope[h] = 0; for (let t = 0; t < areas[h].length; ++t) { let x = areas[h][t].x; let y = areas[h][t].y; let slope = slopeMap[x][y]; if (slope > maxSlope[h]) maxSlope[h] = slope; if (slope < minSlope[h]) minSlope[h] = slope; } } /** * Paint areas by height and slope */ for (let h = 0; h < heighLimits.length; ++h) { for (let t = 0; t < areas[h].length; ++t) { let x = areas[h][t].x; let y = areas[h][t].y; let actor = undefined; let texture = pickRandom(myBiome[h].texture); if (slopeMap[x][y] < 0.4 * (minSlope[h] + maxSlope[h])) { if (randBool(myBiome[h].actor[1])) actor = pickRandom(myBiome[h].actor[0]); } else { texture = pickRandom(myBiome[h].textureHS); if (randBool(myBiome[h].actorHS[1])) actor = pickRandom(myBiome[h].actorHS[0]); } g_Map.texture[x][y] = g_Map.getTextureID(texture); if (actor) placeObject(x + randFloat(), y + randFloat(), actor, 0, randFloat() * TWO_PI); } } log("Terrain texture placement finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check RMS.SetProgress(80); /** * Add start locations and resource spots after terrain texture and path painting */ for (let p = 0; p < playerIDs.length; ++p) { let point = startLocations[p]; rectangularSmoothToHeight(point, 40, 40, playerHeight, 0.7); placeCivDefaultEntities(point.x, point.y, playerIDs[p], { "iberWall": true }); placeStartLocationResources(startLocations[p]); } for (let i = 0; i < resourceSpots.length; ++i) { let choice = i % 5; if (choice == 0) placeMine(resourceSpots[i], "gaia/geology_stonemine_temperate_formation"); if (choice == 1) placeMine(resourceSpots[i], "gaia/geology_metal_temperate_slabs"); if (choice == 2) placeCustomFortress(resourceSpots[i].x, resourceSpots[i].y, pickRandom(fences), "other", 0, randFloat(0, 2 * PI)); if (choice == 3) placeGrove(resourceSpots[i]); if (choice == 4) placeCamp(resourceSpots[i]); } /** * Stop Timer */ log("Map generation finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); /** * Export map data */ ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/cantabrian_highlands.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/cantabrian_highlands.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/cantabrian_highlands.js (revision 19443) @@ -1,350 +1,350 @@ RMS.LoadLibrary("rmgen"); // terrain textures const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; const tGrassPForest = "temp_plants_bog"; const tGrassDForest = "temp_plants_bog"; const tGrassA = "temp_grass_plants"; const tGrassB = "temp_plants_bog"; const tGrassC = "temp_mud_a"; const tDirt = ["temp_plants_bog", "temp_mud_a"]; const tHill = ["temp_highlands", "temp_grass_long_b"]; const tCliff = ["temp_cliff_a", "temp_cliff_b"]; const tRoad = "temp_road"; const tRoadWild = "temp_road_overgrown"; const tGrassPatchBlend = "temp_grass_long_b"; const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; const tShoreBlend = "temp_grass_plants"; const tShore = "temp_plants_bog"; const tWater = "temp_mud_a"; // gaia entities const oOak = "gaia/flora_tree_oak"; const oOakLarge = "gaia/flora_tree_oak_large"; const oApple = "gaia/flora_tree_apple"; const oPine = "gaia/flora_tree_pine"; const oAleppoPine = "gaia/flora_tree_aleppo_pine"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oSheep = "gaia/fauna_sheep"; const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; const oStoneSmall = "gaia/geology_stone_temperate"; const oMetalLarge = "gaia/geology_metal_temperate_slabs"; // decorative props const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; const aGrassShort = "actor|props/flora/grass_soft_large.xml"; const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; const aLillies = "actor|props/flora/pond_lillies_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.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; // terrain + entity (for painting) const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oOak, tGrassDForest + TERRAIN_SEPARATOR + oOakLarge, tGrassDForest]; const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oPine, tGrassPForest + TERRAIN_SEPARATOR + oAleppoPine, tGrassPForest]; log("Initializing map..."); InitMap(); var numPlayers = getNumPlayers(); var mapSize = getMapSize(); var mapArea = mapSize*mapSize; var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // calculate size based on the radius var hillSize = PI * radius * radius; // create the hill var placer = new ClumpPlacer(hillSize, 0.95, 0.6, 10, ix, iz); var terrainPainter = new LayeredPainter( [tCliff, tHill], // terrains [cliffRadius] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type elevation, // elevation cliffRadius // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clPlayer)], null); // create the ramp var rampAngle = playerAngle[i] + PI + randFloat(-PI/8, PI/8); var rampDist = radius; var rampLength = 15; var rampWidth = 12; var rampX1 = round(fx + (rampDist + rampLength) * cos(rampAngle)); var rampZ1 = round(fz + (rampDist + rampLength) * sin(rampAngle)); var rampX2 = round(fx + (rampDist - 3) * cos(rampAngle)); var rampZ2 = round(fz + (rampDist - 3) * sin(rampAngle)); createRamp (rampX1, rampZ1, rampX2, rampZ2, 3, 20, rampWidth, 2, tHill, tCliff, clPlayer); // create the city patch var cityRadius = radius/3; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id, { 'iberWall': false }); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oOak, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(10); log("Creating lakes..."); var numLakes = round(scaleByMapSize(1,4) * numPlayers); placer = new ClumpPlacer(scaleByMapSize(100,250), 0.8, 0.1, 10); terrainPainter = new LayeredPainter( [tShoreBlend, tShore, tWater], // terrains [1,1] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -7, 6); var waterAreas = createAreas( placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 2, clWater, 20), numLakes ); RMS.SetProgress(15); log("Creating reeds..."); group = new SimpleGroup( [new SimpleObject(aReeds, 5,10, 0,4), new SimpleObject(aLillies, 0,1, 0,4)], true ); createObjectGroupsByAreas(group, 0, [borderClasses(clWater, 3, 0), stayClasses(clWater, 1)], numLakes, 100, waterAreas ); RMS.SetProgress(20); log("Creating fish..."); createObjectGroupsByAreas( new SimpleGroup( [new SimpleObject(oFish, 1,1, 0,1)], true, clFood ), 0, [stayClasses(clWater, 4), avoidClasses(clFood, 8)], numLakes / 4, 50, waterAreas ); RMS.SetProgress(25); createBumps(avoidClasses(clWater, 2, clPlayer, 0)); RMS.SetProgress(30); log("Creating hills..."); createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 2, clWater, 5, clHill, 15), clHill, scaleByMapSize(1, 4) * numPlayers); RMS.SetProgress(35); createForests( [tGrass, tGrassDForest, tGrassPForest, pForestP, pForestD], avoidClasses(clPlayer, 1, clWater, 3, clForest, 17, clHill, 1), clForest ); RMS.SetProgress(40); log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], [1,1], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0) ); RMS.SetProgress(45); log("Creating grass patches..."); createLayeredPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], [tGrassPatchBlend, tGrassPatch], [1], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0) ); RMS.SetProgress(50); log("Creating stone mines..."); createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clRock, 10, clHill, 1) ); RMS.SetProgress(55); log("Creating metal mines..."); createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clMetal, 10, clRock, 5, clHill, 1), clMetal ); RMS.SetProgress(60); 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), scaleByMapSize(13, 200), scaleByMapSize(13, 200), scaleByMapSize(13, 200) ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0) ); RMS.SetProgress(70); createFood ( [ [new SimpleObject(oSheep, 2,3, 0,2)], [new SimpleObject(oDeer, 5,7, 0,4)] ], [ 3 * numPlayers, 3 * numPlayers ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 1, clHill, 1, clFood, 20) ); RMS.SetProgress(80); createFood ( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(1, 4) * numPlayers + 2 + randIntInclusive(1, 4) * numPlayers + 2 ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10) ); RMS.SetProgress(85); log("Creating metal mines..."); var types = [oOak, oOakLarge, oPine, oApple]; // some variation createStragglerTrees(types, avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6)); RMS.SetProgress(90); setSkySet("cirrus"); setWaterColor(0.447, 0.412, 0.322); // muddy brown setWaterTint(0.447, 0.412, 0.322); // muddy brown setWaterMurkiness(1.0); setWaterWaviness(3.0); setWaterType("lake"); setFogThickness(0.25); setFogFactor(0.4); setPPEffect("hdr"); setPPSaturation(0.62); setPPContrast(0.62); setPPBloom(0.3); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/canyon.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/canyon.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/canyon.js (revision 19443) @@ -1,507 +1,513 @@ RMS.LoadLibrary("rmgen"); //random terrain textures var random_terrain = randomizeBiome(); const tMainTerrain = rBiomeT1(); const tForestFloor1 = rBiomeT2(); const tForestFloor2 = rBiomeT3(); const tCliff = rBiomeT4(); const tTier1Terrain = rBiomeT5(); const tTier2Terrain = rBiomeT6(); const tTier3Terrain = rBiomeT7(); const tHill = rBiomeT8(); const tDirt = rBiomeT9(); const tRoad = rBiomeT10(); const tRoadWild = rBiomeT11(); const tTier4Terrain = rBiomeT12(); const tShoreBlend = rBiomeT13(); const tShore = rBiomeT14(); const tWater = rBiomeT15(); // gaia entities const oTree1 = rBiomeE1(); const oTree2 = rBiomeE2(); const oTree3 = rBiomeE3(); const oTree4 = rBiomeE4(); const oTree5 = rBiomeE5(); const oFruitBush = rBiomeE6(); const oMainHuntableAnimal = rBiomeE8(); const oFish = rBiomeE9(); const oSecondaryHuntableAnimal = rBiomeE10(); const oStoneLarge = rBiomeE11(); const oStoneSmall = rBiomeE12(); const oMetalLarge = rBiomeE13(); const oWood = "gaia/special_treasure_wood"; const oFood = "gaia/special_treasure_food_bin"; // decorative props const aGrass = rBiomeA1(); const aGrassShort = rBiomeA2(); const aReeds = rBiomeA3(); const aLillies = rBiomeA4(); const aRockLarge = rBiomeA5(); const aRockMedium = rBiomeA6(); const aBushMedium = rBiomeA7(); const aBushSmall = rBiomeA8(); const aTree = rBiomeA9(); const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; log("Initializing map..."); InitMap(); var numPlayers = getNumPlayers(); var mapSize = getMapSize(); var mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clHill2 = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clLand = createTileClass(); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); placeTerrain(ix, iz, tMainTerrain); } } var fx = fractionToTiles(0.5); var fz = fractionToTiles(0.5); ix = round(fx); iz = round(fz); var lSize = sqrt(sqrt(sqrt(scaleByMapSize(1, 6)))); var placer = new ClumpPlacer(mapArea * 0.065 * lSize, 0.7, 0.1, 10, ix, iz); var terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 3 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], null); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(18,32); var cliffRadius = 2; var elevation = 20; var hillSize = PI * radius * radius; // get the x and z in tiles fx = fractionToTiles(playerX[i]); fz = fractionToTiles(playerZ[i]); ix = round(fx); iz = round(fz); // create the hill var placer = new ClumpPlacer(hillSize, 0.65, 0.1, 10, ix, iz); var terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [cliffRadius] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation cliffRadius // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 11; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 100); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = 12; var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oTree1, num, num, 0,4)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); // create the city patch var cityRadius = radius/2; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, fractionToTiles(playerX[i]), fractionToTiles(playerZ[i])); var painter = new LayeredPainter([tMainTerrain, tMainTerrain], [1]); createArea(placer, [painter, paintClass(clPlayer)], null); } placer = new ClumpPlacer(150, 0.6, 0.3, 10, fractionToTiles(0.5), fractionToTiles(0.5)); var painter = new LayeredPainter([tRoad, tRoad], [1]); createArea(placer, [painter, paintClass(clHill)], null); for (var i = 0; i < scaleByMapSize(9,16); i++) { - var ix = randInt(1, mapSize - 1); - var iz = randInt(1, mapSize - 1); - var ix2 = randInt(1, mapSize - 1); - var iz2 = randInt(1, mapSize - 1); - var placer = new PathPlacer(ix, iz, ix2, iz2, scaleByMapSize(11,16), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0); + var placer = new PathPlacer( + randIntExclusive(1, mapSize), + randIntExclusive(1, mapSize), + randIntExclusive(1, mapSize), + randIntExclusive(1, mapSize), + scaleByMapSize(11,16), + 0.4, + 3 * scaleByMapSize(1,4), + 0.1, + 0); + var terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 30, // elevation 3 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill2)], avoidClasses(clPlayer, 6, clHill2, 3, clHill, 2)); } for (var g = 0; g < scaleByMapSize(5,30); g++) { - var tx = randInt(1, mapSize - 1); - var tz = randInt(1, mapSize - 1); + var tx = randIntInclusive(1, mapSize - 1); + var tz = randIntInclusive(1, mapSize - 1); placer = new ClumpPlacer(mapArea * 0.01 * lSize, 0.7, 0.1, 10, tx, tz); terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [3] // widths ); elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 3 // blend radius ); var newarea = createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], avoidClasses(clLand, 6)); if (newarea !== null) { var distances = new Array(0); var d1 = 9999; var d2 = 9999; var p1 = -1; var p2 = 0; for (var i = 0; i < numPlayers; i++) { distances.push(sqrt((tx-mapSize*playerX[i])*(tx-mapSize*playerX[i])+(tz-mapSize*playerZ[i])*(tz-mapSize*playerZ[i]))); } for (var a = 0; a < numPlayers; a++) { if (d1 >= distances[a]) { d2 = d1; d1 = distances[a]; p2 = p1; p1 = a; } else if (d2 >= distances[a]) { d2 = distances[a]; p2 = a; } } var placer = new PathPlacer(tx, tz, mapSize*playerX[p1], mapSize*playerZ[p1], scaleByMapSize(11,17), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0.1); var terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 3 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], null); if (numPlayers > 1) { var placer = new PathPlacer(tx, tz, mapSize*playerX[p2], mapSize*playerZ[p2], scaleByMapSize(11,17), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0.1); var terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 3 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], null); } } } for (var i = 0; i < numPlayers; i++) { if (i+1 == numPlayers) { var placer = new PathPlacer(fractionToTiles(playerX[i]), fractionToTiles(playerZ[i]), fractionToTiles(playerX[0]), fractionToTiles(playerZ[0]), scaleByMapSize(8,13), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0); } else { var placer = new PathPlacer(fractionToTiles(playerX[i]), fractionToTiles(playerZ[i]), fractionToTiles(playerX[i+1]), fractionToTiles(playerZ[i+1]), scaleByMapSize(8,13), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0); } var terrainPainter = new LayeredPainter( [tRoadWild, tRoad], // terrains [1] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 2 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand), paintClass(clHill)], null); var placer = new PathPlacer(fractionToTiles(playerX[i]), fractionToTiles(playerZ[i]), fractionToTiles(0.5), fractionToTiles(0.5), scaleByMapSize(8,13), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0); var terrainPainter = new LayeredPainter( [tRoadWild, tRoad], // terrains [1] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 2 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand), paintClass(clHill)], null); } for (var i = 0; i < numPlayers; i++) { // create the city patch var cityRadius = radius/3; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, fractionToTiles(playerX[i]), fractionToTiles(playerZ[i])); var painter = new LayeredPainter([tRoad, tRoad], [1]); createArea(placer, [painter, paintClass(clPlayer)], null); } placer = new ClumpPlacer(150, 0.6, 0.3, 10, fractionToTiles(0.5), fractionToTiles(0.5)); var painter = new LayeredPainter([tRoad, tRoad], [1]); createArea(placer, [painter, paintClass(clHill)], null); RMS.SetProgress(20); paintTerrainBasedOnHeight(3.1, 29, 0, tCliff); paintTileClassBasedOnHeight(3.1, 32, 0, clHill2); // create bumps createBumps([avoidClasses(clPlayer, 2), stayClasses(clLand, 2)]); // create hills createHills([tCliff, tCliff, tHill], [avoidClasses(clPlayer, 2, clHill, 8, clHill2, 8), stayClasses(clLand, 5)], clHill, scaleByMapSize(10, 40)); // create hills outside the canyon createHills([tCliff, tCliff, tMainTerrain], avoidClasses(clLand, 1, clHill, 1), clHill, scaleByMapSize(20, 150), undefined, undefined, undefined, undefined, 40); // create forests createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], [avoidClasses(clPlayer, 1, clForest, 15, clHill, 1, clHill2, 0), stayClasses(clLand, 4)], clForest, 1.0, random_terrain ); RMS.SetProgress(50); // create dirt patches 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, 4, clHill2, 0), stayClasses(clLand, 3)] ); // create grass patches log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tTier4Terrain, [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4, clHill2, 0), stayClasses(clLand, 3)] ); log("Creating stone mines..."); // create stone quarries createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], [avoidClasses(clForest, 1, clPlayer, 3, clRock, 10, clHill, 1, clHill2, 1), stayClasses(clLand, 2)] ); log("Creating metal mines..."); // create large metal quarries createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], [avoidClasses(clForest, 1, clPlayer, 3, clMetal, 10, clRock, 5, clHill, 1, clHill2, 1), stayClasses(clLand, 2)], clMetal ); RMS.SetProgress(65); // create decoration var planetm = 1; if (random_terrain == g_BiomeTropic) 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ 3*scaleByMapSize(16, 262), 3*scaleByMapSize(8, 131), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200) ], avoidClasses(clForest, 0, clPlayer, 0, clHill, 0) ); // create actor trees log("Creating actor trees..."); group = new SimpleGroup( [new SimpleObject(aTree, 1,1, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clLand, 5), scaleByMapSize(200, 800), 50 ); RMS.SetProgress(70); // create animals createFood ( [ [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)] ], [ 3 * numPlayers, 3 * numPlayers ], [avoidClasses(clForest, 0, clPlayer, 4, clHill, 1, clFood, 20, clHill2, 1), stayClasses(clLand, 3)] ); // create fruits createFood ( [ [new SimpleObject(oFruitBush, 5,7, 0,4)] ], [ 3 * numPlayers ], [avoidClasses(clForest, 0, clPlayer, 4, clHill, 1, clFood, 10, clHill2, 1), stayClasses(clLand, 3)] ); RMS.SetProgress(85); // create straggler trees log("Creating straggler trees..."); var types = [oTree1, oTree2, oTree4, oTree3]; // some variation createStragglerTrees(types, [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6, clHill2, 1), stayClasses(clLand, 3)]); // create treasures var fx = fractionToTiles(0.5); var fz = fractionToTiles(0.5); -for (var i = 0; i < randInt(3,8); i++) - placeObject(fx+randFloat(-7,7), fz+randFloat(-7,7), oWood, 0, randFloat(0, TWO_PI)); +for (let i = 0; i < randIntInclusive(3, 8); ++i) + placeObject(fx + randFloat(-7, 7), fz + randFloat(-7, 7), oWood, 0, randFloat(0, 2 * PI)); -for (var i = 0; i < randInt(3,8); i++) - placeObject(fx+randFloat(-7,7), fz+randFloat(-7,7), oFood, 0, randFloat(0, TWO_PI)); +for (let i = 0; i < randIntInclusive(3, 8); ++i) + placeObject(fx + randFloat(-7, 7), fz + randFloat(-7, 7), oFood, 0, randFloat(0, 2 * PI)); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/cycladic_archipelago.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/cycladic_archipelago.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/cycladic_archipelago.js (revision 19443) @@ -1,511 +1,511 @@ RMS.LoadLibrary("rmgen"); // terrain textures const tOceanDepths = "medit_sea_depths"; const tOceanRockDeep = "medit_sea_coral_deep"; const tOceanRockShallow = "medit_rocks_wet"; const tOceanCoral = "medit_sea_coral_plants"; const tBeachWet = "medit_sand_wet"; const tBeachDry = "medit_sand"; const tBeachGrass = "medit_rocks_grass"; const tBeach = ["medit_rocks_grass","medit_sand", "medit_rocks_grass_shrubs"]; const tBeachBlend = ["medit_rocks_grass", "medit_rocks_grass_shrubs"]; const tBeachCliff = "medit_dirt"; const tCity = "medit_city_tile"; const tGrassDry = ["medit_grass_field_dry", "medit_grass_field_b"]; const tGrass = ["medit_rocks_grass", "medit_rocks_grass","medit_dirt","medit_rocks_grass_shrubs"]; const tGrassLush = ["grass_temperate_dry_tufts", "medit_grass_flowers"]; const tGrassShrubs = "medit_shrubs"; const tCliffShrubs = ["medit_cliff_aegean_shrubs", "medit_cliff_italia_grass","medit_cliff_italia"]; const tGrassRock = ["medit_rocks_grass"]; const tDirt = "medit_dirt"; const tDirtGrass = "medit_dirt_b"; const tDirtCliff = "medit_cliff_italia"; const tGrassCliff = "medit_cliff_italia_grass"; const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; const tForestFloor = "medit_forestfloor_a"; // gaia entities const oBeech = "gaia/flora_tree_euro_beech"; const oBerryBush = "gaia/flora_bush_berry"; const oCarob = "gaia/flora_tree_carob"; const oCypress1 = "gaia/flora_tree_cypress"; const oCypress2 = "gaia/flora_tree_cypress"; const oLombardyPoplar = "gaia/flora_tree_poplar_lombardy"; const oOak = "gaia/flora_tree_oak"; const oPalm = "gaia/flora_tree_medit_fan_palm"; const oPine = "gaia/flora_tree_aleppo_pine"; const oPoplar = "gaia/flora_tree_poplar"; const oDateT = "gaia/flora_tree_cretan_date_palm_tall"; const oDateS = "gaia/flora_tree_cretan_date_palm_short"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oWhale = "gaia/fauna_whale_humpback"; const oStoneLarge = "gaia/geology_stonemine_medit_quarry"; const oStoneSmall = "gaia/geology_stone_mediterranean"; const oMetalLarge = "gaia/geology_metal_mediterranean_slabs"; const oShipwreck = "other/special_treasure_shipwreck"; const oShipDebris = "other/special_treasure_shipwreck_debris"; // decorative props const aBushLargeDry = "actor|props/flora/bush_medit_la_dry.xml"; const aBushLarge = "actor|props/flora/bush_medit_la.xml"; const aBushMedDry = "actor|props/flora/bush_medit_me_dry.xml"; const aBushMed = "actor|props/flora/bush_medit_me.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const aBushSmallDry = "actor|props/flora/bush_medit_sm_dry.xml"; const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; const aGrassDry = "actor|props/flora/grass_soft_dry_large_tall.xml"; const aRockLarge = "actor|geology/stone_granite_large.xml"; const aRockMed = "actor|geology/stone_granite_med.xml"; const aRockSmall = "actor|geology/stone_granite_small.xml"; // terrain + entity (for painting) const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); var clCoral = createTileClass(); var clPlayer = createTileClass(); var clIsland = createTileClass(); var clCity = createTileClass(); var clDirt = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); //array holding starting islands based on number of players var startingPlaces=[[0],[0,3],[0,2,4],[0,1,3,4],[0,1,2,3,4],[0,1,2,3,4,5]]; var numIslands = Math.max(6, numPlayers); var islandX = new Array(numIslands); var islandZ = new Array(numIslands); var islandAngle = new Array(numIslands); //holds all land areas var areas = []; var startAngle = randFloat() * 2 * PI; for (var i=0; i < numIslands; i++) { islandAngle[i] = startAngle + i*2*PI/numIslands; islandX[i] = 0.5 + 0.39*cos(islandAngle[i]); islandZ[i] = 0.5 + 0.39*sin(islandAngle[i]); } for (var i = 0; i < numIslands; ++i) { var radius = scaleByMapSize(15,40); var coral=scaleByMapSize(1,5); var wet = 3; var dry = 1; var gbeach = 2; var elevation = 3; // get the x and z in tiles var fx = fractionToTiles(islandX[i]); var fz = fractionToTiles(islandZ[i]); var ix = round(fx); var iz = round(fz); var islandSize = PI*radius*radius; var islandBottom=PI*(radius+coral)*(radius+coral); //create base var placer = new ClumpPlacer(islandBottom, .7, .1, 10, ix, iz); var terrainPainter = new LayeredPainter([tOceanRockDeep, tOceanCoral], [5]); createArea(placer, [terrainPainter, paintClass(clCoral)],avoidClasses(clCoral,0)); } //create spoke islands //put down base resources and animals but do not populate for (var i=0; i < numIslands; i++) { log("Creating base Island " + (i + 1) + "..."); var radius = scaleByMapSize(15,40); var coral=scaleByMapSize(2,5); var wet = 3; var dry = 1; var gbeach = 2; var elevation = 3; // get the x and z in tiles var fx = fractionToTiles(islandX[i]); var fz = fractionToTiles(islandZ[i]); var ix = round(fx); var iz = round(fz); var islandSize = PI*radius*radius; var islandBottom=PI*(radius+coral)*(radius+coral); // create island var placer = new ClumpPlacer(islandSize, .7, .1, 10, ix, iz); var terrainPainter = new LayeredPainter( [tOceanCoral,tBeachWet, tBeachDry, tBeach, tBeachBlend, tGrass], [1, wet, dry, 1, gbeach] ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, elevation, 5); var temp = createArea(placer, [terrainPainter, paintClass(clPlayer), elevationPainter],avoidClasses(clPlayer,0)); areas.push(temp); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 10; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(12, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPalm, num, num, 0,3)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } RMS.SetProgress(15); log("Populating islands ..."); //nPlayer is the player we are on i is the island we are on var nPlayer = 0; for (let i = 0; i < numIslands; ++i) if (numPlayers >= 6 || i == startingPlaces[numPlayers-1][nPlayer]) { var id = playerIDs[nPlayer]; // Get the x and z in tiles var fx = fractionToTiles(islandX[i]); var fz = fractionToTiles(islandZ[i]); var ix = round(fx); var iz = round(fz); // Create city patch var cityRadius = 6; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tGrass, tCity], [1]); createArea(placer, [painter,paintClass(clCity)], null); placeCivDefaultEntities(fx, fz, id, { 'iberWall': 'towers' }); ++nPlayer; } RMS.SetProgress(20); // get the x and z in tiles var nCenter = floor(scaleByMapSize(1,4)); var startAngle = randFloat() * 2 * PI; for (var i = 0; i < nCenter; ++i) { var fx = 0.5; var fz = 0.5; if (nCenter != 1) { let isangle = startAngle + i*2*PI/nCenter + PI/8 * randFloat(-1, -1); let dRadius = randFloat(0.1, 0.16); fx = 0.5 + dRadius * cos(isangle); fz = 0.5 + dRadius * sin(isangle); } var ix = round(fractionToTiles(fx)); var iz = round(fractionToTiles(fz)); var radius = scaleByMapSize(15,30); var coral= 2; var wet = 3; var dry = 1; var gbeach = 2; var elevation = 3; var islandSize = PI*radius*radius; var islandBottom=PI*(radius+coral)*(radius+coral); // Create base var placer = new ClumpPlacer(islandBottom, .7, .1, 10, ix, iz); var terrainPainter = new LayeredPainter( [tOceanRockDeep, tOceanCoral], [5] ); createArea(placer, [terrainPainter, paintClass(clCoral)],avoidClasses(clCoral,0,clPlayer,0)); // Create island var placer = new ClumpPlacer(islandSize, .7, .1, 10, ix, iz); var terrainPainter = new LayeredPainter( [tOceanCoral,tBeachWet, tBeachDry, tBeach, tBeachBlend, tGrass], [1, wet, dry, 1, gbeach] ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, elevation, 5); var temp = createArea(placer, [terrainPainter, paintClass(clIsland), elevationPainter],avoidClasses(clPlayer,0)); areas.push(temp); } RMS.SetProgress(30); log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 60), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 3); createAreasInAreas( placer, painter, avoidClasses(clCity, 0), scaleByMapSize(25, 75),15, areas ); RMS.SetProgress(34); log("Creating hills..."); placer = new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1); terrainPainter = new LayeredPainter( [tCliff, tCliffShrubs], // terrains [2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 12, 2); createAreasInAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clCity, 15, clHill, 15), scaleByMapSize(5, 30), 15, areas ); RMS.SetProgress(38); // Find all water for (var ix = 0; ix < mapSize; ix++) for (var iz = 0; iz < mapSize; iz++) if (getHeight(ix,iz) < 0) addToClass(ix,iz,clWater); log("Creating forests..."); var types = [ [[tForestFloor, tGrass, pPalmForest], [tForestFloor, pPalmForest]], [[tForestFloor, tGrass, pPineForest], [tForestFloor, pPineForest]], [[tForestFloor, tGrass, pPoplarForest], [tForestFloor, pPoplarForest]], [[tForestFloor, tGrass, pMainForest], [tForestFloor, pMainForest]] ]; // some variation var size = 5; //size var num = scaleByMapSize(10, 64); //number for (var i = 0; i < types.length; ++i) { - placer = new ClumpPlacer(6+randInt(12), 0.1, 0.1, 1); + placer = new ClumpPlacer(randIntInclusive(6, 17), 0.1, 0.1, 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreasInAreas( placer, [painter, paintClass(clForest)], avoidClasses(clCity, 1, clWater, 3, clForest, 3, clHill, 1), num, 20, areas ); } RMS.SetProgress(42); log("Creating stone mines..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroupsByAreas(group, 0, [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 6)], scaleByMapSize(4,16), 200, areas ); RMS.SetProgress(46); log("Creating small stone mines..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroupsByAreas(group, 0, [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 2)], scaleByMapSize(4,16), 200, areas ); RMS.SetProgress(50); log("Creating metal mines..."); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroupsByAreas(group, 0, [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6)], scaleByMapSize(4,16), 200, areas ); RMS.SetProgress(54); log("Creating shrub patches..."); var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter([tBeachBlend,tGrassShrubs],[1]); createAreasInAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0), scaleByMapSize(4, 16), 20, areas ); } RMS.SetProgress(58); log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter([tGrassDry],[]); createAreasInAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0), scaleByMapSize(4, 16), 20, areas ); } RMS.SetProgress(62); log("Creating straggler trees..."); for (let tree of [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine]) createObjectGroupsByAreas( new SimpleGroup([new SimpleObject(tree, 1,1, 0,1)], true, clForest), 0, avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 1, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), scaleByMapSize(2, 38), 50, areas ); RMS.SetProgress(66); log("Create straggler cypresses..."); group = new SimpleGroup( [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], true ); createObjectGroupsByAreas(group, 0, avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 1, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), scaleByMapSize(5, 75), 50, areas ); RMS.SetProgress(70); log("Create straggler date palms..."); group = new SimpleGroup( [new SimpleObject(oDateS, 1,3, 0,3), new SimpleObject(oDateT, 0,2, 0,2)], true ); createObjectGroupsByAreas(group, 0, avoidClasses(clWater, 2, clForest, 1, clCity, 0, clBaseResource, 1, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), scaleByMapSize(5, 75), 50, areas ); RMS.SetProgress(74); log("Creating rocks..."); group = new SimpleGroup( [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), new SimpleObject(aRockLarge, 0,1, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clCity, 0), scaleByMapSize(30, 180), 50 ); RMS.SetProgress(78); log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 5, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 2, clFood, 8), 3 * numPlayers, 50 ); RMS.SetProgress(82); log("Creating berry bushes..."); group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); createObjectGroups(group, 0, avoidClasses(clWater, 2, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 2, clFood, 8), 1.5 * numPlayers, 100 ); RMS.SetProgress(86); log("Creating Fish..."); group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,3)], true, clFood); createObjectGroups(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8)], scaleByMapSize(40,200), 100 ); RMS.SetProgress(90); log("Creating Whales..."); group = new SimpleGroup([new SimpleObject(oWhale, 1,1, 0,3)], true, clFood); createObjectGroups(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8, clPlayer,4,clIsland,4)], scaleByMapSize(10,40), 100 ); RMS.SetProgress(94); log("Creating shipwrecks..."); group = new SimpleGroup([new SimpleObject(oShipwreck, 1,1, 0,3)], true, clFood); createObjectGroups(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8)], scaleByMapSize(6,16), 100 ); RMS.SetProgress(98); log("Creating shipwreck debris..."); group = new SimpleGroup([new SimpleObject(oShipDebris, 1,2, 0,4)], true, clFood); createObjectGroups(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8)], scaleByMapSize(10,20), 100 ); RMS.SetProgress(99); setSkySet("sunny"); setWaterColor(0.2,0.294,0.49); setWaterTint(0.208, 0.659, 0.925); setWaterMurkiness(0.72); setWaterWaviness(3.0); setWaterType("ocean"); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/empire.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/empire.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/empire.js (revision 19443) @@ -1,219 +1,219 @@ RMS.LoadLibrary("rmgen"); RMS.LoadLibrary("rmgen2"); InitMap(); randomizeBiome(); initMapSettings(); initTileClasses(); -resetTerrain(g_Terrains.mainTerrain, g_TileClasses.land, randInt(5)); +resetTerrain(g_Terrains.mainTerrain, g_TileClasses.land, randIntInclusive(0, 4)); RMS.SetProgress(10); addBases("stronghold", 0.37, 0.04); RMS.SetProgress(20); // Change the starting angle and add the players again var rotation = PI; if (g_MapInfo.teams.length == 2) rotation = PI / 2; if (g_MapInfo.teams.length == 4) rotation = PI + PI / 4; g_MapInfo.startAngle = g_MapInfo.startAngle + rotation; addBases("stronghold", 0.15, 0.04); RMS.SetProgress(40); addElements(shuffleArray([ { "func": addHills, "avoid": [ g_TileClasses.bluff, 5, g_TileClasses.hill, 15, g_TileClasses.mountain, 2, g_TileClasses.plateau, 5, g_TileClasses.player, 20, g_TileClasses.valley, 2, g_TileClasses.water, 2 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["tons"] }, { "func": addMountains, "avoid": [ g_TileClasses.bluff, 20, g_TileClasses.mountain, 25, g_TileClasses.plateau, 20, g_TileClasses.player, 20, g_TileClasses.valley, 10, g_TileClasses.water, 15 ], "sizes": ["huge"], "mixes": ["same", "similar"], "amounts": ["tons"] }, { "func": addPlateaus, "avoid": [ g_TileClasses.bluff, 20, g_TileClasses.mountain, 25, g_TileClasses.plateau, 20, g_TileClasses.player, 40, g_TileClasses.valley, 10, g_TileClasses.water, 15 ], "sizes": ["huge"], "mixes": ["same", "similar"], "amounts": ["tons"] } ])); RMS.SetProgress(50); addElements([ { "func": addLayeredPatches, "avoid": [ g_TileClasses.bluff, 2, g_TileClasses.dirt, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 12, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addDecoration, "avoid": [ g_TileClasses.bluff, 2, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 12, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] } ]); RMS.SetProgress(60); addElements(shuffleArray([ { "func": addMetal, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 3, g_TileClasses.mountain, 2, g_TileClasses.player, 30, g_TileClasses.rock, 10, g_TileClasses.metal, 20, g_TileClasses.plateau, 2, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["same"], "amounts": g_AllAmounts }, { "func": addStone, "avoid": [g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 3, g_TileClasses.mountain, 2, g_TileClasses.player, 30, g_TileClasses.rock, 20, g_TileClasses.metal, 10, g_TileClasses.plateau, 2, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["same"], "amounts": g_AllAmounts }, { "func": addForests, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 18, g_TileClasses.metal, 3, g_TileClasses.mountain, 5, g_TileClasses.plateau, 2, g_TileClasses.player, 20, g_TileClasses.rock, 3, g_TileClasses.water, 2 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["few", "normal", "many", "tons"] } ])); RMS.SetProgress(80); addElements(shuffleArray([ { "func": addBerries, "avoid": [ g_TileClasses.berries, 30, g_TileClasses.bluff, 5, g_TileClasses.forest, 5, g_TileClasses.metal, 10, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 20, g_TileClasses.rock, 10, g_TileClasses.water, 3 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addAnimals, "avoid": [ g_TileClasses.animals, 20, g_TileClasses.bluff, 5, g_TileClasses.forest, 2, g_TileClasses.metal, 2, g_TileClasses.mountain, 1, g_TileClasses.plateau, 2, g_TileClasses.player, 20, g_TileClasses.rock, 2, g_TileClasses.water, 3 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addStragglerTrees, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 7, g_TileClasses.metal, 2, g_TileClasses.mountain, 1, g_TileClasses.plateau, 2, g_TileClasses.player, 12, g_TileClasses.rock, 2, g_TileClasses.water, 5 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts } ])); RMS.SetProgress(90); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/english_channel.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/english_channel.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/english_channel.js (revision 19443) @@ -1,409 +1,409 @@ RMS.LoadLibrary("rmgen"); // terrain textures const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; const tGrassPForest = "temp_plants_bog"; const tGrassDForest = "temp_plants_bog"; const tGrassA = "temp_grass_plants"; const tGrassB = "temp_plants_bog"; const tGrassC = "temp_mud_a"; const tDirt = ["temp_plants_bog", "temp_mud_a"]; const tHill = ["temp_highlands", "temp_grass_long_b"]; const tCliff = ["temp_cliff_a", "temp_cliff_b"]; const tRoad = "temp_road"; const tRoadWild = "temp_road_overgrown"; const tGrassPatchBlend = "temp_grass_long_b"; const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; const tShoreBlend = "temp_grass_plants"; const tShore = "temp_dirt_gravel"; const tWater = "temp_dirt_gravel_b"; // gaia entities const oBeech = "gaia/flora_tree_euro_beech"; const oPoplar = "gaia/flora_tree_poplar"; const oApple = "gaia/flora_tree_apple"; const oOak = "gaia/flora_tree_oak"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oGoat = "gaia/fauna_goat"; const oBoar = "gaia/fauna_boar"; const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; const oStoneSmall = "gaia/geology_stone_temperate"; const oMetalLarge = "gaia/geology_metal_temperate_slabs"; // decorative props 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 aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; const aLillies = "actor|props/flora/water_lillies.xml"; // terrain + entity (for painting) const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest]; const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest]; const WATER_WIDTH = 0.25; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clShallow = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = primeSortPlayers(sortPlayers(playerIDs)); // place players var playerX = []; var playerZ = []; var playerAngle = []; var playerPos = []; var iop = 0; for (var i = 0; i < numPlayers; i++) { iop = i - 1; if (numPlayers % 2 == 0) playerPos[i] = ((iop + abs(iop % 2)) / 2 + 1) / ((numPlayers / 2) + 1); else if (iop % 2 != 0) playerPos[i] = ((iop + abs(iop % 2)) / 2 + 1) / (((numPlayers + 1) / 2) + 1); else playerPos[i] = (iop / 2 + 1) / (((numPlayers - 1) / 2) + 1); playerZ[i] = 0.2 + 0.6*(i%2); playerX[i] = playerPos[i]; } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // Setting tile class addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, [painter, paintClass(clPlayer)], null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oOak, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(10); log("Creating sea"); var theta = randFloat(0, 1); var theta2 = randFloat(0, 1); var seed = randFloat(2,3); var seed2 = randFloat(2,3); for (var ix = 0; ix < mapSize; ix++) for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); // add the rough shape of the water var km = 20/scaleByMapSize(35, 160); var fadeDist = 0.02; var cu = km*rndRiver(theta+x*0.5*(mapSize/64),seed); var cu2 = km*rndRiver(theta2+x*0.5*(mapSize/64),seed2); if (z > cu + 0.5 - WATER_WIDTH/2 && z < cu2 + 0.5 + WATER_WIDTH/2) { var h; if (z < (cu + 0.5 + fadeDist - WATER_WIDTH/2)) h = 3 - 7 * (1 - ((cu + 0.5 + fadeDist - WATER_WIDTH/2) - z)/fadeDist); else if (z > (cu2 + 0.5 - fadeDist + WATER_WIDTH/2)) h = 3 - 7 * (1 - (z - (cu2 + 0.5 - fadeDist + WATER_WIDTH/2))/fadeDist); else h = -4.0; if (h < -1.5) placeTerrain(ix, iz, tWater); else placeTerrain(ix, iz, tShore); setHeight(ix, iz, h); } else setHeight(ix, iz, 3.1); } RMS.SetProgress(20); log("Creating rivers"); for (let i = 0; i <= randIntInclusive(8, scaleByMapSize(12, 20)); ++i) { var cLocation = randFloat(0.05, 0.95); var sign = randBool() ? 1 : -1; var tang = sign * PI * randFloat(0.2, 0.8); var cDistance = sign * 0.05; var point = getTIPIADBON([fractionToTiles(cLocation), fractionToTiles(0.5 + cDistance)], [fractionToTiles(cLocation), fractionToTiles(0.5 - cDistance)], [-6, -1.5], 0.5, 4, 0.01); if (point !== undefined) { var placer = new PathPlacer(floor(point[0]), floor(point[1]), floor(fractionToTiles(0.5 + 0.49*cos(tang))), floor(fractionToTiles(0.5 + 0.49*sin(tang))), scaleByMapSize(10,20), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0.05); var terrainPainter = new LayeredPainter( [tShore, tWater, tWater], // terrains [1, 3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type -4, // elevation 4 // blend radius ); var success = createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 8, clWater, 3, clShallow, 2)); if (success !== undefined) { placer = new ClumpPlacer(floor(PI*scaleByMapSize(10,20)*scaleByMapSize(10,20)/4), 0.95, 0.6, 10, fractionToTiles(0.5 + 0.49*cos(tang)), fractionToTiles(0.5 + 0.49*sin(tang))); var painter = new LayeredPainter( [tShore, tWater, tWater], // terrains [1, 3] // widths); ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -3, 3); createArea(placer, [painter, elevationPainter], avoidClasses(clPlayer, 23)); } } } passageMaker(round(fractionToTiles(0.2)), round(fractionToTiles(0.25)), round(fractionToTiles(0.8)), round(fractionToTiles(0.25)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); passageMaker(round(fractionToTiles(0.2)), round(fractionToTiles(0.75)), round(fractionToTiles(0.8)), round(fractionToTiles(0.75)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); paintTerrainBasedOnHeight(-5, 1, 1, tWater); paintTerrainBasedOnHeight(1, 3, 1, tShore); paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); RMS.SetProgress(25); createBumps(avoidClasses(clWater, 5, clPlayer, 20)); RMS.SetProgress(30); createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15, clWater, 5), clHill, scaleByMapSize(1, 4) * numPlayers); RMS.SetProgress(50); createForests( [tGrass, tGrassDForest, tGrassDForest, pForestD, pForestD], avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 6), clForest, 1.0, 0 ); RMS.SetProgress(70); log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tGrass,tGrassA], tGrassB, [tGrassB,tGrassC]], [1,1], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6) ); log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], [tGrassPatchBlend, tGrassPatch], [1], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6) ); RMS.SetProgress(80); log("Creating stone mines..."); createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clWater, 2, clForest, 1, clPlayer, 20, clRock, 10, clHill, 2) ); log("Creating metal mines..."); createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clWater, 2, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), clMetal ); RMS.SetProgress(85); 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), scaleByMapSize(13, 200), scaleByMapSize(13, 200), scaleByMapSize(13, 200) ], avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 0) ); // create water decoration in the shallow parts createDecoration ( [[new SimpleObject(aReeds, 1,3, 0,1)], [new SimpleObject(aLillies, 1,2, 0,1)] ], [ scaleByMapSize(800, 12800), scaleByMapSize(800, 12800) ], stayClasses(clShallow, 0) ); // create animals createFood ( [ [new SimpleObject(oDeer, 5,7, 0,4)], [new SimpleObject(oGoat, 2,3, 0,2)], [new SimpleObject(oBoar, 2,3, 0,2)] ], [ 3 * numPlayers, 3 * numPlayers, 3 * numPlayers ], avoidClasses(clWater, 1, clForest, 0, clPlayer, 20, clHill, 0, clFood, 15) ); // create fruits createFood ( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(1, 4) * numPlayers + 2 + randIntInclusive(1, 4) * numPlayers + 2 ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10) ); // create fish createFood ( [ [new SimpleObject(oFish, 2,3, 0,2)] ], [scaleByMapSize(3, 25) * numPlayers], [avoidClasses(clFood, 6), stayClasses(clWater, 4)] ); log("Creating straggler trees..."); var types = [oBeech, oPoplar, oApple]; // some variation createStragglerTrees(types, avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 8, clMetal, 6, clRock, 6)); // Set environment setSkySet("cirrus"); setWaterColor(0.114, 0.192, 0.463); setWaterTint(0.255, 0.361, 0.651); setWaterWaviness(3.0); setWaterType("ocean"); setWaterMurkiness(0.83); setFogThickness(0.35); setFogFactor(0.55); setPPEffect("hdr"); setPPSaturation(0.62); setPPContrast(0.62); setPPBloom(0.37); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/flood.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/flood.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/flood.js (revision 19443) @@ -1,410 +1,422 @@ RMS.LoadLibrary("rmgen"); let random_terrain = randomizeBiome([g_BiomeSavanna]); const tMainTerrain = rBiomeT1(); const tForestFloor1 = rBiomeT2(); const tForestFloor2 = rBiomeT3(); const tCliff = rBiomeT4(); const tTier1Terrain = rBiomeT5(); const tTier2Terrain = rBiomeT6(); const tTier3Terrain = rBiomeT7(); const tRoad = rBiomeT10(); const tRoadWild = rBiomeT11(); const tTier4Terrain = rBiomeT12(); const tShore = rBiomeT14(); const tWater = rBiomeT15(); let tHill = rBiomeT8(); let tDirt = rBiomeT9(); if (random_terrain == g_BiomeTemperate) { tDirt = ["medit_shrubs_a", "grass_field"]; tHill = ["grass_field", "peat_temp"]; } // Gaia entities const oTree1 = rBiomeE1(); const oTree2 = rBiomeE2(); const oTree3 = rBiomeE3(); const oTree4 = rBiomeE4(); const oTree5 = rBiomeE5(); const oFruitBush = rBiomeE6(); const oMainHuntableAnimal = rBiomeE8(); const oFish = rBiomeE9(); const oSecondaryHuntableAnimal = rBiomeE10(); const oStoneLarge = rBiomeE11(); const oMetalLarge = rBiomeE13(); // Decorative props const aGrass = rBiomeA1(); const aGrassShort = rBiomeA2(); const aRockLarge = rBiomeA5(); const aRockMedium = rBiomeA6(); const aBushMedium = rBiomeA7(); const aBushSmall = rBiomeA8(); const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; log("Initializing map..."); InitMap(); const radius = scaleByMapSize(15, 25); const elevation = 2; const shoreRadius = 6; const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize * mapSize; const centerOfMap = mapSize / 2; // Create tile classes let clPlayer = createTileClass(); let clHill = createTileClass(); let clMountain = createTileClass(); let clForest = createTileClass(); let clWater = createTileClass(); let clDirt = createTileClass(); let clRock = createTileClass(); let clMetal = createTileClass(); let clFood = createTileClass(); let clBaseResource = createTileClass(); for (let ix = 0; ix < mapSize; ++ix) for (let iz = 0; iz < mapSize; ++iz) placeTerrain(ix, iz, tWater); // Randomize player order let playerIDs = []; for (let i = 0; i < numPlayers; ++i) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); // Place players let playerX = []; let playerZ = []; let playerAngle = []; let startAngle = randFloat(0, TWO_PI); for (let i = 0; i < numPlayers; ++i) { playerAngle[i] = startAngle + i * TWO_PI/numPlayers; playerX[i] = 0.5 + 0.38 * cos(playerAngle[i]); playerZ[i] = 0.5 + 0.38 * sin(playerAngle[i]); } let fx = fractionToTiles(0.5); let fz = fractionToTiles(0.5); let ix = round(fx); let iz = round(fz); // Create the water let placer = new ClumpPlacer(mapArea * 1, 1, 1, 1, ix, iz); let terrainPainter = new LayeredPainter( [tWater, tWater, tShore], // terrains [1, 4] // widths ); let elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type getMapBaseHeight(), // elevation 2 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 5)); for (let i = 0; i < numPlayers; ++i) { let id = playerIDs[i]; log("Creating base for player " + id + "..."); // Get the x and z in tiles let fx = fractionToTiles(playerX[i]); let fz = fractionToTiles(playerZ[i]); let ix = round(fx); let iz = round(fz); let hillSize = PI * radius * radius * 2; // Create the hill let placer = new ClumpPlacer(hillSize, 0.80, 0.1, 10, ix, iz); let terrainPainter = new LayeredPainter( [tShore, tMainTerrain], // terrains [shoreRadius] // widths ); let elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type elevation, // elevation shoreRadius // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], null); // Mark a small area around the player's starting coördinates with the clPlayer class addToClass(ix, iz, clPlayer); addToClass(ix + 5, iz, clPlayer); addToClass(ix, iz + 5, clPlayer); addToClass(ix - 5, iz, clPlayer); addToClass(ix, iz - 5, clPlayer); placeCivDefaultEntities(fx, fz, id, { "iberWall": false }); // Create the city patch let cityRadius = radius/3; placer = new ClumpPlacer(PI * cityRadius * cityRadius, 0.6, 0.3, 10, ix, iz); let painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); placeDefaultChicken(fx, fz, clBaseResource); // Create berry bushes let bbAngle = randFloat(0, TWO_PI); let bbDist = 12; let bbX = round(fx + bbDist * cos(bbAngle)); let bbZ = round(fz + bbDist * sin(bbAngle)); let group = new SimpleGroup( [new SimpleObject(oFruitBush, 5, 5, 0, 3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // Create metal mine let mAngle = bbAngle; while (abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); let mDist = 12; let mX = round(fx + mDist * cos(mAngle)); let mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1, 1, 0, 0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // Create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1, 1, 0, 2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // Create starting trees, should avoid mines and bushes let tries = 50; let tDist = 16; let num = 50; for (let x = 0; x < tries; ++x) { let tAngle = randFloat(0, TWO_PI); let tX = round(fx + tDist * cos(tAngle)); let tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oTree2, num, num, 0, 7)], true, clBaseResource, tX, tZ ); if (createObjectGroup(group, 0, avoidClasses(clBaseResource, 5))) break; } placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(40); // Create central island placer = new ChainPlacer(floor(scaleByMapSize(6, 6)), floor(scaleByMapSize(10, 15)), floor(scaleByMapSize(200, 300)), 1, centerOfMap, centerOfMap, 0, [floor(mapSize * 0.01)]); terrainPainter = new LayeredPainter( [tShore, tMainTerrain], // terrains [shoreRadius, 100] // widths ); elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type elevation, // elevation shoreRadius // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 40)); -let randMountains = 20 + randInt(15); -for (let m = 0; m < randMountains; ++m) +for (let m = 0; m < randIntInclusive(20, 34); ++m) { - let randX = randInt(mapSize); - let randY = randInt(mapSize); - let placer = new ChainPlacer(floor(scaleByMapSize(7, 7)), floor(scaleByMapSize(15, 15)), floor(scaleByMapSize(15, 20)), 1, randX, randY, 0, [floor(mapSize * 0.01)]); - let elevRand = 6 + randInt(15); + let placer = new ChainPlacer( + Math.floor(scaleByMapSize(7, 7)), + Math.floor(scaleByMapSize(15, 15)), + Math.floor(scaleByMapSize(15, 20)), + 1, + randIntExclusive(0, mapSize), + randIntExclusive(0, mapSize), + 0, + [Math.floor(mapSize * 0.01)]); + + let elevRand = randIntInclusive(6, 20); let terrainPainter = new LayeredPainter( [tDirt, tHill], // terrains [floor(elevRand / 3), 40] // widths ); let elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type elevRand, // elevation floor(elevRand / 3) // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); } -randMountains = 8 + randInt(10); -for (let m = 0; m < randMountains; ++m) +for (let m = 0; m < randIntInclusive(8, 17); ++m) { - let randX = randInt(mapSize); - let randY = randInt(mapSize); - let placer = new ChainPlacer(floor(scaleByMapSize(5, 5)), floor(scaleByMapSize(8, 8)), floor(scaleByMapSize(15, 20)), 1, randX, randY, 0, [floor(mapSize * 0.01)]); - let elevRand = 15 + randInt(15); + let placer = new ChainPlacer( + Math.floor(scaleByMapSize(5, 5)), + Math.floor(scaleByMapSize(8, 8)), + Math.floor(scaleByMapSize(15, 20)), + 1, + randIntExclusive(0, mapSize), + randIntExclusive(0, mapSize), + 0, + [Math.floor(mapSize * 0.01)]); + + let elevRand = randIntInclusive(15, 29); let terrainPainter = new LayeredPainter( [tCliff, tForestFloor2], // terrains [floor(elevRand / 3), 40] // widths ); let elevationPainter = new SmoothElevationPainter( ELEVATION_MODIFY, // type elevRand, // elevation floor(elevRand / 3) // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clMountain)], [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); } // Create center bounty let group = new SimpleGroup( [new SimpleObject(oMetalLarge, 3, 6, 25, floor(mapSize * 0.25))], true, clBaseResource, centerOfMap, centerOfMap ); createObjectGroup(group, 0, [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 3, 6, 25, floor(mapSize * 0.25))], true, clBaseResource, centerOfMap, centerOfMap ); createObjectGroup(group, 0, [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); group = new SimpleGroup( [new SimpleObject(oMainHuntableAnimal, floor(6 * numPlayers), floor(6 * numPlayers), 2, floor(mapSize * 0.1))], true, clBaseResource, centerOfMap, centerOfMap ); createObjectGroup(group, 0, [avoidClasses(clBaseResource, 2, clMountain, 4, clPlayer, 40, clWater, 2), stayClasses(clHill, 10)]); log("Creating fish..."); group = new SimpleGroup( [new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clHill, 10, clFood, 20), 10 * numPlayers, 60 ); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], [avoidClasses(clPlayer, 25, clForest, 10, clBaseResource, 3, clMetal, 6, clRock, 3, clMountain, 2), stayClasses(clHill, 6)], clForest, 0.7, random_terrain ); log("Creating straggeler trees..."); let types = [oTree1, oTree2, oTree4, oTree3]; createStragglerTrees(types, [avoidClasses(clBaseResource, 2, clMetal, 6, clRock, 3, clMountain, 2, clPlayer, 25), stayClasses(clHill, 6)]); RMS.SetProgress(65); log("Creating dirt patches..."); let sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; let numb = random_terrain == g_BiomeSavanna ? 3 : 1; for (let i = 0; i < sizes.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); let painter = new LayeredPainter( [[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], // terrains [1, 1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), numb * scaleByMapSize(15, 45) ); } log("Painting shorelines..."); paintTerrainBasedOnHeight(1, 2, 0, tMainTerrain); paintTerrainBasedOnHeight(getMapBaseHeight(), 1, 3, tTier1Terrain); log("Creating grass patches..."); sizes = [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]; for (let i = 0; i < sizes.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); let painter = new TerrainPainter(tTier4Terrain); createAreas( placer, painter, avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), numb * scaleByMapSize(15, 45) ); } log("Creating food..."); createFood( [ [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] ], [3 * numPlayers, 3 * numPlayers], [avoidClasses(clForest, 0, clPlayer, 20, clMountain, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clHill, 2)] ); RMS.SetProgress(75); createFood( [ [new SimpleObject(oFruitBush, 5, 7, 0, 4)] ], [3 * numPlayers], [avoidClasses(clForest, 0, clPlayer, 15, clMountain, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clHill, 2)] ); RMS.SetProgress(85); log("Creating more straggeler trees..."); createStragglerTrees(types, avoidClasses(clWater, 5, clForest, 7, clMountain, 1, clPlayer, 30, clMetal, 6, clRock, 3)); log("Creating decoration..."); let planetm = random_terrain == g_BiomeTropic ? 8 : 1; 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, 2, 15, 0, 1, -PI/8, PI/8)], [new SimpleObject(aGrass, 2, 10, 0, 1.8, -PI/8, PI/8), new SimpleObject(aGrassShort, 3, 10, 1.2, 2.5, -PI/8, PI/8)], [new SimpleObject(aBushMedium, 1, 5, 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, 2, clPlayer, 20, clMountain, 5, clFood, 1, clBaseResource, 2) ); log("Creating water forests..."); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], avoidClasses(clPlayer, 30, clHill, 10, clFood, 5), clForest, 0.1, random_terrain ); log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1, 2, 0, 1, -PI / 8, PI / 8)] ); createObjectGroups(group, 0, [avoidClasses(clMountain, 2, clPlayer, 2, clDirt, 0), stayClasses(clHill, 8)], planetm * scaleByMapSize(13, 200) ); setSkySet(pickRandom(["cloudless", "cumulus", "overcast"])); setWaterMurkiness(0.4); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/fortress.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/fortress.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/fortress.js (revision 19443) @@ -1,371 +1,371 @@ RMS.LoadLibrary("rmgen"); // terrain textures const tGrass = ["temp_grass_aut", "temp_grass_aut", "temp_grass_d_aut"]; const tForestFloor = "temp_grass_aut"; const tGrassA = "temp_grass_plants_aut"; const tGrassB = "temp_grass_b_aut"; const tGrassC = "temp_grass_c_aut"; const tDirt = ["temp_plants_bog_aut", "temp_mud_a"]; const tHill = ["temp_highlands_aut", "temp_grass_long_b_aut"]; const tCliff = ["temp_cliff_a", "temp_cliff_b"]; const tRoad = "temp_road_aut"; const tRoadWild = "temp_road_overgrown_aut"; const tGrassPatch = "temp_grass_plants_aut"; const tShoreBlend = "temp_grass_plants_aut"; const tShore = "temp_plants_bog_aut"; const tWater = "temp_mud_a"; // gaia entities const oBeech = "gaia/flora_tree_euro_beech_aut"; const oOak = "gaia/flora_tree_oak_aut"; const oPine = "gaia/flora_tree_pine"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oSheep = "gaia/fauna_rabbit"; const oBerryBush = "gaia/flora_bush_berry"; const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; const oStoneSmall = "gaia/geology_stone_temperate"; const oMetalLarge = "gaia/geology_metal_temperate_slabs"; const oWood = "gaia/special_treasure_wood"; const oFood = "gaia/special_treasure_food_bin"; const oMetal = "gaia/special_treasure_metal"; const oStone = "gaia/special_treasure_stone"; // decorative props const aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; const aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; const aRockLarge = "actor|geology/stone_granite_med.xml"; const aRockMedium = "actor|geology/stone_granite_med.xml"; const aReeds = "actor|props/flora/reeds_pond_dry.xml"; const aLillies = "actor|props/flora/water_lillies.xml"; const aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oBeech, tForestFloor]; const pForestO = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor]; const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var baseRadius = 30; var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = mapSize*(0.5 + 0.35*cos(playerAngle[i])); playerZ[i] = mapSize*(0.5 + 0.35*sin(playerAngle[i])); } for (var i=0; i < numPlayers; i++) { var startEntities = getStartingEntities(i); // Place starting entities createStartingPlayerEntities(playerX[i], playerZ[i], i+1, startEntities); var uDist = 8; var uSpace = 2; for (var j = 1; j < startEntities.length - 1; ++j) { var uAngle = BUILDING_ORIENTATION - PI * (2-j) / 2; var count = (startEntities[j].Count !== undefined ? startEntities[j].Count : 1); for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = playerX[i] + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = playerZ[i] + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); placeObject(ux, uz, startEntities[j].Template, i+1, uAngle); } } // Create treasure var bbAngle = BUILDING_ORIENTATION; var bbDist = 10; var bbX = round(playerX[i] + bbDist * cos(bbAngle)); var bbZ = round(playerZ[i] + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oFood, 5,5, 0,2)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); bbAngle += PI/2; var bbX = round(playerX[i] + bbDist * cos(bbAngle)); var bbZ = round(playerZ[i] + bbDist * sin(bbAngle)); group = new SimpleGroup( [new SimpleObject(oWood, 5,5, 0,2)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); bbAngle += PI/2; var bbX = round(playerX[i] + bbDist * cos(bbAngle)); var bbZ = round(playerZ[i] + bbDist * sin(bbAngle)); group = new SimpleGroup( [new SimpleObject(oMetal, 3,3, 0,2)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); bbAngle += PI/2; var bbX = round(playerX[i] + bbDist * cos(bbAngle)); var bbZ = round(playerZ[i] + bbDist * sin(bbAngle)); group = new SimpleGroup( [new SimpleObject(oStone, 2,2, 0,2)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // Base texture var civ = getCivCode(i); var tilesSize = civ == "cart" ? 27 : 22; const minBoundX = (playerX[i] > tilesSize ? playerX[i] - tilesSize : 0); const minBoundY = (playerZ[i] > tilesSize ? playerZ[i] - tilesSize : 0); const maxBoundX = (playerX[i] < mapSize - tilesSize ? playerX[i] + tilesSize : mapSize); const maxBoundY = (playerZ[i] < mapSize - tilesSize ? playerZ[i] + tilesSize : mapSize); for (var tx = minBoundX; tx < maxBoundX; ++tx) for (var ty = minBoundY; ty < maxBoundY; ++ty) { var unboundSumOfXY = tx + ty - minBoundX - minBoundY; if ((unboundSumOfXY > tilesSize) && (unboundSumOfXY < 3 * tilesSize) && (tx - ty + minBoundY - minBoundX < tilesSize) && (ty - tx - minBoundY + minBoundX < tilesSize)) { placeTerrain(floor(tx), floor(ty), tRoad); addToClass(floor(tx), floor(ty), clPlayer); } } // Place custom fortress if (civ == "brit" || civ == "gaul" || civ == "iber") { var wall = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "barracks", "tower", "wallLong", "tower", "house", "wallLong", "cornerIn", "wallLong", "house", "tower", "gate", "tower", "house", "wallLong", "cornerIn", "wallLong", "house", "tower", "wallLong", "tower", "house", "wallLong", "cornerIn", "wallLong", "house", "tower"]; } else { var wall = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "barracks", "tower", "wallLong", "tower", "wallLong", "cornerIn", "wallLong", "house", "tower", "gate", "tower", "wallLong", "cornerIn", "wallLong", "house", "tower", "wallLong", "tower", "wallLong", "cornerIn", "wallLong", "house", "tower"]; } placeCustomFortress(playerX[i], playerZ[i], new Fortress("Spahbod", wall), civ, i+1); } log("Creating lakes..."); var numLakes = round(scaleByMapSize(1,4) * numPlayers); var placer = new ClumpPlacer(scaleByMapSize(100,250), 0.8, 0.1, 10); var terrainPainter = new LayeredPainter( [tShore, tWater, tWater], // terrains [1,1] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -4, 3); var waterAreas = createAreas( placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 7, clWater, 20), numLakes ); RMS.SetProgress(15); log("Creating reeds..."); group = new SimpleGroup( [new SimpleObject(aReeds, 5,10, 0,4), new SimpleObject(aLillies, 0,1, 0,4)], true ); createObjectGroupsByAreas(group, 0, [borderClasses(clWater, 3, 0), stayClasses(clWater, 1)], numLakes, 100, waterAreas ); RMS.SetProgress(25); log("Creating fish..."); createObjectGroupsByAreas( new SimpleGroup( [new SimpleObject(oFish, 1,1, 0,1)], true, clFood ), 0, [stayClasses(clWater, 4), avoidClasses(clFood, 8)], numLakes / 4, 50, waterAreas ); RMS.SetProgress(30); createBumps(avoidClasses(clWater, 2, clPlayer, 5)); RMS.SetProgress(35); log("Creating hills..."); createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 5, clWater, 5, clHill, 15), clHill, scaleByMapSize(1, 4) * numPlayers); RMS.SetProgress(40); // calculate desired number of trees for map (based on size) const MIN_TREES = 500; const MAX_TREES = 2500; const P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; g_numStragglerTrees = totalTrees * (1.0 - P_FOREST); log("Creating forests..."); var types = [ [[tForestFloor, tGrass, pForestD], [tForestFloor, pForestD]], [[tForestFloor, tGrass, pForestO], [tForestFloor, pForestO]], [[tForestFloor, tGrass, pForestP], [tForestFloor, pForestP]] ]; // some variation var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / num, 0.5); var painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 5, clWater, 3, clForest, 15, clHill, 1), num ); } RMS.SetProgress(50); log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], [1,1], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 1) ); RMS.SetProgress(55); log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tGrassPatch, avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 1) ); RMS.SetProgress(60); log("Creating stone mines..."); createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clRock, 10, clHill, 1) ); RMS.SetProgress(65); log("Creating metal mines..."); createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clMetal, 10, clRock, 5, clHill, 1), clMetal ); RMS.SetProgress(70); 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), scaleByMapSize(13, 200), scaleByMapSize(13, 200), scaleByMapSize(13, 200) ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 1, clHill, 0) ); RMS.SetProgress(80); // create animals createFood ( [ [new SimpleObject(oSheep, 2,3, 0,2)], [new SimpleObject(oDeer, 5,7, 0,4)] ], [ 3 * numPlayers, 3 * numPlayers ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 6, clHill, 1, clFood, 20) ); RMS.SetProgress(85); // create fruits createFood ( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(1, 4) * numPlayers + 2 + randIntInclusive(1, 4) * numPlayers + 2 ], avoidClasses(clWater, 2, clForest, 0, clPlayer, 6, clHill, 1, clFood, 10) ); RMS.SetProgress(90); log("Creating straggler trees..."); var types = [oOak, oBeech, oPine]; // some variation createStragglerTrees(types, avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6)); RMS.SetProgress(95); setSkySet("sunny"); setWaterColor(0.157, 0.149, 0.443); setWaterTint(0.443,0.42,0.824); setWaterWaviness(2.0); setWaterType("lake"); setWaterMurkiness(0.83); setFogFactor(0.35); setFogThickness(0.22); setFogColor(0.82,0.82, 0.73); setPPSaturation(0.56); setPPContrast(0.56); setPPBloom(0.38); setPPEffect("hdr"); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/frontier.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/frontier.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/frontier.js (revision 19443) @@ -1,266 +1,266 @@ RMS.LoadLibrary("rmgen"); RMS.LoadLibrary("rmgen2"); InitMap(); randomizeBiome(); initMapSettings(); initTileClasses(); RMS.SetProgress(10); // Pick a random elevation with a bias towards lower elevations -var randElevation = randInt(30); +var randElevation = randIntInclusive(0, 29); if (randElevation < 25) - randElevation = 1 + randInt(4); + randElevation = randIntInclusive(1, 4); resetTerrain(g_Terrains.mainTerrain, g_TileClasses.land, randElevation); RMS.SetProgress(20); var pos = randomStartingPositionPattern(); addBases(pos.setup, pos.distance, pos.separation); RMS.SetProgress(40); var features = [ { "func": addBluffs, "avoid": [ g_TileClasses.bluff, 20, g_TileClasses.hill, 10, g_TileClasses.mountain, 20, g_TileClasses.plateau, 15, g_TileClasses.player, 30, g_TileClasses.valley, 5, g_TileClasses.water, 7 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addHills, "avoid": [ g_TileClasses.bluff, 5, g_TileClasses.hill, 15, g_TileClasses.mountain, 2, g_TileClasses.plateau, 15, g_TileClasses.player, 20, g_TileClasses.valley, 2, g_TileClasses.water, 2 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addMountains, "avoid": [ g_TileClasses.bluff, 20, g_TileClasses.mountain, 25, g_TileClasses.plateau, 15, g_TileClasses.player, 20, g_TileClasses.valley, 10, g_TileClasses.water, 15 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addPlateaus, "avoid": [ g_TileClasses.bluff, 20, g_TileClasses.mountain, 25, g_TileClasses.plateau, 25, g_TileClasses.plateau, 25, g_TileClasses.player, 40, g_TileClasses.valley, 10, g_TileClasses.water, 15 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts } ]; if (randElevation < 4) features.push({ "func": addLakes, "avoid": [ g_TileClasses.bluff, 7, g_TileClasses.hill, 2, g_TileClasses.mountain, 15, g_TileClasses.plateau, 10, g_TileClasses.player, 20, g_TileClasses.valley, 10, g_TileClasses.water, 25 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }); if (randElevation > 20) features.push({ "func": addValleys, "avoid": [ g_TileClasses.bluff, 5, g_TileClasses.hill, 5, g_TileClasses.mountain, 25, g_TileClasses.plateau, 20, g_TileClasses.player, 40, g_TileClasses.valley, 15, g_TileClasses.water, 10 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }); addElements(shuffleArray(features)); RMS.SetProgress(50); addElements([ { "func": addLayeredPatches, "avoid": [ g_TileClasses.bluff, 2, g_TileClasses.dirt, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 12, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addDecoration, "avoid": [ g_TileClasses.bluff, 2, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 12, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] } ]); RMS.SetProgress(60); addElements(shuffleArray([ { "func": addMetal, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 3, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 30, g_TileClasses.rock, 10, g_TileClasses.metal, 20, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["same"], "amounts": g_AllAmounts }, { "func": addStone, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 3, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 30, g_TileClasses.rock, 20, g_TileClasses.metal, 10, g_TileClasses.water, 3 ], "sizes": ["normal"], "mixes": ["same"], "amounts": g_AllAmounts }, { "func": addForests, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 18, g_TileClasses.metal, 3, g_TileClasses.mountain, 5, g_TileClasses.plateau, 5, g_TileClasses.player, 20, g_TileClasses.rock, 3, g_TileClasses.water, 2 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["few", "normal", "many", "tons"] } ])); RMS.SetProgress(70); addElements(shuffleArray([ { "func": addBerries, "avoid": [ g_TileClasses.berries, 30, g_TileClasses.bluff, 5, g_TileClasses.forest, 5, g_TileClasses.metal, 10, g_TileClasses.mountain, 2, g_TileClasses.plateau, 2, g_TileClasses.player, 20, g_TileClasses.rock, 10, g_TileClasses.water, 3 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addAnimals, "avoid": [ g_TileClasses.animals, 20, g_TileClasses.bluff, 5, g_TileClasses.forest, 2, g_TileClasses.metal, 2, g_TileClasses.mountain, 1, g_TileClasses.plateau, 2, g_TileClasses.player, 20, g_TileClasses.rock, 2, g_TileClasses.water, 3 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addStragglerTrees, "avoid": [ g_TileClasses.berries, 5, g_TileClasses.bluff, 5, g_TileClasses.forest, 7, g_TileClasses.metal, 2, g_TileClasses.mountain, 1, g_TileClasses.plateau, 2, g_TileClasses.player, 12, g_TileClasses.rock, 2, g_TileClasses.water, 5 ], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts } ])); RMS.SetProgress(90); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/guadalquivir_river.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/guadalquivir_river.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/guadalquivir_river.js (revision 19443) @@ -1,424 +1,424 @@ RMS.LoadLibrary("rmgen"); const tGrass = ["medit_grass_field_a", "medit_grass_field_b"];; const tForestFloorC = "medit_plants_dirt"; const tForestFloorP = "medit_grass_shrubs"; const tCliff = ["medit_cliff_grass", "medit_cliff_greek", "medit_cliff_greek_2", "medit_cliff_aegean", "medit_cliff_italia", "medit_cliff_italia_grass"]; const tGrassA = "medit_grass_field_b"; const tGrassB = "medit_grass_field_brown"; const tGrassC = "medit_grass_field_dry"; const tHill = ["medit_rocks_grass_shrubs", "medit_rocks_shrubs"]; const tDirt = ["medit_dirt", "medit_dirt_b"]; const tRoad = "medit_city_tile"; const tRoadWild = "medit_city_tile"; const tGrassPatch = "medit_grass_shrubs"; const tShoreBlend = "medit_sand"; const tShore = "sand_grass_25"; const tWater = "medit_sand_wet"; // gaia entities const oPoplar = "gaia/flora_tree_poplar"; const oApple = "gaia/flora_tree_apple"; const oCarob = "gaia/flora_tree_carob"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oSheep = "gaia/fauna_sheep"; const oStoneLarge = "gaia/geology_stonemine_medit_quarry"; const oStoneSmall = "gaia/geology_stone_mediterranean"; const oMetalLarge = "gaia/geology_metal_mediterranean_slabs"; // decorative props const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; const aGrassShort = "actor|props/flora/grass_soft_large.xml"; const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; const aLillies = "actor|props/flora/water_lillies.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.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; // terrain + entity (for painting) const pForestP = [tForestFloorP + TERRAIN_SEPARATOR + oPoplar, tForestFloorP]; const pForestC = [tForestFloorC + TERRAIN_SEPARATOR + oCarob, tForestFloorC]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clLand = createTileClass(); var clUpperLand = createTileClass(); var clRiver = createTileClass(); var clShallow = createTileClass(); //Create the continent body var fx = fractionToTiles(0.5); var fz = fractionToTiles(0.7); var ix = round(fx); var iz = round(fz); var placer = new RectPlacer(0, floor(mapSize * 0.70), mapSize - 1, mapSize - 1); var terrainPainter = new LayeredPainter( [tWater, tShore, tGrass], // terrains [4, 2] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clUpperLand)], null); var placer = new ChainPlacer(2, floor(scaleByMapSize(5, 12)), floor(scaleByMapSize(60, 700)), 1, ix, iz, 0, [floor(mapSize * 0.49)]); var terrainPainter = new LayeredPainter( [tGrass, tGrass, tGrass], // terrains [4, 2] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 3, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clLand)], null); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = primeSortPlayers(sortPlayers(playerIDs)); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = 0; for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle - 0.23*(i+(i%2))*TWO_PI/numPlayers - (i%2)*PI/2; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.7 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles fx = fractionToTiles(playerX[i]); fz = fractionToTiles(playerZ[i]); ix = round(fx); iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id, { 'iberWall': false }); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 8; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 10; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPoplar, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(20); const WATER_WIDTH = 0.07; log("Creating river"); var theta = randFloat(0, 1); var seed = randFloat(2,3); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); var h = 0; var distToWater = 0; h = 32 * (z - 0.5); // add the rough shape of the water var km = 12/scaleByMapSize(35, 160); var cu = km*rndRiver(theta+z*0.5*(mapSize/64),seed); var zk = z*randFloat(0.995,1.005); var xk = x*randFloat(0.995,1.005); if (-3.0 < getHeight(ix, iz)){ if ((xk > cu+((1.0-WATER_WIDTH)/2))&&(xk < cu+((1.0+WATER_WIDTH)/2))) { if (xk < cu+((1.05-WATER_WIDTH)/2)) { h = -3 + 200.0* abs(cu+((1.05-WATER_WIDTH)/2-xk)); if ((((zk>0.3)&&(zk<0.4))||((zk>0.5)&&(zk<0.6))||((zk>0.7)&&(zk<0.8)))&&(h<-1.5)) { h=-1.5; addToClass(ix, iz, clShallow); } } else if (xk > (cu+(0.95+WATER_WIDTH)/2)) { h = -3 + 200.0*(xk-(cu+((0.95+WATER_WIDTH)/2))); if ((((zk>0.3)&&(zk<0.4))||((zk>0.5)&&(zk<0.6))||((zk>0.7)&&(zk<0.8)))&&(h<-1.5)) { h=-1.5; addToClass(ix, iz, clShallow); } } else { if (((zk>0.3)&&(zk<0.4))||((zk>0.5)&&(zk<0.6))||((zk>0.7)&&(zk<0.8))){ h = -1.5; addToClass(ix, iz, clShallow); } else { h = -3.0; } } setHeight(ix, iz, h); addToClass(ix, iz, clRiver); placeTerrain(ix, iz, tWater); } } } } paintTerrainBasedOnHeight(1, 3, 0, tShore); paintTerrainBasedOnHeight(-8, 1, 2, tWater); // create bumps createBumps([avoidClasses(clPlayer, 20, clRiver, 1), stayClasses(clLand, 3)]); // create forests createForests( [tGrass, tForestFloorP, tForestFloorC, pForestC, pForestP], [avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clRiver, 1), stayClasses(clLand, 7)], clForest, 1.0, 0 ); RMS.SetProgress(50); // create dirt patches log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], [1,1], [avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 8, clRiver, 1), stayClasses(clLand, 7)] ); // create grass patches log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tGrassPatch, [avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 8, clRiver, 1), stayClasses(clLand, 7)] ); RMS.SetProgress(55); log("Creating stone mines..."); // create stone quarries createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], [avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1, clRiver, 1), stayClasses(clLand, 5)] ); log("Creating metal mines..."); // create large metal quarries createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], [avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1, clRiver, 1), stayClasses(clLand, 5)], clMetal ); RMS.SetProgress(65); // create decoration 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), scaleByMapSize(13, 200), scaleByMapSize(13, 200), scaleByMapSize(13, 200) ], [avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1, clRiver, 1), stayClasses(clLand, 6)] ); // create water decoration in the shallow parts createDecoration ( [[new SimpleObject(aReeds, 1,3, 0,1)], [new SimpleObject(aLillies, 1,2, 0,1)] ], [ scaleByMapSize(800, 12800), scaleByMapSize(800, 12800) ], stayClasses(clShallow, 0) ); RMS.SetProgress(70); // create animals createFood ( [ [new SimpleObject(oDeer, 5,7, 0,4)], [new SimpleObject(oSheep, 2,3, 0,2)] ], [ 3 * numPlayers, 3 * numPlayers ], [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20, clRiver, 1), stayClasses(clLand, 3)] ); // create fruits createFood ( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(1, 4) * numPlayers + 2 + randIntInclusive(1, 4) * numPlayers + 2 ], [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10, clRiver, 1), stayClasses(clLand, 3)] ); // create fish createFood ( [ [new SimpleObject(oFish, 2,3, 0,2)] ], [ 25 * numPlayers ], avoidClasses(clLand, 2, clRiver, 1) ); RMS.SetProgress(85); // create straggler trees log("Creating straggler trees..."); var types = [oPoplar, oCarob, oApple]; // some variation createStragglerTrees(types, [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6, clRiver, 1), stayClasses(clLand, 7)]); setSkySet("cumulus"); setWaterColor(0.2,0.312,0.522); setWaterTint(0.1,0.1,0.8); setWaterWaviness(4.0); setWaterType("lake"); setWaterMurkiness(0.73); setFogFactor(0.3); setFogThickness(0.25); setPPEffect("hdr"); setPPContrast(0.62); setPPSaturation(0.51); setPPBloom(0.12); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/gulf_of_bothnia.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/gulf_of_bothnia.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/gulf_of_bothnia.js (revision 19443) @@ -1,495 +1,495 @@ RMS.LoadLibrary("rmgen"); TILE_CENTERED_HEIGHT_MAP = true; -var random_terrain = randInt(1,3); +var random_terrain = randIntInclusive(1, 3); if (random_terrain == 1) { setFogThickness(0.26); setFogFactor(0.4); setPPEffect("hdr"); setPPSaturation(0.48); setPPContrast(0.53); setPPBloom(0.12); var tPrimary = ["alpine_dirt_grass_50"]; var tForestFloor = "alpine_forrestfloor"; var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; var tSecondary = "alpine_grass_rocky"; var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; var tSnowLimited = ["alpine_snow_rocky"]; var tDirt = "alpine_dirt"; var tRoad = "new_alpine_citytile"; var tRoadWild = "new_alpine_citytile"; var tShore = "alpine_shore_rocks_grass_50"; var tWater = "alpine_shore_rocks"; // gaia entities var oPine = "gaia/flora_tree_pine"; var oBerryBush = "gaia/flora_bush_berry"; var oDeer = "gaia/fauna_deer"; var oFish = "gaia/fauna_fish"; var oRabbit = "gaia/fauna_rabbit"; var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; var oStoneSmall = "gaia/geology_stone_alpine_a"; var oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props var aGrass = "actor|props/flora/grass_soft_small_tall.xml"; var aGrassShort = "actor|props/flora/grass_soft_large.xml"; var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; var aBushMedium = "actor|props/flora/bush_medit_me.xml"; var aBushSmall = "actor|props/flora/bush_medit_sm.xml"; } else if (random_terrain == 2) { setFogFactor(0.35); setFogThickness(0.19); setPPSaturation(0.37); setPPEffect("hdr"); var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; var tForestFloor = "alpine_forrestfloor_snow"; var tCliff = ["alpine_cliff_snow"]; var tSecondary = "alpine_grass_snow_50"; var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; var tDirt = "alpine_dirt"; var tRoad = "new_alpine_citytile"; var tRoadWild = "new_alpine_citytile"; var tShore = "alpine_shore_rocks_icy"; var tWater = "alpine_shore_rocks"; // gaia entities var oPine = "gaia/flora_tree_pine_w"; var oBerryBush = "gaia/flora_bush_berry"; var oDeer = "gaia/fauna_deer"; var oFish = "gaia/fauna_fish"; var oRabbit = "gaia/fauna_rabbit"; var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; var oStoneSmall = "gaia/geology_stone_alpine_a"; var oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; var aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; var aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; } else { setFogFactor(0.41); setFogThickness(0.23); setPPSaturation(0.34); setPPEffect("hdr"); var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; var tForestFloor = "alpine_snow_a"; var tCliff = ["alpine_cliff_snow"]; var tSecondary = "polar_ice_snow"; var tHalfSnow = ["polar_ice_cracked"]; var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; var tDirt = "alpine_dirt"; var tRoad = "new_alpine_citytile"; var tRoadWild = "new_alpine_citytile"; var tShore = "polar_ice_snow"; var tWater = ["polar_ice_snow", "polar_ice"]; // gaia entities var oPine = "gaia/flora_tree_pine_w"; var oBerryBush = "gaia/flora_bush_berry"; var oDeer = "gaia/fauna_deer"; var oFish = "gaia/fauna_fish"; var oRabbit = "gaia/fauna_rabbit"; var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; var oStoneSmall = "gaia/geology_stone_alpine_a"; var oMetalLarge = "gaia/geology_metal_alpine_slabs"; // decorative props var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; var aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; var aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; } const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); placeTerrain(ix, iz, tPrimary); } } // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = -PI/6; for (var i = 0; i < numPlayers; i++) { if (numPlayers == 1) playerAngle[i] = startAngle + TWO_PI/3; else playerAngle[i] = startAngle + i*TWO_PI/(numPlayers-1)*2/3; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); ix = round(fx); iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPine, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(20); //create the gulf if (random_terrain == 3) { var seaHeight = 0; } else { var seaHeight = -3; } //create the upper part var fx = fractionToTiles(0.5); var fz = fractionToTiles(0.5); ix = round(fx); iz = round(fz); var lSize = 1; var placer = new ChainPlacer(2, floor(scaleByMapSize(5, 16)), floor(scaleByMapSize(35, 200)), 1, ix, iz, 0, [floor(mapSize * 0.17 * lSize)]); var terrainPainter = new LayeredPainter( [tPrimary, tPrimary, tPrimary, tPrimary], // terrains [1, 4, 2] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type seaHeight, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer,scaleByMapSize(20,28))); //the middle part var fx = fractionToTiles(0.5); var fz = fractionToTiles(0.3); ix = round(fx); iz = round(fz); var lSize = sqrt(sqrt(sqrt(scaleByMapSize(1, 6)))); var placer = new ChainPlacer(2, floor(scaleByMapSize(5, 16)), floor(scaleByMapSize(35, 120)), 1, ix, iz, 0, [floor(mapSize * 0.18 * lSize)]); var terrainPainter = new LayeredPainter( [tPrimary, tPrimary, tPrimary, tPrimary], // terrains [1, 4, 2] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type seaHeight, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer,scaleByMapSize(20,28))); //the lower part var fx = fractionToTiles(0.5); var fz = 0; ix = round(fx); iz = round(fz)+1; var lSize = sqrt(sqrt(sqrt(scaleByMapSize(1, 6)))); var placer = new ChainPlacer(2, floor(scaleByMapSize(5, 16)), floor(scaleByMapSize(35, 100)), 1, ix, iz, 0, [floor(mapSize * 0.19 * lSize)]); var terrainPainter = new LayeredPainter( [tPrimary, tPrimary, tPrimary, tPrimary], // terrains [1, 4, 2] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type seaHeight, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer,scaleByMapSize(20,28))); if (random_terrain == 3) { paintTerrainBasedOnHeight(2, 3, 0, tShore); paintTerrainBasedOnHeight(-1, 2, 2, tWater); } else { paintTerrainBasedOnHeight(1, 3, 0, tShore); paintTerrainBasedOnHeight(-8, 1, 2, tWater); } // create bumps createBumps(avoidClasses(clWater, 2, clPlayer, 10)); // create hills if (randBool()) createHills([tPrimary, tCliff, tPrimary], avoidClasses(clPlayer, 20, clHill, 15, clWater, 0), clHill, scaleByMapSize(1, 4) * numPlayers); else createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15, clWater, 0), clHill, scaleByMapSize(1, 4) * numPlayers); // create forests createForests( [tPrimary, tForestFloor, tForestFloor, pForest, pForest], avoidClasses(clPlayer, 20, clForest, 16, clHill, 0, clWater, 2), clForest, 1.0, random_terrain ); RMS.SetProgress(60); // create dirt patches log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tPrimary,tSecondary],[tSecondary,tHalfSnow], [tHalfSnow,tSnowLimited]], [1,1], avoidClasses(clWater, 6, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12) ); // create grass patches log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tHalfSnow, avoidClasses(clWater, 6, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12) ); RMS.SetProgress(65); log("Creating stone mines..."); // create stone quarries createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1) ); log("Creating metal mines..."); // create large metal quarries createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), clMetal ); RMS.SetProgress(70); // create decoration var multiplier = 0; if (random_terrain !== 3) multiplier = 1; 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, -PI/8,PI/8)], [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)], [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), multiplier * scaleByMapSize(13, 200), multiplier * scaleByMapSize(13, 200), multiplier * scaleByMapSize(13, 200) ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0) ); RMS.SetProgress(75); // create animals createFood ( [ [new SimpleObject(oDeer, 5,7, 0,4)], [new SimpleObject(oRabbit, 2,3, 0,2)] ], [ 3 * numPlayers, 3 * numPlayers ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20) ); // create fruits createFood ( [ [new SimpleObject(oBerryBush, 5,7, 0,4)] ], [ - randInt(1, 4) * numPlayers + 2 + randIntInclusive(1, 4) * numPlayers + 2 ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10) ); if (random_terrain !== 3) { // create fish createFood ( [ [new SimpleObject(oFish, 2,3, 0,2)] ], [ 25 * numPlayers ], [avoidClasses(clFood, 20), stayClasses(clWater, 6)] ); } RMS.SetProgress(85); // create straggler trees log("Creating straggler trees..."); var types = [oPine]; createStragglerTrees(types, avoidClasses(clWater, 3, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6)); setSkySet("stormy"); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 6, PI / 4)); setWaterColor(0.035,0.098,0.314); setWaterTint(0.28, 0.3, 0.59); setWaterWaviness(5.0); setWaterType("lake"); setWaterMurkiness(0.88); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/heightmap/heightmap.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/heightmap/heightmap.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/heightmap/heightmap.js (revision 19443) @@ -1,338 +1,338 @@ /** * Heightmap manipulation functionality * * A heightmapt is an array of width arrays of height floats * Width and height is normally mapSize+1 (Number of vertices is one bigger than number of tiles in each direction) * The default heightmap is g_Map.height (See the Map object) * * @warning - Ambiguous naming and potential confusion: * To use this library use TILE_CENTERED_HEIGHT_MAP = false (default) * Otherwise TILE_CENTERED_HEIGHT_MAP has nothing to do with any tile centered map in this library * @todo - TILE_CENTERED_HEIGHT_MAP should be removed and g_Map.height should never be tile centered */ /** * Get the height range of a heightmap * @param {array} [heightmap=g_Map.height] - The reliefmap the minimum and maximum height should be determined for * @return {object} [height] - Height range with 2 floats in properties "min" and "max" */ function getMinAndMaxHeight(heightmap = g_Map.height) { let height = {}; height.min = Infinity; height.max = - Infinity; for (let x = 0; x < heightmap.length; ++x) { for (let y = 0; y < heightmap[x].length; ++y) { if (heightmap[x][y] < height.min) height.min = heightmap[x][y]; else if (heightmap[x][y] > height.max) height.max = heightmap[x][y]; } } return height; } /** * Rescales a heightmap so its minimum and maximum height is as the arguments told preserving it's global shape * @param {float} [minHeight=MIN_HEIGHT] - Minimum height that should be used for the resulting heightmap * @param {float} [maxHeight=MAX_HEIGHT] - Maximum height that should be used for the resulting heightmap * @param {array} [heightmap=g_Map.height] - A reliefmap * @todo Add preserveCostline to leave a certain height untoucht and scale below and above that seperately */ function rescaleHeightmap(minHeight = MIN_HEIGHT, maxHeight = MAX_HEIGHT, heightmap = g_Map.height) { let oldHeightRange = getMinAndMaxHeight(heightmap); let max_x = heightmap.length; let max_y = heightmap[0].length; for (let x = 0; x < max_x; ++x) for (let y = 0; y < max_y; ++y) heightmap[x][y] = minHeight + (heightmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight); } /** * Get start location with the largest minimum distance between players * @param {array} [heightRange] - The height range start locations are allowed * @param {integer} [maxTries=1000] - How often random player distributions are rolled to be compared * @param {float} [minDistToBorder=20] - How far start locations have to be away from the map border * @param {integer} [numberOfPlayers=g_MapSettings.PlayerData.length] - How many start locations should be placed * @param {array} [heightmap=g_Map.height] - The reliefmap for the start locations to be placed on * @param {boolean} [isCircular=g_MapSettings.CircularMap] - If the map is circular or rectangular * @return {array} [finalStartLoc] - Array of 2D points in the format { "x": float, "y": float} */ function getStartLocationsByHeightmap(heightRange, maxTries = 1000, minDistToBorder = 20, numberOfPlayers = g_MapSettings.PlayerData.length - 1, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap) { let validStartLoc = []; let r = 0.5 * (heightmap.length - 1); // Map center x/y as well as radius for (let x = minDistToBorder; x < heightmap.length - minDistToBorder; ++x) for (let y = minDistToBorder; y < heightmap[0].length - minDistToBorder; ++y) if (heightmap[x][y] > heightRange.min && heightmap[x][y] < heightRange.max) // Is in height range if (!isCircular || r - getDistance(x, y, r, r) >= minDistToBorder) // Is far enough away from map border validStartLoc.push({ "x": x, "y": y }); let maxMinDist = 0; let finalStartLoc; for (let tries = 0; tries < maxTries; ++tries) { let startLoc = []; let minDist = Infinity; for (let p = 0; p < numberOfPlayers; ++p) startLoc.push(pickRandom(validStartLoc)); for (let p1 = 0; p1 < numberOfPlayers - 1; ++p1) { for (let p2 = p1 + 1; p2 < numberOfPlayers; ++p2) { let dist = getDistance(startLoc[p1].x, startLoc[p1].y, startLoc[p2].x, startLoc[p2].y); if (dist < minDist) minDist = dist; } } if (minDist > maxMinDist) { maxMinDist = minDist; finalStartLoc = startLoc; } } return finalStartLoc; } /** * Meant to place e.g. resource spots within a height range * @param {array} [heightRange] - The height range in which to place the entities (An associative array with keys "min" and "max" each containing a float) * @param {array} [avoidPoints] - An array of 2D points (arrays of length 2), points that will be avoided in the given minDistance e.g. start locations * @param {number} [minDistance=30] - How many tile widths the entities to place have to be away from each other, start locations and the map border * @param {array} [heightmap=g_Map.height] - The reliefmap the entities should be distributed on * @param {array} [entityList=[g_Gaia.stoneLarge, g_Gaia.metalLarge]] - Entity/actor strings to be placed with placeObject() * @param {number} [playerID=0] - Index of the player the entities should be placed for. Gaia is 0. * @param {number} [maxTries=1000] - How often random player distributions are rolled to be compared * @param {boolean} [isCircular=g_MapSettings.CircularMap] - If the map is circular or rectangular * @return {array} [placements] Array of points where entities were placed */ function distributeEntitiesByHeight(heightRange, avoidPoints, minDistance = 30, entityList = [g_Gaia.stoneLarge, g_Gaia.metalLarge], playerID = 0, maxTries = 1000, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap) { let validPoints = []; let r = 0.5 * (heightmap.length - 1); // Map center x/y as well as radius for (let x = minDistance; x < heightmap.length - minDistance; ++x) { for (let y = minDistance; y < heightmap[0].length - minDistance; ++y) { if (heightmap[x][y] < heightRange.min || heightmap[x][y] > heightRange.max) continue; // Out of height range let checkpoint = { "x" : x + 0.5, "y" : y + 0.5 }; if (isCircular && r - getDistance(checkpoint.x, checkpoint.y, r, r) < minDistance) continue; // Too close to map border // Avoid points by minDistance, else add to validPoints if (avoidPoints.every(ap => getDistance(checkpoint.x, checkpoint.y, ap.x, ap.y) > minDistance)) validPoints.push(checkpoint); } } let placements = []; if (!validPoints.length) { log("No placement points found for the given arguments (entityList=" + uneval(entityList) + "):\n" + new Error().stack); return placements; } for (let tries = 0; tries < maxTries; ++tries) { - let checkPointIndex = randInt(validPoints.length); + let checkPointIndex = randIntExclusive(0, validPoints.length); let checkPoint = validPoints[checkPointIndex]; if (placements.every(p => getDistance(p.x, p.y, checkPoint.x, checkPoint.y) > minDistance)) { placeObject(checkPoint.x, checkPoint.y, pickRandom(entityList), playerID, randFloat(0, 2*PI)); placements.push(checkPoint); } validPoints.splice(checkPointIndex); if (!validPoints.length) break; // No more valid points left } if (!placements.length) log("Nothing was placed:\n" + new Error().stack); return placements; } /** * Sets a given heightmap to entirely random values within a given range * @param {float} [minHeight=MIN_HEIGHT] - Lower limit of the random height to be rolled * @param {float} [maxHeight=MAX_HEIGHT] - Upper limit of the random height to be rolled * @param {array} [heightmap=g_Map.height] - The reliefmap that should be randomized */ function setRandomHeightmap(minHeight = MIN_HEIGHT, maxHeight = MAX_HEIGHT, heightmap = g_Map.height) { for (let x = 0; x < heightmap.length; ++x) for (let y = 0; y < heightmap[0].length; ++y) heightmap[x][y] = randFloat(minHeight, maxHeight); } /** * Sets the heightmap to a relatively realistic shape * The function doubles the size of the initial heightmap (if given, else a random 2x2 one) until it's big enough, then the extend is cut off * @note min/maxHeight will not necessarily be present in the heightmap * @note On circular maps the edges (given by initialHeightmap) may not be in the playable map area * @note The impact of the initial heightmap depends on its size and target map size * @param {float} [minHeight=MIN_HEIGHT] - Lower limit of the random height to be rolled * @param {float} [maxHeight=MAX_HEIGHT] - Upper limit of the random height to be rolled * @param {array} [initialHeightmap] - Optional, Small (e.g. 3x3) heightmap describing the global shape of the map e.g. an island [[MIN_HEIGHT, MIN_HEIGHT, MIN_HEIGHT], [MIN_HEIGHT, MAX_HEIGHT, MIN_HEIGHT], [MIN_HEIGHT, MIN_HEIGHT, MIN_HEIGHT]] * @param {float} [smoothness=0.5] - Float between 0 (rough, more local structures) to 1 (smoother, only larger scale structures) * @param {array} [heightmap=g_Map.height] - The reliefmap that will be set by this function */ function setBaseTerrainDiamondSquare(minHeight = MIN_HEIGHT, maxHeight = MAX_HEIGHT, initialHeightmap = undefined, smoothness = 0.5, heightmap = g_Map.height) { initialHeightmap = (initialHeightmap || [[randFloat(minHeight / 2, maxHeight / 2), randFloat(minHeight / 2, maxHeight / 2)], [randFloat(minHeight / 2, maxHeight / 2), randFloat(minHeight / 2, maxHeight / 2)]]); let heightRange = maxHeight - minHeight; if (heightRange <= 0) warn("setBaseTerrainDiamondSquare: heightRange <= 0"); let offset = heightRange / 2; // Double initialHeightmap width until target width is reached (diamond square method) let newHeightmap = []; while (initialHeightmap.length < heightmap.length) { newHeightmap = []; let oldWidth = initialHeightmap.length; // Square for (let x = 0; x < 2 * oldWidth - 1; ++x) { newHeightmap.push([]); for (let y = 0; y < 2 * oldWidth - 1; ++y) { if (x % 2 == 0 && y % 2 == 0) // Old tile newHeightmap[x].push(initialHeightmap[x/2][y/2]); else if (x % 2 == 1 && y % 2 == 1) // New tile with diagonal old tile neighbors { newHeightmap[x].push((initialHeightmap[(x-1)/2][(y-1)/2] + initialHeightmap[(x+1)/2][(y-1)/2] + initialHeightmap[(x-1)/2][(y+1)/2] + initialHeightmap[(x+1)/2][(y+1)/2]) / 4); newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset); } else // New tile with straight old tile neighbors newHeightmap[x].push(undefined); // Define later } } // Diamond for (let x = 0; x < 2 * oldWidth - 1; ++x) { for (let y = 0; y < 2 * oldWidth - 1; ++y) { if (newHeightmap[x][y] !== undefined) continue; if (x > 0 && x + 1 < newHeightmap.length - 1 && y > 0 && y + 1 < newHeightmap.length - 1) // Not a border tile { newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x][y+1] + newHeightmap[x-1][y] + newHeightmap[x][y-1]) / 4; newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset); } else if (x < newHeightmap.length - 1 && y > 0 && y < newHeightmap.length - 1) // Left border { newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x][y+1] + newHeightmap[x][y-1]) / 3; newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset); } else if (x > 0 && y > 0 && y < newHeightmap.length - 1) // Right border { newHeightmap[x][y] = (newHeightmap[x][y+1] + newHeightmap[x-1][y] + newHeightmap[x][y-1]) / 3; newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset); } else if (x > 0 && x < newHeightmap.length - 1 && y < newHeightmap.length - 1) // Bottom border { newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x][y+1] + newHeightmap[x-1][y]) / 3; newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset); } else if (x > 0 && x < newHeightmap.length - 1 && y > 0) // Top border { newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x-1][y] + newHeightmap[x][y-1]) / 3; newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset); } } } initialHeightmap = deepcopy(newHeightmap); offset /= Math.pow(2, smoothness); } // Cut initialHeightmap to fit target width let shift = [floor((newHeightmap.length - heightmap.length) / 2), floor((newHeightmap[0].length - heightmap[0].length) / 2)]; for (let x = 0; x < heightmap.length; ++x) for (let y = 0; y < heightmap[0].length; ++y) heightmap[x][y] = newHeightmap[x + shift[0]][y + shift[1]]; } /** * Smoothens the entire map * @param {float} [strength=0.8] - How strong the smooth effect should be: 0 means no effect at all, 1 means quite strong, higher values might cause interferences, better apply it multiple times * @param {array} [heightmap=g_Map.height] - The heightmap to be smoothed * @param {array} [smoothMap=[[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]] - Array of offsets discribing the neighborhood tiles to smooth the height of a tile to */ function globalSmoothHeightmap(strength = 0.8, heightmap = g_Map.height, smoothMap = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]) { let referenceHeightmap = deepcopy(heightmap); let max_x = heightmap.length; let max_y = heightmap[0].length; for (let x = 0; x < max_x; ++x) { for (let y = 0; y < max_y; ++y) { for (let i = 0; i < smoothMap.length; ++i) { let mapX = x + smoothMap[i][0]; let mapY = y + smoothMap[i][1]; if (mapX >= 0 && mapX < max_x && mapY >= 0 && mapY < max_y) heightmap[x][y] += strength / smoothMap.length * (referenceHeightmap[mapX][mapY] - referenceHeightmap[x][y]); } } } } /** * Pushes a rectangular area towards a given height smoothing it into the original terrain * @note The window function to determine the smooth is not exactly a gaussian to ensure smooth edges * @param {object} [center] - The x and y coordinates of the center point (rounded in this function) * @param {float} [dx] - Distance from the center in x direction the rectangle ends (half width, rounded in this function) * @param {float} [dy] - Distance from the center in y direction the rectangle ends (half depth, rounded in this function) * @param {float} [targetHeight] - Height the center of the rectangle will be pushed to * @param {float} [strength=1] - How strong the height is pushed: 0 means not at all, 1 means the center will be pushed to the target height * @param {array} [heightmap=g_Map.height] - The heightmap to be manipulated * @todo Make the window function an argument and maybe add some */ function rectangularSmoothToHeight(center, dx, dy, targetHeight, strength = 0.8, heightmap = g_Map.height) { let x = round(center.x); let y = round(center.y); dx = round(dx); dy = round(dy); let heightmapWin = []; for (let wx = 0; wx < 2 * dx + 1; ++wx) { heightmapWin.push([]); for (let wy = 0; wy < 2 * dy + 1; ++wy) { let actualX = x - dx + wx; let actualY = y - dy + wy; if (actualX >= 0 && actualX < heightmap.length - 1 && actualY >= 0 && actualY < heightmap[0].length - 1) // Is in map heightmapWin[wx].push(heightmap[actualX][actualY]); else heightmapWin[wx].push(targetHeight); } } for (let wx = 0; wx < 2 * dx + 1; ++wx) { for (let wy = 0; wy < 2 * dy + 1; ++wy) { let actualX = x - dx + wx; let actualY = y - dy + wy; if (actualX >= 0 && actualX < heightmap.length - 1 && actualY >= 0 && actualY < heightmap[0].length - 1) // Is in map { // Window function polynomial 2nd degree let scaleX = 1 - (wx / dx - 1) * (wx / dx - 1); let scaleY = 1 - (wy / dy - 1) * (wy / dy - 1); heightmap[actualX][actualY] = heightmapWin[wx][wy] + strength * scaleX * scaleY * (targetHeight - heightmapWin[wx][wy]); } } } } Index: ps/trunk/binaries/data/mods/public/maps/random/hyrcanian_shores.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/hyrcanian_shores.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/hyrcanian_shores.js (revision 19443) @@ -1,530 +1,530 @@ RMS.LoadLibrary("rmgen"); // terrain textures 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 tDirt = ["temp_dirt_gravel", "temp_dirt_gravel_b"]; const tRoad = "temp_road"; const tRoadWild = "temp_road_overgrown"; const tGrassPatch = "temp_grass_plants"; const tShoreBlend = "temp_mud_plants"; const tShore = "medit_sand_wet"; const tWater = "medit_sand_wet"; // gaia entities const oPoplar = "gaia/flora_tree_poplar"; const oPalm = "gaia/flora_tree_cretan_date_palm_short"; const oApple = "gaia/flora_tree_apple"; const oOak = "gaia/flora_tree_oak"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oGoat = "gaia/fauna_goat"; const oBoar = "gaia/fauna_boar"; const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; const oStoneSmall = "gaia/geology_stone_temperate"; const oMetalLarge = "gaia/geology_metal_temperate_slabs"; // decorative props 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"; // terrain + entity (for painting) const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oPoplar, tGrassDForest]; const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest]; const WATER_WIDTH = 0.25; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clSea = createTileClass(); var clHighlands = createTileClass(); var clFlatlands = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerPos = new Array(numPlayers); for (var i = 0; i < numPlayers; i++) { playerPos[i] = (i + 1) / (numPlayers + 1); playerX[i] = playerPos[i]; playerZ[i] = 0.4 + 0.2*(i%2); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // Setting tile class addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oOak, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(10); // create sea and hills log("Creating sea and northern hills..."); var theta = randFloat(0, 1); var seed = randFloat(2,3); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); // add the rough shape of the water var km = 20/scaleByMapSize(35, 160); var cu = km*rndRiver(theta+x*0.5*(mapSize/64),seed); var fadeDist = 0.05; if (z < 0.25) { addToClass(ix, iz, clHighlands); } if (z > cu + 0.75) { var h; if ((z < (cu + 0.75 + fadeDist))&&(z > (cu + 0.75))) { h = 1 - 4.0 * (1 - ((cu + 0.75 + fadeDist) - z)/fadeDist); } else { h = -3.0; } if (h < -1.5) { placeTerrain(ix, iz, tWater); } else { placeTerrain(ix, iz, tShore); } setHeight(ix, iz, h); if (h < 0){ addToClass(ix, iz, clWater); } } } } RMS.SetProgress(20); // create fish log("Creating fish..."); num = scaleByMapSize(10, 20); for (var i=0; i < num; i++){ group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, [stayClasses(clWater, 2), avoidClasses(clFood, 3)], numPlayers, 50 ); } RMS.SetProgress(25); // create bumps log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 4, 3); createAreas( placer, painter, stayClasses(clHighlands, 1), scaleByMapSize(300, 600) ); RMS.SetProgress(30); // create hills log("Creating hills..."); placer = new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1); var terrainPainter = new LayeredPainter( [tCliff, tHill], // terrains [2] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 15, 2); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clSea, 5, clPlayer, 20, clWater, 5, clHill, 15, clHighlands, 5), scaleByMapSize(1, 4) * numPlayers ); RMS.SetProgress(35); // calculate desired number of trees for map (based on size) const MIN_TREES = 500; const MAX_TREES = 2500; const P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create mainland forests log("Creating mainland forests..."); var types = [ [[tGrassDForest, tGrass, pForestD], [tGrassDForest, pForestD]] ]; // some variation var size = numForest*1.3 / (scaleByMapSize(2,8) * numPlayers); var num = floor(0.7*size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ClumpPlacer(numForest / num, 0.1, 0.1, 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clWater, 3, clForest, 10, clHill, 0, clSea, 6, clBaseResource, 3), num ); } RMS.SetProgress(45); // create highland forests log("Creating highland forests..."); var types = [ [[tGrassDForest, tGrass, pForestP], [tGrassDForest, pForestP]] ]; // some variation var size = numForest / (scaleByMapSize(2,8) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ClumpPlacer(numForest / num, 0.1, 0.1, 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clWater, 3, clForest, 2, clHill, 0, clSea, 6, clFlatlands, 3), num ); } RMS.SetProgress(70); // create dirt patches log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter( [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4, clSea, 0), scaleByMapSize(15, 45) ); } RMS.SetProgress(75); // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]; for (var i = 0; i < sizes.length; i++) { placer = new ClumpPlacer(sizes[i], 0.3, 0.06, 0.5); painter = new LayeredPainter([tGrassC, tGrassPatch], [2]); createAreas( placer, painter, avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4, clSea, 0), scaleByMapSize(15, 45) ); } RMS.SetProgress(80); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clSea, 2, clHill, 2)], scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clSea, 2, clHill, 2)], scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clSea, 0, clHill, 2)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(85); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0, clSea, 0), scaleByMapSize(16, 262), 50 ); RMS.SetProgress(90); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0, clSea, 0), scaleByMapSize(8, 131), 50 ); // create deer log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 5, clSea, 0, clFlatlands, 0), 6 * numPlayers, 50 ); // create sheep log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oGoat, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 20, clSea, 0), 3 * numPlayers, 50 ); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 6, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); // create boar log("Creating boar..."); group = new SimpleGroup( [new SimpleObject(oBoar, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 20, clSea, 0, clFlatlands, 0), 2 * numPlayers, 50 ); // create straggler trees log("Creating straggler trees..."); var types = [oPoplar, oPalm, oApple]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 10, clMetal, 6, clRock, 6, clSea, 1, clHighlands, 25), num ); } //create small grass tufts log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0, clSea, 1), scaleByMapSize(13, 200) ); // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0, clSea, 1), scaleByMapSize(13, 200) ); RMS.SetProgress(95); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1, clSea, 1), scaleByMapSize(13, 200), 50 ); // Set environment setSkySet("cirrus"); setWaterColor(0.114, 0.192, 0.463); setWaterTint(0.255, 0.361, 0.651); setWaterWaviness(2.0); setWaterType("ocean"); setWaterMurkiness(0.83); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/islands.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/islands.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/islands.js (revision 19443) @@ -1,572 +1,572 @@ RMS.LoadLibrary("rmgen"); TILE_CENTERED_HEIGHT_MAP = true; //random terrain textures var random_terrain = randomizeBiome(); const tMainTerrain = rBiomeT1(); const tForestFloor1 = rBiomeT2(); const tForestFloor2 = rBiomeT3(); const tCliff = rBiomeT4(); const tTier1Terrain = rBiomeT5(); const tTier2Terrain = rBiomeT6(); const tTier3Terrain = rBiomeT7(); const tHill = rBiomeT8(); const tDirt = rBiomeT9(); const tRoad = rBiomeT10(); const tRoadWild = rBiomeT11(); const tTier4Terrain = rBiomeT12(); const tShoreBlend = rBiomeT13(); const tShore = rBiomeT14(); const tWater = rBiomeT15(); // gaia entities const oTree1 = rBiomeE1(); const oTree2 = rBiomeE2(); const oTree3 = rBiomeE3(); const oTree4 = rBiomeE4(); const oTree5 = rBiomeE5(); const oFruitBush = rBiomeE6(); const oMainHuntableAnimal = rBiomeE8(); const oFish = rBiomeE9(); const oSecondaryHuntableAnimal = rBiomeE10(); const oStoneLarge = rBiomeE11(); const oStoneSmall = rBiomeE12(); const oMetalLarge = rBiomeE13(); const oWood = "gaia/special_treasure_wood"; // decorative props const aGrass = rBiomeA1(); const aGrassShort = rBiomeA2(); const aReeds = rBiomeA3(); const aLillies = rBiomeA4(); const aRockLarge = rBiomeA5(); const aRockMedium = rBiomeA6(); const aBushMedium = rBiomeA7(); const aBushSmall = rBiomeA8(); const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clLand = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(20,29); var shoreRadius = 6; var elevation = 3; var hillSize = PI * radius * radius; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // create the hill var placer = new ClumpPlacer(hillSize, 0.80, 0.1, 10, ix, iz); var terrainPainter = new LayeredPainter( [tMainTerrain , tMainTerrain, tMainTerrain], // terrains [1, shoreRadius] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type elevation, // elevation shoreRadius // blend radius ); createArea(placer, [terrainPainter, elevationPainter, paintClass(clPlayer)], null); // create starting units placeCivDefaultEntities(fx, fz, id, { 'iberWall': 'towers' }); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create woods var bbAngle = randFloat(0, TWO_PI); var bbDist = 13; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); group = new SimpleGroup( [new SimpleObject(oWood, 14,14, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = 5; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(12, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oTree1, num, num, 0,3)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); //create docks var dockLocation = getTIPIADBON([ix, iz], [mapSize / 2, mapSize / 2], [-3 , 2.6], 0.5, 3); if (dockLocation !== undefined) placeObject(dockLocation[0], dockLocation[1], "structures/" + getCivCode(id-1) + "_dock", id, playerAngle[i] + PI); } var landAreas = []; var playerConstraint = new AvoidTileClassConstraint(clPlayer, floor(scaleByMapSize(12,16))); var landConstraint = new AvoidTileClassConstraint(clLand, floor(scaleByMapSize(12,16))); for (var x = 0; x < mapSize; ++x) for (var z = 0; z < mapSize; ++z) if (playerConstraint.allows(x, z) && landConstraint.allows(x, z)) landAreas.push([x, z]); var chosenPoint; var landAreaLen; log("Creating big islands..."); var numIslands = scaleByMapSize(4, 14); for (var i = 0; i < numIslands; ++i) { landAreaLen = landAreas.length; if (!landAreaLen) break; chosenPoint = pickRandom(landAreas); // create big islands placer = new ChainPlacer(floor(scaleByMapSize(4, 8)), floor(scaleByMapSize(8, 14)), floor(scaleByMapSize(25, 60)), 0.07, chosenPoint[0], chosenPoint[1], scaleByMapSize(30,70)); //placer = new ClumpPlacer(floor(hillSize*randFloat(0.9,2.1)), 0.80, 0.1, 0.07, chosenPoint[0], chosenPoint[1]); terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 3, 6); var newIsland = createAreas( placer, [terrainPainter, elevationPainter, paintClass(clLand)], avoidClasses(clLand, 3, clPlayer, 3), 1, 1 ); if (newIsland && newIsland.length) { var n = 0; for (var j = 0; j < landAreaLen; ++j) { var x = landAreas[j][0], z = landAreas[j][1]; if (playerConstraint.allows(x, z) && landConstraint.allows(x, z)) landAreas[n++] = landAreas[j]; } landAreas.length = n; } } playerConstraint = new AvoidTileClassConstraint(clPlayer, floor(scaleByMapSize(9,12))); landConstraint = new AvoidTileClassConstraint(clLand, floor(scaleByMapSize(9,12))); log("Creating small islands..."); numIslands = scaleByMapSize(6, 18) * scaleByMapSize(1,3); for (var i = 0; i < numIslands; ++i) { landAreaLen = landAreas.length; if (!landAreaLen) break; chosenPoint = pickRandom(landAreas); placer = new ChainPlacer(floor(scaleByMapSize(4, 7)), floor(scaleByMapSize(7, 10)), floor(scaleByMapSize(16, 40)), 0.07, chosenPoint[0], chosenPoint[1], scaleByMapSize(22,40)); terrainPainter = new LayeredPainter( [tMainTerrain, tMainTerrain], // terrains [2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 3, 6); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clLand)], avoidClasses(clLand, 3, clPlayer, 3), 1, 1 ); if (newIsland !== undefined) { var temp = []; for (var j = 0; j < landAreaLen; ++j) { var x = landAreas[j][0], z = landAreas[j][1]; if (playerConstraint.allows(x, z) && landConstraint.allows(x, z)) temp.push([x, z]); } landAreas = temp; } } paintTerrainBasedOnHeight(1, 3, 0, tShore); paintTerrainBasedOnHeight(-8, 1, 2, tWater); for (var i = 0; i < numPlayers; i++) { var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // create the city patch var cityRadius = radius/3; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); } // create bumps log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, [avoidClasses(clPlayer, 0), stayClasses(clLand, 3)], scaleByMapSize(20, 100) ); // create hills log("Creating hills..."); placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(16, 40)), 0.5); terrainPainter = new LayeredPainter( [tCliff, tHill], // terrains [2] // widths ); elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 18, 2); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], scaleByMapSize(4, 13) ); // calculate desired number of trees for map (based on size) if (random_terrain == g_BiomeSavanna) { var MIN_TREES = 200; var MAX_TREES = 1250; var P_FOREST = 0; } else if (random_terrain == g_BiomeTropic) { var MIN_TREES = 1000; var MAX_TREES = 6000; var P_FOREST = 0.52; } else { var MIN_TREES = 500; var MAX_TREES = 3000; var P_FOREST = 0.7; } var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [ [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] ]; // some variation if (random_terrain != g_BiomeSavanna) { var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / (num * floor(scaleByMapSize(2,5))), 0.5); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], [avoidClasses(clPlayer, 0, clForest, 10, clHill, 0), stayClasses(clLand, 6)], num ); } } RMS.SetProgress(50); // create dirt patches log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; var numb = 1; if (random_terrain == g_BiomeSavanna) numb = 3; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)], numb*scaleByMapSize(15, 45) ); } // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new TerrainPainter(tTier4Terrain); createAreas( placer, painter, [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)], numb*scaleByMapSize(15, 45) ); } RMS.SetProgress(55); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)], scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)], scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clPlayer, 0, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 5)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(65); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)], scaleByMapSize(16, 262), 50 ); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)], scaleByMapSize(8, 131), 50 ); RMS.SetProgress(70); // create deer log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)], 3 * numPlayers, 50 ); RMS.SetProgress(75); // create sheep log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)], 3 * numPlayers, 50 ); // create fruit bush log("Creating fruit bush..."); group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clForest, 0, clPlayer, 8, clHill, 1, clFood, 20), stayClasses(clLand, 5)], - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); // create fish log("Creating fish..."); group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clLand, 4, clForest, 2, clPlayer, 2, clHill, 2, clFood, 20), 25 * numPlayers, 60 ); RMS.SetProgress(85); // create straggler trees log("Creating straggler trees..."); var types = [oTree1, oTree2, oTree4, oTree3]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, [avoidClasses(clForest, 1, clHill, 1, clPlayer, 0, clMetal, 6, clRock, 6), stayClasses(clLand, 6)], num ); } var planetm = 1; if (random_terrain == g_BiomeTropic) planetm = 8; //create small grass tufts log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(90); // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 5)], planetm * scaleByMapSize(13, 200) ); RMS.SetProgress(95); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, [avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200), 50 ); setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randFloat(0, TWO_PI)); setSunElevation(randFloat(PI/ 5, PI / 3)); setWaterWaviness(2); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/kerala.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/kerala.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/kerala.js (revision 19443) @@ -1,472 +1,479 @@ RMS.LoadLibrary("rmgen"); const tGrass = ["tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_plants", "tropic_plants", "tropic_plants_b"]; const tGrassA = "tropic_plants_c"; const tGrassB = "tropic_plants_c"; const tGrassC = "tropic_grass_c"; const tForestFloor = "tropic_grass_plants"; const tCliff = ["tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a_plants"]; const tPlants = "tropic_plants"; const tRoad = "tropic_citytile_a"; const tRoadWild = "tropic_citytile_plants"; const tShoreBlend = "tropic_beach_dry_plants"; const tShore = "tropic_beach_dry"; const tWater = "tropic_beach_wet"; // gaia entities const oTree = "gaia/flora_tree_toona"; const oPalm = "gaia/flora_tree_palm_tropic"; const oStoneLarge = "gaia/geology_stonemine_tropic_quarry"; const oStoneSmall = "gaia/geology_stone_tropic_a"; const oMetalLarge = "gaia/geology_metal_tropic_slabs"; const oFish = "gaia/fauna_fish"; const oDeer = "gaia/fauna_deer"; const oSheep = "gaia/fauna_tiger"; const oBush = "gaia/flora_bush_berry"; // decorative props const aRockLarge = "actor|geology/stone_granite_large.xml"; const aRockMedium = "actor|geology/stone_granite_med.xml"; const aBush1 = "actor|props/flora/plant_tropic_a.xml"; const aBush2 = "actor|props/flora/plant_lg.xml"; const aBush3 = "actor|props/flora/plant_tropic_large.xml"; const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oTree, tForestFloor]; const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oPalm, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clHill2 = createTileClass(); var clHill3 = createTileClass(); var clHill4 = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clMountains = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerPos = new Array(numPlayers); for (var i = 0; i < numPlayers; i++) { playerPos[i] = (i + 1) / (numPlayers + 1); playerX[i] = 0.45 + 0.2*(i%2); playerZ[i] = playerPos[i]; } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); var group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 60); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(12, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oTree, num, num, 0,3)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } RMS.SetProgress(15); // create western sea var fadedistance = 8; for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { if (ix < 0.31 * mapSize) { if (ix > 0.31 * mapSize - fadedistance) { setHeight(ix, iz, 3 - 8 * (0.31 * mapSize - ix) / fadedistance); if (ix, iz, 3 - 8 * (0.31 * mapSize - ix) / fadedistance < 0.5) addToClass(ix, iz, clWater); } else { setHeight(ix, iz, -5); addToClass(ix, iz, clWater); } } else if (ix > 0.69 * mapSize) addToClass(ix, iz, clMountains); } } // create shore log("Creating shores..."); for (var i = 0; i < scaleByMapSize(20,120); i++) { - placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(16, 30)), 1, floor(randFloat(0.28,0.34)*mapSize), floor(randFloat(0.1,0.9)*mapSize)); + placer = new ChainPlacer( + 1, + Math.floor(scaleByMapSize(4, 6)), + Math.floor(scaleByMapSize(16, 30)), + 1, + randIntExclusive(0.28 * mapSize, 0.34 * mapSize), + randIntExclusive(0.1 * mapSize, 0.9 * mapSize)); + var terrainPainter = new LayeredPainter( [tGrass, tGrass], // terrains [2] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 3, 3); createArea( placer, [terrainPainter, elevationPainter, unPaintClass(clWater)], null ); } paintTerrainBasedOnHeight(-6, 1, 1, tWater); paintTerrainBasedOnHeight(1, 2.8, 1, tShoreBlend); paintTerrainBasedOnHeight(0, 1, 1, tShore); paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); RMS.SetProgress(45); // create hills log("Creating hills..."); placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(16, 40)), 0.1); var terrainPainter = new LayeredPainter( [tCliff, tGrass], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 25, 3); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], [avoidClasses(clPlayer, 20, clHill, 5, clWater, 2, clBaseResource, 2), stayClasses(clMountains, 0)], scaleByMapSize(5, 40) * numPlayers ); // calculate desired number of trees for map (based on size) var MIN_TREES = 1000; var MAX_TREES = 6000; var P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [ [[tGrass, tGrass, tGrass, tGrass, pForestD], [tGrass, tGrass, tGrass, pForestD]], [[tGrass, tGrass, tGrass, tGrass, pForestP], [tGrass, tGrass, tGrass, pForestP]] ]; // some variation var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / (num * floor(scaleByMapSize(2,4))), 0.5); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clForest, 10, clHill, 0, clWater, 8), num ); } RMS.SetProgress(70); // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [tGrassC,tGrassA,tGrassB], // terrains [2,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 12, clDirt, 16), scaleByMapSize(20, 80) ); } var sizes = [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [tPlants,tPlants], // terrains [1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 12, clDirt, 16), scaleByMapSize(20, 80) ); } log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), scaleByMapSize(4,16), 100 ); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), 3*scaleByMapSize(16, 262), 50 ); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), 3*scaleByMapSize(8, 131), 50 ); //create small grass tufts log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aBush1, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), 8 * scaleByMapSize(13, 200) ); RMS.SetProgress(90); // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aBush2, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aBush1, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), 8 * scaleByMapSize(13, 200) ); RMS.SetProgress(95); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBush3, 1,2, 0,2), new SimpleObject(aBush2, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), 8 * scaleByMapSize(13, 200), 50 ); RMS.SetProgress(95); // create straggler trees log("Creating straggler trees..."); var types = [oTree, oPalm]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), num ); } // create deer log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); RMS.SetProgress(75); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 6, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); // create sheep log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oSheep, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 22, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); // create fish log("Creating fish..."); group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clFood, 20), stayClasses(clWater, 6)], 25 * numPlayers, 60 ); setSunColor(0.6, 0.6, 0.6); setSunElevation(PI/ 3); setWaterColor(0.524,0.734,0.839); setWaterTint(0.369,0.765,0.745); setWaterWaviness(1.0); setWaterType("ocean"); setWaterMurkiness(0.35); setFogFactor(0.4); setFogThickness(0.2); setPPEffect("hdr"); setPPContrast(0.7); setPPSaturation(0.65); setPPBloom(0.6); setSkySet("cirrus"); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/latium.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/latium.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/latium.js (revision 19443) @@ -1,546 +1,552 @@ RMS.LoadLibrary("rmgen"); const WATER_WIDTH = 0.1; // terrain textures const tOceanDepths = "medit_sea_depths"; const tOceanRockDeep = "medit_sea_coral_deep"; const tOceanRockShallow = "medit_rocks_wet"; const tOceanCoral = "medit_sea_coral_plants"; const tBeachWet = "medit_sand_wet"; const tBeachDry = "medit_sand"; const tBeachGrass = "medit_rocks_grass"; const tBeachCliff = "medit_dirt"; const tCity = "medit_city_tile"; const tGrassDry = ["medit_grass_field_brown", "medit_grass_field_dry", "medit_grass_field_b"]; const tGrass = ["medit_grass_field_dry", "medit_grass_field_brown", "medit_grass_field_b"]; const tGrassLush = ["grass_temperate_dry_tufts", "medit_grass_flowers"]; const tGrassShrubs = ["medit_grass_shrubs", "medit_grass_flowers"]; const tGrassRock = ["medit_rocks_grass"]; const tDirt = "medit_dirt"; const tDirtGrass = "medit_dirt_b"; const tDirtCliff = "medit_cliff_italia"; const tGrassCliff = "medit_cliff_italia_grass"; const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; const tForestFloor = "medit_grass_wild"; // gaia entities const oBeech = "gaia/flora_tree_euro_beech"; const oBerryBush = "gaia/flora_bush_berry"; const oCarob = "gaia/flora_tree_carob"; const oCypress1 = "gaia/flora_tree_cypress"; const oCypress2 = "gaia/flora_tree_cypress"; const oLombardyPoplar = "gaia/flora_tree_poplar_lombardy"; const oOak = "gaia/flora_tree_oak"; const oPalm = "gaia/flora_tree_medit_fan_palm"; const oPine = "gaia/flora_tree_aleppo_pine"; const oPoplar = "gaia/flora_tree_poplar"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oSheep = "gaia/fauna_sheep"; const oStoneLarge = "gaia/geology_stonemine_medit_quarry"; const oStoneSmall = "gaia/geology_stone_mediterranean"; const oMetalLarge = "gaia/geology_metal_mediterranean_slabs"; // decorative props const aBushLargeDry = "actor|props/flora/bush_medit_la_dry.xml"; const aBushLarge = "actor|props/flora/bush_medit_la.xml"; const aBushMedDry = "actor|props/flora/bush_medit_me_dry.xml"; const aBushMed = "actor|props/flora/bush_medit_me.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const aBushSmallDry = "actor|props/flora/bush_medit_sm_dry.xml"; const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; const aGrassDry = "actor|props/flora/grass_soft_dry_large_tall.xml"; const aRockLarge = "actor|geology/stone_granite_large.xml"; const aRockMed = "actor|geology/stone_granite_med.xml"; const aRockSmall = "actor|geology/stone_granite_small.xml"; const aWaterLog = "actor|props/flora/water_log.xml"; // terrain + entity (for painting) const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // Create classes var clWater = createTileClass(); var clCliff = createTileClass(); var clForest = createTileClass(); var clMetal = createTileClass(); var clRock = createTileClass(); var clFood = createTileClass(); var clPlayer = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) playerIDs.push(i+1); playerIDs = sortPlayers(playerIDs); log("Creating players..."); var playerX = new Array(numPlayers+1); var playerZ = new Array(numPlayers+1); var numLeftPlayers = ceil(numPlayers/2); for (var i = 1; i <= numLeftPlayers; i++) { playerX[i] = 0.28 + randFloat(-0.01, 0.01); playerZ[i] = (0.5+i-1)/numLeftPlayers + randFloat(-0.01, 0.01); } for (var i = numLeftPlayers+1; i <= numPlayers; i++) { playerX[i] = 0.72 + randFloat(-0.01, 0.01); playerZ[i] = (0.5+i-numLeftPlayers-1)/numLeftPlayers + randFloat(-0.01, 0.01); } function distanceToPlayers(x, z) { var r = 10000; for (var i = 1; i <= numPlayers; i++) { var dx = x - playerX[i]; var dz = z - playerZ[i]; r = min(r, dx*dx + dz*dz); } return sqrt(r); } function playerNearness(x, z) { var d = fractionToTiles(distanceToPlayers(x,z)); if (d < 13) return 0; if (d < 19) return (d-13)/(19-13); return 1; } log("Painting elevation..."); var noise0 = new Noise2D(scaleByMapSize(4, 16)); var noise1 = new Noise2D(scaleByMapSize(8, 32)); var noise2 = new Noise2D(scaleByMapSize(15, 60)); var noise2a = new Noise2D(scaleByMapSize(20, 80)); var noise2b = new Noise2D(scaleByMapSize(35, 140)); var noise3 = new Noise2D(scaleByMapSize(4, 16)); var noise4 = new Noise2D(scaleByMapSize(6, 24)); var noise5 = new Noise2D(scaleByMapSize(11, 44)); for (var ix = 0; ix <= mapSize; ix++) { for (var iz = 0; iz <= mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); var pn = playerNearness(x, z); var h = 0; var distToWater = 0; h = 32 * (x - 0.5); // add the rough shape of the water if (x < WATER_WIDTH) { h = max(-16.0, -28.0*(WATER_WIDTH-x)/WATER_WIDTH); } else if (x > 1.0-WATER_WIDTH) { h = max(-16.0, -28.0*(x-(1.0-WATER_WIDTH))/WATER_WIDTH); } else { distToWater = (0.5 - WATER_WIDTH - abs(x-0.5)); var u = 1 - abs(x-0.5) / (0.5-WATER_WIDTH); h = 12*u; } // add some base noise var baseNoise = 16*noise0.get(x,z) + 8*noise1.get(x,z) + 4*noise2.get(x,z) - (16+8+4)/2; if ( baseNoise < 0 ) { baseNoise *= pn; baseNoise *= max(0.1, distToWater / (0.5-WATER_WIDTH)); } var oldH = h; h += baseNoise; // add some higher-frequency noise on land if ( oldH > 0 ) h += (0.4*noise2a.get(x,z) + 0.2*noise2b.get(x,z)) * min(oldH/10.0, 1.0); // create cliff noise if ( h > -10 ) { var cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5; if (h < 1) { var u = 1 - 0.3*((h-1)/-10); cliffNoise *= u; } cliffNoise += 0.05 * distToWater / (0.5 - WATER_WIDTH); if (cliffNoise > 0.6) { var u = 0.8 * (cliffNoise - 0.6); cliffNoise += u * noise5.get(x,z); cliffNoise /= (1 + u); } cliffNoise -= 0.59; cliffNoise *= pn; if (cliffNoise > 0) h += 19 * min(cliffNoise, 0.045) / 0.045; } // set the height setHeight(ix, iz, h); } } RMS.SetProgress(15); log("Painting terrain..."); var noise6 = new Noise2D(scaleByMapSize(10, 40)); var noise7 = new Noise2D(scaleByMapSize(20, 80)); var noise8 = new Noise2D(scaleByMapSize(13, 52)); var noise9 = new Noise2D(scaleByMapSize(26, 104)); var noise10 = new Noise2D(scaleByMapSize(50, 200)); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); var pn = playerNearness(x, z); // get heights of surrounding vertices var h00 = getHeight(ix, iz); var h01 = getHeight(ix, iz+1); var h10 = getHeight(ix+1, iz); var h11 = getHeight(ix+1, iz+1); // find min and max height var maxH = Math.max(h00, h01, h10, h11); var minH = Math.min(h00, h01, h10, h11); var diffH = maxH - minH; // figure out if we're at the top of a cliff using min adjacent height var minAdjHeight = minH; if (maxH > 15) { var maxNx = min(ix+2, mapSize); var maxNz = min(iz+2, mapSize); for (var nx = max(ix-1, 0); nx <= maxNx; nx++) for (var nz = max(iz-1, 0); nz <= maxNz; nz++) minAdjHeight = min(minAdjHeight, getHeight(nx, nz)); } // choose a terrain based on elevation var t = tGrass; // water if (maxH < -12) t = tOceanDepths; else if (maxH < -8.8) t = tOceanRockDeep; else if (maxH < -4.7) t = tOceanCoral; else if (maxH < -2.8) t = tOceanRockShallow; else if (maxH < 0.9 && minH < 0.35) t = tBeachWet; else if (maxH < 1.5 && minH < 0.9) t = tBeachDry; else if (maxH < 2.3 && minH < 1.3) t = tBeachGrass; if (minH < 0) addToClass(ix, iz, clWater); // cliffs if (diffH > 2.9 && minH > -7) { t = tCliff; addToClass(ix, iz, clCliff); } else if (diffH > 2.5 && minH > -5 || maxH - minAdjHeight > 2.9 && minH > 0) { if (minH < -1) t = tCliff; else if (minH < 0.5) t = tBeachCliff; else t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff]; addToClass(ix, iz, clCliff); } // Don't place resources onto potentially impassable mountains if (minH >= 20) addToClass(ix, iz, clCliff); // forests if (getHeight(ix, iz) < 11 && diffH < 2 && minH > 1) { var forestNoise = (noise6.get(x,z) + 0.5*noise7.get(x,z)) / 1.5 * pn - 0.59; // Thin out trees a bit if (forestNoise > 0 && randBool()) { if (minH < 11 && minH >= 4) { var typeNoise = noise10.get(x,z); if (typeNoise < 0.43 && forestNoise < 0.05) t = pPoplarForest; else if (typeNoise < 0.63) t = pMainForest; else t = pPineForest; addToClass(ix, iz, clForest); } else if (minH < 4) { t = pPalmForest; addToClass(ix, iz, clForest); } } } // grass variations if (t == tGrass) { var grassNoise = (noise8.get(x,z) + 0.6*noise9.get(x,z)) / 1.6; if (grassNoise < 0.3) { t = (diffH > 1.2) ? tDirtCliff : tDirt; } else if (grassNoise < 0.34) { t = (diffH > 1.2) ? tGrassCliff : tGrassDry; if (diffH < 0.5 && randBool(0.02)) placeObject(ix+randFloat(), iz+randFloat(), aGrassDry, 0, randFloat(0, TWO_PI)); } else if (grassNoise > 0.61) { t = (diffH > 1.2 ? tGrassRock : tGrassShrubs); } else if (diffH < 0.5 && randBool(0.02)) placeObject(ix+randFloat(), iz+randFloat(), aGrass, 0, randFloat(0, TWO_PI)); } placeTerrain(ix, iz, t); } } RMS.SetProgress(30); for (var i = 1; i <= numPlayers; i++) { var id = playerIDs[i-1]; log("Creating base for player " + id + "..."); // get fractional locations in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); // create the city patch, flatten area under TC var cityRadius = 11; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tGrass, tCity], [4]); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type 5, // elevation 2 // blend radius ); createArea(placer, [painter, elevationPainter], null); placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create starting berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 9; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,2)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) mAngle = randFloat(0, TWO_PI); var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 5; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(10, 11); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPalm, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource, 2, clCliff, 0)); } RMS.SetProgress(40); log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushSmall, 0,2, 0,2), new SimpleObject(aBushSmallDry, 0,2, 0,2), new SimpleObject(aBushMed, 0,1, 0,2), new SimpleObject(aBushMedDry, 0,1, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 4, clCliff, 2), scaleByMapSize(9, 146), 50 ); RMS.SetProgress(45); log("Creating rocks..."); group = new SimpleGroup( [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), new SimpleObject(aRockLarge, 0,1, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clCliff, 1), scaleByMapSize(9, 146), 50 ); RMS.SetProgress(50); log("Creating large stone mines..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 1, clForest, 4, clPlayer, 40, clRock, 60, clMetal, 10, clCliff, 3), scaleByMapSize(4,16), 100 ); log("Creating small stone mines..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clRock, 30, clMetal, 10, clCliff, 3), scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,2)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clMetal, 50, clCliff, 3), scaleByMapSize(4,16), 100 ); RMS.SetProgress(60); log("Creating straggler trees..."); for (let tree of [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine]) { group = new SimpleGroup([new SimpleObject(tree, 1,1, 0,1)], true, clForest); createObjectGroups(group, 0, avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), scaleByMapSize(2, 38), 50 ); } RMS.SetProgress(70); log("Creating straggler cypresses..."); group = new SimpleGroup( [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], true ); createObjectGroups(group, 0, avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), scaleByMapSize(5, 75), 50 ); RMS.SetProgress(80); log("Creating sheep..."); group = new SimpleGroup([new SimpleObject(oSheep, 2,4, 0,2)], true, clFood); createObjectGroups(group, 0, avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), 3 * numPlayers, 50 ); RMS.SetProgress(85); log("Creating fish..."); var num = scaleByMapSize(4, 16); var offsetX = mapSize * WATER_WIDTH/2; -for (var i = 0; i < num; ++i) -{ - var cX = round(offsetX + offsetX/2 * randFloat(-1, 1)); - var cY = round((i + 0.5) * mapSize/num); - group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,1)], true, clFood, cX, cY); - createObjectGroup(group, 0); -} -for (var i = 0; i < num; ++i) -{ - var cX = round(mapSize - offsetX + offsetX/2 * randFloat(-1, 1)); - var cY = round((i + 0.5) * mapSize/num); - group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,1)], true, clFood, cX, cY); - createObjectGroup(group, 0); -} +for (let i = 0; i < num; ++i) + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oFish, 1, 1, 0, 1)], + true, + clFood, + randIntInclusive(offsetX / 2, offsetX * 3/2), + Math.round((i + 0.5) * mapSize / num)), + 0); + +for (let i = 0; i < num; ++i) + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oFish, 1, 1, 0, 1)], + true, + clFood, + randIntInclusive(mapSize - offsetX * 3/2, mapSize - offsetX / 2), + Math.round((i + 0.5) * mapSize / num)), + 0); + RMS.SetProgress(90); log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), 3 * numPlayers, 50 ); RMS.SetProgress(95); log("Creating berry bushes..."); group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); createObjectGroups(group, 0, avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), 1.5 * numPlayers, 100 ); // Adjust environment setSkySet("sunny"); setWaterColor(0.024,0.262,0.224); setWaterTint(0.133, 0.325,0.255); setWaterWaviness(2.5); setWaterType("ocean"); setWaterMurkiness(0.8); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/lorraine_plain.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/lorraine_plain.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/lorraine_plain.js (revision 19443) @@ -1,500 +1,500 @@ RMS.LoadLibrary("rmgen"); const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; const tGrassPForest = "temp_plants_bog"; const tGrassDForest = "temp_plants_bog"; const tGrassA = "temp_grass_plants"; const tGrassB = "temp_plants_bog"; const tGrassC = "temp_mud_a"; const tDirt = ["temp_plants_bog", "temp_mud_a"]; const tHill = ["temp_highlands", "temp_grass_long_b"]; const tCliff = ["temp_cliff_a", "temp_cliff_b"]; const tRoad = "temp_road"; const tRoadWild = "temp_road_overgrown"; const tGrassPatchBlend = "temp_grass_long_b"; const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; const tShoreBlend = "temp_grass_plants"; const tShore = "temp_plants_bog"; const tWater = "temp_mud_a"; // gaia entities const oBeech = "gaia/flora_tree_euro_beech"; const oOak = "gaia/flora_tree_oak"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oRabbit = "gaia/fauna_rabbit"; const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; const oStoneSmall = "gaia/geology_stone_temperate"; const oMetalLarge = "gaia/geology_metal_temperate_slabs"; // decorative props const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; const aGrassShort = "actor|props/flora/grass_soft_large.xml"; const aRockLarge = "actor|geology/stone_granite_med.xml"; const aRockMedium = "actor|geology/stone_granite_med.xml"; const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; const aLillies = "actor|props/flora/water_lillies.xml"; const aBushMedium = "actor|props/flora/bush_medit_me.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const pForestB = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest]; const pForestO = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest]; const pForestR = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest, tGrassDForest + TERRAIN_SEPARATOR + oOak, tGrassDForest, tGrassDForest, tGrassDForest]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clShallow = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = primeSortPlayers(sortPlayers(playerIDs)); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var playerPos = new Array(numPlayers); var iop = 0; for (var i = 0; i < numPlayers; i++) { iop = i - 1; if (!(numPlayers%2)){ playerPos[i] = ((iop + abs(iop%2))/2 + 1) / ((numPlayers / 2) + 1); } else { if (iop%2) { playerPos[i] = ((iop + abs(iop%2))/2 + 1) / (((numPlayers + 1) / 2) + 1); } else { playerPos[i] = ((iop)/2 + 1) / ((((numPlayers - 1)) / 2) + 1); } } playerZ[i] = 0.25 + 0.5*(i%2); playerX[i] = playerPos[i]; } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // scale radius of player area by map size var radius = scaleByMapSize(15,25); // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); // calculate size based on the radius var size = PI * radius * radius / 4; // create the player area var placer = new ClumpPlacer(size, 0.9, 0.5, 10, ix, iz); createArea(placer, paintClass(clPlayer), null); // create the city patch var cityRadius = 10; placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [3]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id, { 'iberWall': 'towers' }); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 11; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0), new SimpleObject(aGrass, 2,4, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2), new SimpleObject(aGrass, 2,4, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 3; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oOak, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } // create the main river log("Creating the main river"); var tang = randFloat(0, TWO_PI); var placer = new PathPlacer(1, fractionToTiles(0.5), fractionToTiles(0.99), fractionToTiles(0.5), scaleByMapSize(10,20), 0.5, 3*(scaleByMapSize(1,4)), 0.1, 0.01); var terrainPainter = new LayeredPainter( [tShore, tWater, tWater], // terrains [1, 3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type -4, // elevation 4 // blend radius ); createArea(placer, [terrainPainter, elevationPainter], avoidClasses(clPlayer, 4)); placer = new ClumpPlacer(floor(PI*scaleByMapSize(10,20)*scaleByMapSize(10,20)/4), 0.95, 0.6, 10, 1, fractionToTiles(0.5)); var painter = new LayeredPainter([tWater, tWater], [1]); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -4, 2); createArea(placer, [painter, elevationPainter], avoidClasses(clPlayer, 8)); placer = new ClumpPlacer(floor(PI*scaleByMapSize(10,20)*scaleByMapSize(10,20)/4), 0.95, 0.6, 10, fractionToTiles(0.99), fractionToTiles(0.5)); var painter = new LayeredPainter([tWater, tWater], [1]); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -4, 2); createArea(placer, [painter, elevationPainter], avoidClasses(clPlayer, 8)); // create the shallows of the main river log("Creating the shallows of the main river"); -for (var i = 0; i <= randInt(3, scaleByMapSize(4,6)); i++) +for (let i = 0; i <= randIntInclusive(3, scaleByMapSize(4, 6)); ++i) { var cLocation = randFloat(0.15,0.85); passageMaker(floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); } // create tributaries log("Creating tributaries"); for (let i = 0; i <= randIntInclusive(8, scaleByMapSize(12, 20)); ++i) { let cLocation = randFloat(0.05, 0.95); let sign = randBool() ? 1 : -1; let tang = sign * PI * randFloat(0.2, 0.8); let cDistance = sign * 0.05; var point = getTIPIADBON([fractionToTiles(cLocation), fractionToTiles(0.5 + cDistance)], [fractionToTiles(cLocation), fractionToTiles(0.5 - cDistance)], [-6, -1.5], 0.5, 5, 0.01); if (point !== undefined) { var placer = new PathPlacer(floor(point[0]), floor(point[1]), floor(fractionToTiles(0.5 + 0.49*cos(tang))), floor(fractionToTiles(0.5 + 0.49*sin(tang))), scaleByMapSize(10,20), 0.4, 3*(scaleByMapSize(1,4)), 0.1, 0.05); var terrainPainter = new LayeredPainter( [tShore, tWater, tWater], // terrains [1, 3] // widths ); var elevationPainter = new SmoothElevationPainter( ELEVATION_SET, // type -4, // elevation 4 // blend radius ); var success = createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 3, clWater, 3, clShallow, 2)); if (success !== undefined) { placer = new ClumpPlacer(floor(PI*scaleByMapSize(10,20)*scaleByMapSize(10,20)/4), 0.95, 0.6, 10, fractionToTiles(0.5 + 0.49*cos(tang)), fractionToTiles(0.5 + 0.49*sin(tang))); var painter = new LayeredPainter([tWater, tWater], [1]); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -4, 2); createArea(placer, [painter, elevationPainter], avoidClasses(clPlayer, 3)); } } } passageMaker(floor(fractionToTiles(0.2)), floor(fractionToTiles(0.25)), floor(fractionToTiles(0.8)), floor(fractionToTiles(0.25)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); passageMaker(floor(fractionToTiles(0.2)), floor(fractionToTiles(0.75)), floor(fractionToTiles(0.8)), floor(fractionToTiles(0.75)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); paintTerrainBasedOnHeight(-5, 1, 1, tWater); paintTerrainBasedOnHeight(1, 2, 1, pForestR); paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); RMS.SetProgress(50); // create bumps log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, avoidClasses(clWater, 2, clPlayer, 15), scaleByMapSize(100, 200) ); RMS.SetProgress(55); // calculate desired number of trees for map (based on size) const MIN_TREES = 500; const MAX_TREES = 2500; const P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [ [[tGrassDForest, tGrass, pForestB], [tGrassDForest, pForestB]], [[tGrassPForest, tGrass, pForestO], [tGrassPForest, pForestO]] ]; // some variation var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / num, 0.5); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 15, clWater, 3, clForest, 16, clHill, 1), num ); } RMS.SetProgress(70); // create dirt patches log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [[tGrass,tGrassA], tGrassB, [tGrassB,tGrassC]], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), scaleByMapSize(15, 45) ); } // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [tGrassPatchBlend, tGrassPatch], // terrains [1] // widths ); createAreas( placer, painter, avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), scaleByMapSize(15, 45) ); } RMS.SetProgress(80); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clRock, 10, clHill, 1)], scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clRock, 10, clHill, 1)], scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clMetal, 10, clRock, 5, clHill, 1)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(86); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(16, 262), 50 ); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(8, 131), 50 ); // create deer log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); // create rabbid log("Creating rabbid..."); group = new SimpleGroup( [new SimpleObject(oRabbit, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 15, clHill, 1, clFood, 10), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); // create straggler trees log("Creating straggler trees..."); var types = [oOak, oBeech]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clForest, 7, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6), num ); } //create small grass tufts log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), scaleByMapSize(13, 200) ); // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), scaleByMapSize(13, 200) ); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), scaleByMapSize(13, 200), 50 ); // create shallow flora log("Creating shallow flora..."); group = new SimpleGroup( [new SimpleObject(aLillies, 1,2, 0,2), new SimpleObject(aReeds, 2,4, 0,2)] ); createObjectGroups(group, 0, stayClasses(clShallow, 1), 60 * scaleByMapSize(13, 200), 80 ); // Set environment setSkySet("cirrus"); setWaterColor(0.1,0.212,0.422); setWaterTint(0.3,0.1,0.949); setWaterWaviness(3.0); setWaterType("lake"); setWaterMurkiness(0.80); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/northern_lights.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/northern_lights.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/northern_lights.js (revision 19443) @@ -1,421 +1,428 @@ RMS.LoadLibrary("rmgen"); const tSnowA = ["polar_snow_b"]; const tSnowB = "polar_ice_snow"; const tSnowC = "polar_ice"; const tSnowD = "polar_snow_a"; const tForestFloor = "polar_tundra_snow"; const tCliff = "polar_snow_rocks"; const tSnowE = ["polar_snow_glacial"]; const tRoad = "new_alpine_citytile"; const tRoadWild = "new_alpine_citytile"; const tShoreBlend = "alpine_shore_rocks_icy"; const tShore = "alpine_shore_rocks"; const tWater = "alpine_shore_rocks"; // gaia entities const oPine = "gaia/flora_tree_pine_w"; const oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; const oStoneSmall = "gaia/geology_stone_alpine_a"; const oMetalLarge = "gaia/geology_metal_alpine_slabs"; const oFish = "gaia/fauna_fish"; const oWalrus = "gaia/fauna_walrus"; const oWolf = "gaia/fauna_wolf_snow"; // decorative props const aRockLarge = "actor|geology/stone_granite_med.xml"; const aRockMedium = "actor|geology/stone_granite_med.xml"; const aIceberg = "actor|props/special/eyecandy/iceberg.xml"; const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor, tForestFloor]; const pForestS = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor, tForestFloor, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clHill2 = createTileClass(); var clHill3 = createTileClass(); var clHill4 = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerPos = new Array(numPlayers); for (var i = 0; i < numPlayers; i++) { playerPos[i] = (i + 1) / (numPlayers + 1); playerX[i] = playerPos[i]; playerZ[i] = 0.35 + 0.2*(i%2); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); // create metal mine var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); var group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 60); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(12, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oPine, num, num, 0,3)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } RMS.SetProgress(15); // create northern sea var fadedistance = 8; for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { if (iz > 0.69 * mapSize) { if (iz < 0.69 * mapSize + fadedistance) { setHeight(ix, iz, 3 - 8 * (iz - 0.69 * mapSize) / fadedistance); if (ix, iz, 3 - 8 * (iz - 0.69 * mapSize) / fadedistance < 0.5) addToClass(ix, iz, clWater); } else { setHeight(ix, iz, -5); addToClass(ix, iz, clWater); } } } } // create shore log("Creating shores..."); for (var i = 0; i < scaleByMapSize(20,120); i++) { - placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(16, 30)), 1, floor(randFloat(0.1,0.9)*mapSize), floor(randFloat(0.67,0.74)*mapSize)); + placer = new ChainPlacer( + 1, + Math.floor(scaleByMapSize(4, 6)), + Math.floor(scaleByMapSize(16, 30)), + 1, + randIntExclusive(0.1 * mapSize, 0.9 * mapSize), + randIntExclusive(0.67 * mapSize, 0.74 * mapSize)); + var terrainPainter = new LayeredPainter( [tSnowA, tSnowA], // terrains [2] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 3, 3); createArea( placer, [terrainPainter, elevationPainter, unPaintClass(clWater)], null ); } // create islands log("Creating islands..."); placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(16, 40)), 0.1); var terrainPainter = new LayeredPainter( [tSnowA, tSnowA], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 3, 3); createAreas( placer, [terrainPainter, elevationPainter, unPaintClass(clWater)], stayClasses(clWater, 7), scaleByMapSize(10, 80) ); paintTerrainBasedOnHeight(-6, 1, 1, tWater); // create lakes log("Creating lakes..."); var numLakes = round(scaleByMapSize(1,4) * numPlayers); var placer = new ChainPlacer(1, floor(scaleByMapSize(5, 7)), floor(scaleByMapSize(20, 50)), 0.1); var terrainPainter = new LayeredPainter( [tShoreBlend, tShore, tWater], // terrains [1,1] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -4, 3); var waterAreas = createAreas( placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 20, clWater, 20), numLakes ); paintTerrainBasedOnHeight(1, 2.8, 1, tShoreBlend); paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); RMS.SetProgress(45); // create hills log("Creating hills..."); placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(16, 40)), 0.1); var terrainPainter = new LayeredPainter( [tCliff, tSnowA], // terrains [3] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 25, 3); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 20, clHill, 15, clWater, 2, clBaseResource, 2), scaleByMapSize(1, 4) * numPlayers ); // calculate desired number of trees for map (based on size) var MIN_TREES = 100; var MAX_TREES = 625; var P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [ [[tSnowA, tSnowA, tSnowA, tSnowA, pForestD], [tSnowA, tSnowA, tSnowA, pForestD]], [[tSnowA, tSnowA, tSnowA, tSnowA, pForestS], [tSnowA, tSnowA, tSnowA, pForestS]] ]; // some variation var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / (num * floor(scaleByMapSize(2,4))), 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clForest, 20, clHill, 0, clWater, 8), num ); } log("Creating iceberg..."); // create iceberg group = new SimpleGroup([new SimpleObject(aIceberg, 0,2, 0,4)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clRock, 6), stayClasses(clWater, 4)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(70); // create dirt patches log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [tSnowD,tSnowB,tSnowC], // terrains [2,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 20, clDirt, 16), scaleByMapSize(20, 80) ); } var sizes = [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [tSnowE,tSnowE], // terrains [1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 20, clDirt, 16), scaleByMapSize(20, 80) ); } log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(8,32), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(8,32), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), scaleByMapSize(8,32), 100 ); RMS.SetProgress(95); // create straggler trees log("Creating straggler trees..."); var types = [oPine]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), num ); } // create deer log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oWalrus, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); RMS.SetProgress(75); // create sheep log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oWolf, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); // create fish log("Creating fish..."); group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); createObjectGroups(group, 0, [avoidClasses(clFood, 20), stayClasses(clWater, 6)], 25 * numPlayers, 60 ); setSunColor(0.6, 0.6, 0.6); setSunElevation(PI/ 6); setWaterColor(0.02, 0.17, 0.52); setWaterTint(0.494, 0.682, 0.808); setWaterMurkiness(0.82); setWaterWaviness(0.5); setWaterType("ocean"); setFogFactor(0.95); setFogThickness(0.09); setPPSaturation(0.28); setPPEffect("hdr"); setSkySet("fog"); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/phoenician_levant.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/phoenician_levant.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/phoenician_levant.js (revision 19443) @@ -1,501 +1,501 @@ RMS.LoadLibrary("rmgen"); //TILE_CENTERED_HEIGHT_MAP = true; const tCity = "medit_city_pavement"; const tCityPlaza = "medit_city_pavement"; const tHill = ["medit_dirt", "medit_dirt_b", "medit_dirt_c", "medit_rocks_grass", "medit_rocks_grass"]; const tMainDirt = "medit_dirt"; const tCliff = "medit_cliff_aegean"; const tForestFloor = "medit_rocks_shrubs"; const tGrass = "medit_rocks_grass"; const tRocksShrubs = "medit_rocks_shrubs"; const tRocksGrass = "medit_rocks_grass"; const tDirt = "medit_dirt_b"; const tDirtB = "medit_dirt_c"; const tShore = "medit_sand"; const tWater = "medit_sand_wet"; // gaia entities const oGrapeBush = "gaia/flora_bush_grapes"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fauna_fish"; const oSheep = "gaia/fauna_sheep"; const oGoat = "gaia/fauna_goat"; const oStoneLarge = "gaia/geology_stonemine_medit_quarry"; const oStoneSmall = "gaia/geology_stone_mediterranean"; const oMetalLarge = "gaia/geology_metal_mediterranean_slabs"; const oDatePalm = "gaia/flora_tree_cretan_date_palm_short"; const oSDatePalm = "gaia/flora_tree_cretan_date_palm_tall"; const oCarob = "gaia/flora_tree_carob"; const oFanPalm = "gaia/flora_tree_medit_fan_palm"; const oPoplar = "gaia/flora_tree_poplar_lombardy"; const oCypress = "gaia/flora_tree_cypress"; // decorative props const aBush1 = "actor|props/flora/bush_medit_sm.xml"; const aBush2 = "actor|props/flora/bush_medit_me.xml"; const aBush3 = "actor|props/flora/bush_medit_la.xml"; const aBush4 = "actor|props/flora/bush_medit_me.xml"; const aBushes = [aBush1, aBush2, aBush3, aBush4]; const aDecorativeRock = "actor|geology/stone_granite_med.xml"; // terrain + entity (for painting) const pForest = [tForestFloor + TERRAIN_SEPARATOR + oDatePalm, tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor + TERRAIN_SEPARATOR + oCarob, tForestFloor, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); var clGrass = createTileClass(); var clHill = createTileClass(); var clIsland = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerPos = new Array(numPlayers); for (var i = 0; i < numPlayers; i++) { playerPos[i] = (i + 1) / (numPlayers + 1); playerZ[i] = playerPos[i]; playerX[i] = 0.66 + 0.2*(i%2); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = floor(fx); var iz = floor(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tCityPlaza, tCity], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oGrapeBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 12; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create starting trees var num = 2; var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oCarob, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aBush1, clBaseResource, radius); } RMS.SetProgress(30); log("Creating sea"); var theta = randFloat(0, 1); var seed = randFloat(2,3); for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var x = ix / (mapSize + 1.0); var z = iz / (mapSize + 1.0); // add the rough shape of the water var km = 20/scaleByMapSize(35, 160); var cu = km*rndRiver(theta+z*0.5*(mapSize/64),seed); var fadeDist = 0.05; if (x < cu + 0.5) { var h; if (x < (cu + 0.5 + fadeDist)) { h = 1 + 4.0 * (1 - ((cu + 0.5 + fadeDist) - x)/fadeDist); } else { h = -3.0; } if (h < -1.5) { placeTerrain(ix, iz, tWater); } else { placeTerrain(ix, iz, tShore); } setHeight(ix, iz, h); if (h < 0){ addToClass(ix, iz, clWater); } } } } RMS.SetProgress(40); // create bumps log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, avoidClasses(clWater, 2, clPlayer, 20), scaleByMapSize(100, 200) ); // create hills log("Creating hills..."); placer = new ChainPlacer(1, floor(scaleByMapSize(4, 6)), floor(scaleByMapSize(16, 40)), 0.5); var terrainPainter = new LayeredPainter( [tCliff, tHill], // terrains [2] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 15, 2); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], avoidClasses(clPlayer, 20, clForest, 1, clHill, 15, clWater, 0), scaleByMapSize(1, 4) * numPlayers * 3 ); // calculate desired number of trees for map (based on size) const MIN_TREES = 500; const MAX_TREES = 2500; const P_FOREST = 0.5; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var num = scaleByMapSize(10,42); placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / (num * floor(scaleByMapSize(2,5))), 0.5); painter = new TerrainPainter([tForestFloor, pForest]); createAreas(placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clForest, 10, clWater, 1, clHill, 1, clBaseResource, 3), num, 50 ); RMS.SetProgress(50); // create grass patches log("Creating grass patches..."); var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [[tGrass,tRocksShrubs],[tRocksShrubs,tRocksGrass], [tRocksGrass,tGrass]], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clForest, 0, clGrass, 5, clPlayer, 10, clWater, 4, clDirt, 5, clHill, 1), scaleByMapSize(15, 45) ); } RMS.SetProgress(55); // create dirt patches log("Creating dirt patches..."); var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 0.5); painter = new LayeredPainter( [[tDirt,tDirtB],[tDirt,tMainDirt], [tDirtB,tMainDirt]], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clForest, 0, clDirt, 5, clPlayer, 10, clWater, 4, clGrass, 5, clHill, 1), scaleByMapSize(15, 45) ); } RMS.SetProgress(60); // create cyprus log("Creating cyprus..."); placer = new ClumpPlacer(4.5 * scaleByMapSize(60, 540), 0.2, 0.1, 0.01); var terrainPainter = new LayeredPainter( [tShore, tHill], // terrains [12] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 6, 8); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clIsland)], [stayClasses (clWater, 5)], 1 ); log("Creating cyprus stone mines..."); // create cyprus large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, stayClasses(clIsland, 9), 14 * scaleByMapSize(4,16), 100 ); // create cyprus small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, stayClasses(clIsland, 9), 14 * scaleByMapSize(4,16), 100 ); log("Creating cyprus metal mines..."); // create cyprus large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, stayClasses(clIsland, 9), 14 * scaleByMapSize(4,16), 100 ); log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 3, clHill, 1), scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 3, clHill, 1), scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 3, clHill, 1), scaleByMapSize(4,16), 100 ); RMS.SetProgress(65); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aDecorativeRock, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1), scaleByMapSize(16, 262), 50 ); // create shrubs log("Creating shrubs..."); group = new SimpleGroup( [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2), new SimpleObject(aBush4, 1,2, 0,1), new SimpleObject(aBush3, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 3, clPlayer, 0, clHill, 1), scaleByMapSize(40, 360), 50 ); RMS.SetProgress(70); // create fish log("Creating fish..."); group = new SimpleGroup([new SimpleObject(oFish, 1,3, 2,6)], true, clFood); createObjectGroups(group, 0, [avoidClasses(clIsland, 2, clFood, 10), stayClasses(clWater, 5)], 3*scaleByMapSize(5,20), 50 ); // create sheeps log("Creating sheeps..."); group = new SimpleGroup([new SimpleObject(oSheep, 5,7, 0,4)], true, clFood); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), scaleByMapSize(5,20), 50 ); // create goats log("Creating goats..."); group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), scaleByMapSize(5,20), 50 ); // create deers log("Creating deers..."); group = new SimpleGroup([new SimpleObject(oDeer, 2,4, 0,2)], true, clFood); createObjectGroups(group, 0, avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), scaleByMapSize(5,20), 50 ); // create grape bushes log("Creating grape bushes..."); group = new SimpleGroup( [new SimpleObject(oGrapeBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 15, clHill, 1, clFood, 7), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); RMS.SetProgress(90); // create straggler trees log("Creating straggler trees..."); var types = [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup([new SimpleObject(types[i], 1,1, 0,0)], true); createObjectGroups(group, 0, avoidClasses(clForest, 0, clWater, 1, clPlayer, 8, clMetal, 6, clHill, 1), num ); } log("Creating straggler trees..."); var types = [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress]; // some variation var num = 3*floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup([new SimpleObject(types[i], 1,1, 0,0)], true); createObjectGroups(group, 0, stayClasses(clIsland, 9), num ); } // Set environment setSkySet("sunny"); setSunColor(0.917, 0.828, 0.734); setWaterColor(0.263,0.314,0.631); setWaterTint(0.133, 0.725,0.855); setWaterWaviness(2.0); setWaterType("ocean"); setWaterMurkiness(0.8); setTerrainAmbientColor(0.57, 0.58, 0.55); setUnitsAmbientColor(0.447059, 0.509804, 0.54902); setSunElevation(0.671884); setSunRotation(-0.582913); setFogFactor(0.2); setFogThickness(0.15); setFogColor(0.8, 0.7, 0.6); setPPEffect("hdr"); setPPContrast(0.53); setPPSaturation(0.47); setPPBloom(0.52); // Export map data ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/rhine_marshlands.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rhine_marshlands.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rhine_marshlands.js (revision 19443) @@ -1,456 +1,456 @@ RMS.LoadLibrary("rmgen"); const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; const tForestFloor = "temp_plants_bog"; const tGrassA = "temp_grass_plants"; const tGrassB = "temp_plants_bog"; const tMud = "temp_mud_a"; const tRoad = "temp_road"; const tRoadWild = "temp_road_overgrown"; const tShoreBlend = "temp_grass_plants"; const tShore = "temp_plants_bog"; const tWater = "temp_mud_a"; // gaia entities const oBeech = "gaia/flora_tree_euro_beech"; const oOak = "gaia/flora_tree_oak"; const oBerryBush = "gaia/flora_bush_berry"; const oDeer = "gaia/fauna_deer"; const oHorse = "gaia/fauna_horse"; const oWolf = "gaia/fauna_wolf"; const oFish = "gaia/fauna_fish"; const oRabbit = "gaia/fauna_rabbit"; const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; const oStoneSmall = "gaia/geology_stone_temperate"; const oMetalLarge = "gaia/geology_metal_temperate_slabs"; // decorative props const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; const aGrassShort = "actor|props/flora/grass_soft_large.xml"; const aRockLarge = "actor|geology/stone_granite_med.xml"; const aRockMedium = "actor|geology/stone_granite_med.xml"; const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; const aLillies = "actor|props/flora/water_lillies.xml"; const aBushMedium = "actor|props/flora/bush_medit_me.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oBeech, tForestFloor]; const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor]; log("Initializing map..."); InitMap(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new LayeredPainter([tRoadWild, tRoad], [1]); createArea(placer, painter, null); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = radius - 4; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oStoneLarge, 1,1, 0,2)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 100); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = 12; var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oBeech, num, num, 0,5)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius); } RMS.SetProgress(15); // create bumps log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 2, 2); createAreas( placer, painter, avoidClasses(clPlayer, 13), scaleByMapSize(300, 800) ); // create marshes log("Creating marshes..."); for (var i = 0; i < 7; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(6, 12)), floor(scaleByMapSize(15, 60)), 0.8); var terrainPainter = new LayeredPainter( [tShoreBlend, tShore, tWater], // terrains [1,1] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -2, 3); var waterAreas = createAreas( placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 20, clWater, round(scaleByMapSize(7,16)*randFloat(0.8,1.35))), scaleByMapSize(4,20) ); } // create reeds log("Creating reeds..."); group = new SimpleGroup( [new SimpleObject(aReeds, 5,10, 0,4), new SimpleObject(aLillies, 5,10, 0,4)], true ); createObjectGroups(group, 0, stayClasses(clWater, 1), scaleByMapSize(400,2000), 100 ); waterAreas = []; RMS.SetProgress(40); // create bumps log("Creating bumps..."); placer = new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1); painter = new SmoothElevationPainter(ELEVATION_MODIFY, 1, 2); createAreas( placer, painter, stayClasses(clWater, 2), scaleByMapSize(50, 100) ); // calculate desired number of trees for map (based on size) const MIN_TREES = 500; const MAX_TREES = 2500; const P_FOREST = 0.7; var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; var numStragglers = totalTrees * (1.0 - P_FOREST); // create forests log("Creating forests..."); var types = [ [[tForestFloor, tGrass, pForestD], [tForestFloor, pForestD]], [[tForestFloor, tGrass, pForestP], [tForestFloor, pForestP]] ]; // some variation var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / (num * floor(scaleByMapSize(2,4))), 1); painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(clForest)], avoidClasses(clPlayer, 20, clWater, 0, clForest, 10, clHill, 1), num ); } RMS.SetProgress(50); // create mud patches log("Creating mud patches..."); var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; for (var i = 0; i < sizes.length; i++) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 1); painter = new LayeredPainter( [tGrassA, tGrassB, tMud], // terrains [1,1] // widths ); createAreas( placer, [painter, paintClass(clDirt)], avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 8), scaleByMapSize(15, 45) ); } log("Creating stone mines..."); // create large stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1)], scaleByMapSize(4,16), 100 ); // create small stone quarries group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1)], scaleByMapSize(4,16), 100 ); log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1)], scaleByMapSize(4,16), 100 ); RMS.SetProgress(60); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(16, 262), 50 ); RMS.SetProgress(65); // create large decorative rocks log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(8, 131), 50 ); RMS.SetProgress(70); // create deer log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), 6 * numPlayers, 50 ); // create horse log("Creating horse..."); group = new SimpleGroup( [new SimpleObject(oHorse, 1,3, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), 3 * numPlayers, 50 ); RMS.SetProgress(75); // create rabbit log("Creating rabbit..."); group = new SimpleGroup( [new SimpleObject(oRabbit, 5,7, 0,2)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), 6 * numPlayers, 50 ); // create wolf log("Creating wolf..."); group = new SimpleGroup( [new SimpleObject(oWolf, 1,3, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), 3 * numPlayers, 50 ); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); RMS.SetProgress(80); // create straggler trees log("Creating straggler trees..."); var types = [oOak, oBeech]; // some variation var num = floor(numStragglers / types.length); for (var i = 0; i < types.length; ++i) { group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clForest, 1, clHill, 1, clPlayer, 13, clMetal, 6, clRock, 6, clWater, 0), num ); } RMS.SetProgress(85); //create small grass tufts log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 2, clHill, 2, clPlayer, 13, clDirt, 0), scaleByMapSize(13, 200) ); RMS.SetProgress(90); // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -PI/8,PI/8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clHill, 2, clPlayer, 13, clDirt, 1, clForest, 0), scaleByMapSize(13, 200) ); RMS.SetProgress(95); // create bushes log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clHill, 1, clPlayer, 13, clDirt, 1), scaleByMapSize(13, 200), 50 ); // Set environment setSkySet("cirrus"); setWaterColor(0.753,0.635,0.345); // muddy brown setWaterTint(0.161,0.514,0.635); // clear blue for blueness setWaterMurkiness(0.8); setWaterWaviness(1.0); setWaterType("clap"); setFogThickness(0.25); setFogFactor(0.6); setPPEffect("hdr"); setPPSaturation(0.44); setPPBloom(0.3); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/misc.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/misc.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/misc.js (revision 19443) @@ -1,806 +1,804 @@ ///////////////////////////////////////////////////////////////////////////////////////// // passageMaker // // Function for creating shallow water between two given points by changing the heiight of all tiles in // the path with height less than or equal to "maxheight" to "height" // // x1,z1: Starting point of path // x2,z2: Ending point of path // width: Width of the shallow // maxheight: Maximum height that it changes // height: Height of the shallow // smooth: smooth elevation in borders // tileclass: (Optianal) - Adds those tiles to the class given // terrain: (Optional) - Changes the texture of the elevated land // ///////////////////////////////////////////////////////////////////////////////////////// function passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain, riverheight) { var tchm = TILE_CENTERED_HEIGHT_MAP; TILE_CENTERED_HEIGHT_MAP = true; var mapSize = g_Map.size; for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var a = z1-z2; var b = x2-x1; var c = (z1*(x1-x2))-(x1*(z1-z2)); var dis = abs(a*ix + b*iz + c)/sqrt(a*a + b*b); var k = (a*ix + b*iz + c)/(a*a + b*b); var my = iz-(b*k); var inline = 0; if (b == 0) { dis = abs(ix-x1); if ((iz <= Math.max(z1,z2))&&(iz >= Math.min(z1,z2))) { inline = 1; } } else { if ((my <= Math.max(z1,z2))&&(my >= Math.min(z1,z2))) { inline = 1; } } if ((dis <= width)&&(inline)) { if(g_Map.getHeight(ix, iz) <= maxheight) { if (dis > width - smooth) { g_Map.setHeight(ix, iz, ((width - dis)*(height)+(riverheight)*(smooth - width + dis))/(smooth)); } else if (dis <= width - smooth) { g_Map.setHeight(ix, iz, height); } if (tileclass !== undefined) { addToClass(ix, iz, tileclass); } if (terrain !== undefined) { placeTerrain(ix, iz, terrain); } } } } } TILE_CENTERED_HEIGHT_MAP = tchm; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //rndRiver is a fuction that creates random values useful for making a jagged river. // //it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi //it needs the "seed" parameter to use it to make random curves that don't get broken. //seed must be created using randFloat(). or else it won't work // // f: Input: Same as angle in a sine function // seed: Random Seed: Best to implement is to use randFloat() // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function rndRiver(f, seed) { var rndRq = seed; var rndRw = rndRq; var rndRe = 0; var rndRr = f-floor(f); var rndRa = 0; for (var rndRx=0; rndRx<=floor(f); rndRx++) { rndRw = 10*(rndRw-floor(rndRw)); } if (rndRx%2==0) { var rndRs = -1; } else { var rndRs = 1; } rndRe = (floor(rndRw))%5; if (rndRe==0) { rndRa = (rndRs)*2.3*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.5); } else if (rndRe==1) { rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.3)*(rndRr-0.7); } else if (rndRe==2) { rndRa = (rndRs)*22*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.3)*(rndRr-0.3)*(rndRr-0.8); } else if (rndRe==3) { rndRa = (rndRs)*180*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.2)*(rndRr-0.4)*(rndRr-0.6)*(rndRr-0.6)*(rndRr-0.8); } else if (rndRe==4) { rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.7); } return rndRa; } ///////////////////////////////////////////////////////////////////////////////////////// // createStartingPlayerEntities // // Creates the starting player entities // fx&fz: position of player base // playerid: id of player // civEntities: use getStartingEntities(id-1) fo this one // orientation: orientation of the main base building, default is BUILDING_ORIENTATION // /////////////////////////////////////////////////////////////////////////////////////////// function createStartingPlayerEntities(fx, fz, playerid, civEntities, orientation = BUILDING_ORIENTATION) { var uDist = 6; var uSpace = 2; placeObject(fx, fz, civEntities[0].Template, playerid, orientation); for (var j = 1; j < civEntities.length; ++j) { var uAngle = orientation - PI * (2-j) / 2; var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); placeObject(ux, uz, civEntities[j].Template, playerid, uAngle); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeCivDefaultEntities // // Creates the default starting player entities depending on the players civ // fx&fy: position of player base // playerid: id of player // kwargs: Takes some optional keyword arguments to tweek things // 'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus // 'orientation': angle of the main base building, default is BUILDING_ORIENTATION // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeCivDefaultEntities(fx, fz, playerid, kwargs = {}) { // Unpack kwargs var iberWall = 'walls'; if (getMapSize() <= 128) iberWall = false; if ('iberWall' in kwargs) iberWall = kwargs['iberWall']; var orientation = BUILDING_ORIENTATION; if ('orientation' in kwargs) orientation = kwargs['orientation']; // Place default civ starting entities var civ = getCivCode(playerid-1); var civEntities = getStartingEntities(playerid-1); var uDist = 6; var uSpace = 2; placeObject(fx, fz, civEntities[0].Template, playerid, orientation); for (var j = 1; j < civEntities.length; ++j) { var uAngle = orientation - PI * (2-j) / 2; var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); placeObject(ux, uz, civEntities[j].Template, playerid, uAngle); } } // Add defensive structiures for Iberians as their civ bonus if (civ == 'iber' && iberWall != false) { if (iberWall == 'towers') placePolygonalWall(fx, fz, 15, ['entry'], 'tower', civ, playerid, orientation, 7); else placeGenericFortress(fx, fz, 20/*radius*/, playerid); } } function placeDefaultChicken(playerX, playerZ, tileClass, constraint = undefined, template = "gaia/fauna_chicken") { for (let j = 0; j < 2; ++j) for (var tries = 0; tries < 10; ++tries) { let aAngle = randFloat(0, TWO_PI); // Roman and ptolemian civic centers have a big footprint! let aDist = 9; let aX = round(playerX + aDist * cos(aAngle)); let aZ = round(playerZ + aDist * sin(aAngle)); let group = new SimpleGroup( [new SimpleObject(template, 5,5, 0,2)], true, tileClass, aX, aZ ); if (createObjectGroup(group, 0, constraint)) break; } } /** * Typically used for placing grass tufts around the civic centers. */ function placeDefaultDecoratives(playerX, playerZ, template, tileclass, radius, constraint = undefined) { for (let i = 0; i < PI * radius * radius / 250; ++i) { let angle = randFloat(0, 2 * PI); let dist = radius - randIntInclusive(5, 11); createObjectGroup( new SimpleGroup( [new SimpleObject(template, 2, 5, 0, 1, -PI/8, PI/8)], false, tileclass, Math.round(playerX + dist * Math.cos(angle)), Math.round(playerZ + dist * Math.sin(angle)) ), 0, constraint); } } ///////////////////////////////////////////////////////////////////////////////////////// // paintTerrainBasedOnHeight // // paints the tiles which have a height between minheight and maxheight with the given terrain // minheight: minimum height of the tile // maxheight: maximum height of the tile // mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight. // 1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than // minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight // terrain: intended terrain texture // /////////////////////////////////////////////////////////////////////////////////////////// function paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain) { var mSize = g_Map.size; for (var qx = 0; qx < mSize; qx++) { for (var qz = 0; qz < mSize; qz++) { if (mode == 0) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 1) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 2) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 3) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { placeTerrain(qx, qz, terrain); } } } } } ///////////////////////////////////////////////////////////////////////////////////////// // paintTileClassBasedOnHeight and unPaintTileClassBasedOnHeight // // paints or unpaints the tiles which have a height between minheight and maxheight with the given tile class // minheight: minimum height of the tile // maxheight: maximum height of the tile // mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight. // 1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than // minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight // tileclass: intended tile class // /////////////////////////////////////////////////////////////////////////////////////////// function paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) { var mSize = g_Map.size; for (var qx = 0; qx < mSize; qx++) { for (var qz = 0; qz < mSize; qz++) { if (mode == 0) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 1) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 2) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 3) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { addToClass(qx, qz, tileclass); } } } } } function unPaintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) { var mSize = g_Map.size; for (var qx = 0; qx < mSize; qx++) { for (var qz = 0; qz < mSize; qz++) { if (mode == 0) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { removeFromClass(qx, qz, tileclass); } } else if (mode == 1) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { removeFromClass(qx, qz, tileclass); } } else if (mode == 2) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { removeFromClass(qx, qz, tileclass); } } else if (mode == 3) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { removeFromClass(qx, qz, tileclass); } } } } } ///////////////////////////////////////////////////////////////////////////////////////// // getTIPIADBON // // "get The Intended Point In A Direction Based On Height" // gets the N'th point with a specific height in a line and returns it as a [x, y] array // startPoint: [x, y] array defining the start point // endPoint: [x, y] array defining the ending point // heightRange: [min, max] array defining the range which the height of the intended point can be. includes both "min" and "max" // step: how much tile units per turn should the search go. more value means faster but less accurate // n: how many points to skip before ending the search. skips """n-1 points""". // /////////////////////////////////////////////////////////////////////////////////////////// function getTIPIADBON(startPoint, endPoint, heightRange, step, n) { var stepX = step*(endPoint[0]-startPoint[0])/(sqrt((endPoint[0]-startPoint[0])*(endPoint[0]-startPoint[0]) + step*(endPoint[1]-startPoint[1])*(endPoint[1]-startPoint[1]))); var stepY = step*(endPoint[1]-startPoint[1])/(sqrt((endPoint[0]-startPoint[0])*(endPoint[0]-startPoint[0]) + step*(endPoint[1]-startPoint[1])*(endPoint[1]-startPoint[1]))); var y = startPoint[1]; var checked = 0; for (var x = startPoint[0]; true; x += stepX) { if ((floor(x) < g_Map.size)||(floor(y) < g_Map.size)) { if ((g_Map.getHeight(floor(x), floor(y)) <= heightRange[1])&&(g_Map.getHeight(floor(x), floor(y)) >= heightRange[0])) { ++checked; } if (checked >= n) { return [x, y]; } } y += stepY; if ((y > endPoint[1])&&(stepY>0)) break; if ((y < endPoint[1])&&(stepY<0)) break; if ((x > endPoint[1])&&(stepX>0)) break; if ((x < endPoint[1])&&(stepX<0)) break; } return undefined; } ///////////////////////////////////////////////////////////////////////////////////////// // doIntersect // // determines if two lines with the width "width" intersect or collide with each other // x1, y1, x2, y2: determine the position of the first line // x3, y3, x4, y4: determine the position of the second line // width: determines the width of the lines // /////////////////////////////////////////////////////////////////////////////////////////// function checkIfIntersect (x1, y1, x2, y2, x3, y3, x4, y4, width) { if (x1 == x2) { if (((x3 - x1) < width) || ((x4 - x2) < width)) return true; } else { var m = (y1 - y2) / (x1 - x2); var b = y1 - m * x1; var m2 = sqrt(m * m + 1); if ((Math.abs((y3 - x3 * m - b)/m2) < width) || (Math.abs((y4 - x4 * m - b)/m2) < width)) return true; //neccessary for some situations. if (x3 == x4) { if (((x1 - x3) < width) || ((x2 - x4) < width)) return true; } else { var m = (y3 - y4) / (x3 - x4); var b = y3 - m * x3; var m2 = sqrt(m * m + 1); if ((Math.abs((y1 - x1 * m - b)/m2) < width) || (Math.abs((y2 - x2 * m - b)/m2) < width)) return true; } } var s = ((x1 - x2) * (y3 - y1) - (y1 - y2) * (x3 - x1)), p = ((x1 - x2) * (y4 - y1) - (y1 - y2) * (x4 - x1)); if ((s * p) <= 0) { s = ((x3 - x4) * (y1 - y3) - (y3 - y4) * (x1 - x3)); p = ((x3 - x4) * (y2 - y3) - (y3 - y4) * (x2 - x3)); if ((s * p) <= 0) return true; } return false; } ///////////////////////////////////////////////////////////////////////////////////////// // distanceOfPointFromLine // // returns the distance of a point from a line // x1, y1, x2, y2: determine the position of the line // x3, y3: determine the position of the point // /////////////////////////////////////////////////////////////////////////////////////////// function distanceOfPointFromLine (x1, y1, x2, y2, x3, y3) { if (x1 == x2) { return Math.abs(x3 - x1); } else if (y1 == y2) { return Math.abs(y3 - y1); } else { var m = (y1 - y2) / (x1 - x2); var b = y1 - m * x1; var m2 = sqrt(m * m + 1); return Math.abs((y3 - x3 * m - b)/m2); } } ///////////////////////////////////////////////////////////////////////////////////////// // createRamp // // creates a ramp from point (x1, y1) to (x2, y2). // x1, y1, x2, y2: determine the position of the start and end of the ramp // minHeight, maxHeight: determine the height levels of the start and end point // width: determines the width of the ramp // smoothLevel: determines the smooth level around the edges of the ramp // mainTerrain: (Optional) determines the terrain texture for the ramp // edgeTerrain: (Optional) determines the terrain texture for the edges // tileclass: (Optional) adds the ramp to this tile class // /////////////////////////////////////////////////////////////////////////////////////////// function createRamp (x1, y1, x2, y2, minHeight, maxHeight, width, smoothLevel, mainTerrain, edgeTerrain, tileclass) { var halfWidth = width / 2; var mapSize = g_Map.size; if (y1 == y2) { var x3 = x2; var y3 = y2 + halfWidth; } else { var m = (x1 - x2) / (y1 - y2); var b = y2 + m * x2; var x3 = x2 + halfWidth; var y3 = - m * x3 + b; } var minBoundX = (x1 <= x2 ? (x1 > halfWidth ? x1 - halfWidth : 0) : (x2 > halfWidth ? x2 - halfWidth : 0)); var maxBoundX = (x1 >= x2 ? (x1 < mapSize - halfWidth ? x1 + halfWidth : mapSize) : (x2 < mapSize - halfWidth ? x2 + halfWidth : mapSize)); var minBoundY = (y1 <= y2 ? (y1 > halfWidth ? y1 - halfWidth : 0) : (y2 > halfWidth ? y2 - halfWidth : 0)); var maxBoundY = (y1 >= y2 ? (x1 < mapSize - halfWidth ? y1 + halfWidth : mapSize) : (y2 < mapSize - halfWidth ? y2 + halfWidth : mapSize)); for (var x = minBoundX; x < maxBoundX; ++x) { for (var y = minBoundY; y < maxBoundY; ++y) { var lDist = distanceOfPointFromLine(x3, y3, x2, y2, x, y); var sDist = distanceOfPointFromLine(x1, y1, x2, y2, x, y); var rampLength = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); if (lDist <= rampLength && sDist <= halfWidth) { var h = ((rampLength - lDist) * maxHeight + lDist * minHeight) / rampLength; if (sDist >= halfWidth - smoothLevel) { h = (h - minHeight) * (halfWidth - sDist) / smoothLevel + minHeight; if (edgeTerrain !== undefined) placeTerrain(x, y, edgeTerrain); } else { if (mainTerrain !== undefined) placeTerrain(x, y, mainTerrain); } if (tileclass !== undefined) addToClass(x, y, tileclass); if((g_Map.getHeight(floor(x), floor(y)) < h) && (h <= maxHeight)) g_Map.setHeight(x, y, h); } } } } ///////////////////////////////////////////////////////////////////////////////////////// // createMountain // // creates a mountain using a tecnique very similar to chain placer. // /////////////////////////////////////////////////////////////////////////////////////////// function createMountain(maxHeight, minRadius, maxRadius, numCircles, constraint, x, z, terrain, tileclass, fcc, q) { fcc = (fcc !== undefined ? fcc : 0); q = (q !== undefined ? q : []); // checking for an array of constraints if (constraint instanceof Array) { var constraintArray = constraint; constraint = new AndConstraint(constraintArray); } // Preliminary bounds check if (!g_Map.inMapBounds(x, z) || !constraint.allows(x, z)) { return; } var size = getMapSize(); var queueEmpty = (q.length ? false : true); var gotRet = new Array(size); for (var i = 0; i < size; ++i) { gotRet[i] = new Array(size); for (var j = 0; j < size; ++j) { gotRet[i][j] = -1; } } --size; if (minRadius < 1) minRadius = 1; if (minRadius > maxRadius) minRadius = maxRadius; var edges = [[x, z]]; var circles = []; for (var i = 0; i < numCircles; ++i) { var badPoint = false; var [cx, cz] = pickRandom(edges); if (queueEmpty) - { - var radius = randInt(minRadius, maxRadius); - } + var radius = randIntInclusive(minRadius, maxRadius); else { var radius = q.pop(); queueEmpty = (q.length ? false : true); } var sx = cx - radius, lx = cx + radius; var sz = cz - radius, lz = cz + radius; sx = (sx < 0 ? 0 : sx); sz = (sz < 0 ? 0 : sz); lx = (lx > size ? size : lx); lz = (lz > size ? size : lz); var radius2 = radius * radius; var dx, dz, distance2; //log (uneval([sx, sz, lx, lz])); for (var ix = sx; ix <= lx; ++ix) { for (var iz = sz; iz <= lz; ++ iz) { dx = ix - cx; dz = iz - cz; distance2 = dx * dx + dz * dz; if (dx * dx + dz * dz <= radius2) { if (g_Map.inMapBounds(ix, iz)) { if (!constraint.allows(ix, iz)) { badPoint = true; break; } var state = gotRet[ix][iz]; if (state == -1) { gotRet[ix][iz] = -2; } else if (state >= 0) { var s = edges.splice(state, 1); gotRet[ix][iz] = -2; var edgesLength = edges.length; for (var k = state; k < edges.length; ++k) { --gotRet[edges[k][0]][edges[k][1]]; } } } } } if (badPoint) break; } if (badPoint) continue; else circles.push([cx, cz, radius]); for (var ix = sx; ix <= lx; ++ix) { for (var iz = sz; iz <= lz; ++ iz) { if (fcc) if ((x - ix) > fcc || (ix - x) > fcc || (z - iz) > fcc || (iz - z) > fcc) continue; if (gotRet[ix][iz] == -2) { if (ix > 0) { if (gotRet[ix-1][iz] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } if (iz > 0) { if (gotRet[ix][iz-1] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } if (ix < size) { if (gotRet[ix+1][iz] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } if (iz < size) { if (gotRet[ix][iz+1] == -1) { edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; continue; } } } } } } var numFinalCircles = circles.length; for (var i = 0; i < numFinalCircles; ++i) { var point = circles[i]; var cx = point[0], cz = point[1], radius = point[2]; var sx = cx - radius, lx = cx + radius; var sz = cz - radius, lz = cz + radius; sx = (sx < 0 ? 0 : sx); sz = (sz < 0 ? 0 : sz); lx = (lx > size ? size : lx); lz = (lz > size ? size : lz); var radius2 = radius * radius; var dx, dz, distance2; var clumpHeight = (radius/maxRadius)*maxHeight*randFloat(0.8,1.2); for (var ix = sx; ix <= lx; ++ix) { for (var iz = sz; iz <= lz; ++ iz) { dx = ix - cx; dz = iz - cz; distance2 = dx * dx + dz * dz; - var newHeight = round((Math.sin(PI*(2*((radius - sqrt(distance2))/radius)/3 - 1/6)) + 0.5) * 2 / 3 *clumpHeight) + randInt(0,2); + var newHeight = Math.round((Math.sin(PI * (2 * ((radius - Math.sqrt(distance2)) / radius) / 3 - 1/6)) + 0.5) * 2/3 * clumpHeight) + randIntInclusive(0, 2); if (dx * dx + dz * dz <= radius2) { if (g_Map.getHeight(ix, iz) < newHeight) g_Map.setHeight(ix, iz, newHeight); else if (g_Map.getHeight(ix, iz) >= newHeight && g_Map.getHeight(ix, iz) < newHeight + 4) g_Map.setHeight(ix, iz, newHeight + 4); if (terrain !== undefined) placeTerrain(ix, iz, terrain); if (tileclass !== undefined) addToClass(ix, iz, tileclass); } } } } } Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/utilityfunctions.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/utilityfunctions.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/utilityfunctions.js (revision 19443) @@ -1,278 +1,278 @@ var g_numStragglerTrees = 0; function createBumps(constraint, count, minsize, maxsize, spread, failfraction, elevation) { log("Creating bumps..."); constraint = (constraint !== undefined ? constraint : avoidClasses(clPlayer, 20)); minsize = (minsize !== undefined ? minsize : 1); maxsize = (maxsize !== undefined ? maxsize : floor(scaleByMapSize(4, 6))); spread = (spread !== undefined ? spread : floor(scaleByMapSize(2, 5))); failfraction = (failfraction !== undefined ? failfraction : 0); elevation = (elevation !== undefined ? elevation : 2); count = (count !== undefined ? count : scaleByMapSize(100, 200)); var placer = new ChainPlacer(minsize, maxsize, spread, failfraction); var painter = new SmoothElevationPainter(ELEVATION_MODIFY, elevation, 2); createAreas( placer, painter, constraint, count ); } function createHills(terrainset, constraint, tileclass, count, minsize, maxsize, spread, failfraction, elevation, elevationsmooth) { log("Creating hills..."); tileclass = (tileclass !== undefined ? tileclass : clHill); constraint = (constraint !== undefined ? constraint : avoidClasses(clPlayer, 20, clHill, 15)); count = (count !== undefined ? count : scaleByMapSize(1, 4) * getNumPlayers()); minsize = (minsize !== undefined ? minsize : 1); maxsize = (maxsize !== undefined ? maxsize : floor(scaleByMapSize(4, 6))); spread = (spread !== undefined ? spread : floor(scaleByMapSize(16, 40))); failfraction = (failfraction !== undefined ? failfraction : 0.5); elevation = (elevation !== undefined ? elevation : 18); elevationsmooth = (elevationsmooth !== undefined ? elevationsmooth : 2); var placer = new ChainPlacer(minsize, maxsize, spread, failfraction); var terrainPainter = new LayeredPainter( terrainset, // terrains [1, elevationsmooth] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, elevation, elevationsmooth); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clHill)], constraint, count ); } function createMountains(terrain, constraint, tileclass, count, maxHeight, minRadius, maxRadius, numCircles) { log("Creating mountains..."); tileclass = tileclass !== undefined ? tileclass : clHill; constraint = constraint !== undefined ? constraint : avoidClasses(clPlayer, 20, clHill, 15); count = count !== undefined ? count : scaleByMapSize(1, 4) * getNumPlayers(); maxHeight = maxHeight !== undefined ? maxHeight : floor(scaleByMapSize(30, 50)); minRadius = minRadius !== undefined ? minRadius : floor(scaleByMapSize(3, 4)); maxRadius = maxRadius !== undefined ? maxRadius : floor(scaleByMapSize(6, 12)); numCircles = numCircles !== undefined ? numCircles : floor(scaleByMapSize(4, 10)); var numHills = count; for (var i = 0; i < numHills; ++i) createMountain( maxHeight, minRadius, maxRadius, numCircles, constraint, - randInt(mapSize), - randInt(mapSize), + randIntExclusive(0, mapSize), + randIntExclusive(0, mapSize), terrain, tileclass, 14 ); } function createForests(terrainset, constraint, tileclass, numMultiplier, biomeID) { log("Creating forests..."); tileclass = (tileclass !== undefined ? tileclass : clForest); constraint = (constraint !== undefined ? constraint : avoidClasses(clPlayer, 20, clForest, 17, clHill, 0)); numMultiplier = (numMultiplier !== undefined ? numMultiplier : 1.0); biomeID = (biomeID !== undefined ? biomeID : 0); var [tM, tFF1, tFF2, tF1, tF2] = terrainset; if (biomeID == g_BiomeSavanna) { var MIN_TREES = 200 * numMultiplier; var MAX_TREES = 1250 * numMultiplier; var P_FOREST = 0; } else if (biomeID == g_BiomeTropic) { var MIN_TREES = 1000 * numMultiplier; var MAX_TREES = 6000 * numMultiplier; var P_FOREST = 0.52; } else { var MIN_TREES = 500 * numMultiplier; var MAX_TREES = 3000 * numMultiplier; var P_FOREST = 0.7; } var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); var numForest = totalTrees * P_FOREST; g_numStragglerTrees = totalTrees * (1.0 - P_FOREST); log("Creating forests..."); var types = [ [[tFF2, tM, tF1], [tFF2, tF1]], [[tFF1, tM, tF2], [tFF1, tF2]] ]; // some variation if (biomeID != g_BiomeSavanna) { var size = numForest / (scaleByMapSize(3,6) * numPlayers); var num = floor(size / types.length); for (var i = 0; i < types.length; ++i) { var placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), numForest / num, 0.5); var painter = new LayeredPainter( types[i], // terrains [2] // widths ); createAreas( placer, [painter, paintClass(tileclass)], constraint, num ); } } } function createLayeredPatches(sizes, terrainset, twidthset, constraint, count, tileclass, failfraction) { tileclass = (tileclass !== undefined ? tileclass : clDirt); constraint = (constraint !== undefined ? constraint : avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12)); count = (count !== undefined ? count : scaleByMapSize(15, 45)); failfraction = (failfraction !== undefined ? failfraction : 0.5); for (var i = 0; i < sizes.length; i++) { var placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], failfraction); var painter = new LayeredPainter( terrainset, // terrains twidthset // widths ); createAreas( placer, [painter, paintClass(tileclass)], constraint, count ); } } function createPatches(sizes, terrain, constraint, count, tileclass, failfraction) { tileclass = (tileclass !== undefined ? tileclass : clDirt); constraint = (constraint !== undefined ? constraint : avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12)); count = (count !== undefined ? count : scaleByMapSize(15, 45)); failfraction = (failfraction !== undefined ? failfraction : 0.5); for (var i = 0; i < sizes.length; i++) { var placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], failfraction); var painter = new TerrainPainter(terrain); createAreas( placer, [painter, paintClass(tileclass)], constraint, count ); } } function createMines(mines, constraint, tileclass, count) { tileclass = (tileclass !== undefined ? tileclass : clRock); constraint = (constraint !== undefined ? constraint : avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1)); count = (count !== undefined ? count : scaleByMapSize(4,16)); for (var i = 0; i < mines.length; ++i) { var group = new SimpleGroup(mines[i], true, tileclass); createObjectGroups(group, 0, constraint, count, 70 ); } } /** * Places 8 stone mines in a small circular shape. */ function createStoneMineFormation(x, z, tileclass) { var placer = new ChainPlacer(1, 2, 2, 1, x, z, undefined, [5]); var painter = new TerrainPainter(tileclass); createArea(placer, painter, null); var bbAngle = randFloat(0, TWO_PI); const bbDist = 2.5; for (var i = 0; i < 8; ++i) { var bbX = round(x + (bbDist + randFloat(0,1)) * cos(bbAngle)); var bbZ = round(z + (bbDist + randFloat(0,1)) * sin(bbAngle)); placeObject(bbX, bbZ, oStoneSmall, 0, randFloat(0, TWO_PI)); bbAngle += PI / 6; } } function createDecoration(objects, counts, constraint) { log("Creating decoration..."); constraint = (constraint !== undefined ? constraint : avoidClasses(clForest, 0, clPlayer, 0, clHill, 0)); for (var i = 0; i < objects.length; ++i) { var group = new SimpleGroup( objects[i], true ); createObjectGroups( group, 0, constraint, counts[i], 5 ); } } function createFood(objects, counts, constraint, tileclass) { log("Creating food..."); constraint = (constraint !== undefined ? constraint : avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20)); tileclass = (tileclass !== undefined ? tileclass : clFood); for (var i = 0; i < objects.length; ++i) { var group = new SimpleGroup( objects[i], true, tileclass ); createObjectGroups( group, 0, constraint, counts[i], 50 ); } } function createStragglerTrees(types, constraint, tileclass) { log("Creating straggler trees..."); constraint = constraint !== undefined ? constraint : avoidClasses(clForest, 8, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6); tileclass = tileclass !== undefined ? tileclass : clForest; var num = floor(g_numStragglerTrees / types.length); for (var i = 0; i < types.length; ++i) { let group = new SimpleGroup( [new SimpleObject(types[i], 1,1, 0,3)], true, tileclass ); createObjectGroups(group, 0, constraint, num ); } } Index: ps/trunk/binaries/data/mods/public/maps/random/sahel.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/sahel.js (revision 19442) +++ ps/trunk/binaries/data/mods/public/maps/random/sahel.js (revision 19443) @@ -1,359 +1,359 @@ RMS.LoadLibrary("rmgen"); const tGrass1 = "savanna_grass_a"; const tGrass2 = "savanna_grass_b"; const tGrass3 = "savanna_shrubs_a"; const tDirt1 = "savanna_dirt_rocks_a"; const tDirt2 = "savanna_dirt_rocks_b"; const tDirt3 = "savanna_dirt_rocks_c"; const tDirt4 = "savanna_dirt_b"; const tCityTiles = "savanna_tile_a"; const tShore = "savanna_riparian_bank"; const tWater = "savanna_riparian_wet"; // gaia entities const oBaobab = "gaia/flora_tree_baobab"; const oBerryBush = "gaia/flora_bush_berry"; const oGazelle = "gaia/fauna_gazelle"; const oGiraffe = "gaia/fauna_giraffe"; const oGiraffeInfant = "gaia/fauna_giraffe_infant"; const oElephant = "gaia/fauna_elephant_african_bush"; const oElephantInfant = "gaia/fauna_elephant_african_infant"; const oLion = "gaia/fauna_lion"; const oLioness = "gaia/fauna_lioness"; const oZebra = "gaia/fauna_zebra"; const oStoneSmall = "gaia/geology_stone_savanna_small"; const oMetalLarge = "gaia/geology_metal_savanna_slabs"; // decorative props const aBush = "actor|props/flora/bush_medit_sm_dry.xml"; const aRock = "actor|geology/stone_savanna_med.xml"; log("Initializing map..."); InitMap(); var numPlayers = getNumPlayers(); var mapSize = getMapSize(); var mapArea = mapSize*mapSize; // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clSettlement = createTileClass(); // randomize player order var playerIDs = []; for (var i = 0; i < numPlayers; i++) { playerIDs.push(i+1); } playerIDs = sortPlayers(playerIDs); // place players var playerX = new Array(numPlayers); var playerZ = new Array(numPlayers); var playerAngle = new Array(numPlayers); var startAngle = randFloat(0, TWO_PI); for (var i = 0; i < numPlayers; i++) { playerAngle[i] = startAngle + i*TWO_PI/numPlayers; playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); } for (var i = 0; i < numPlayers; i++) { var id = playerIDs[i]; log("Creating base for player " + id + "..."); // some constants var radius = scaleByMapSize(15,25); var cliffRadius = 2; var elevation = 20; // get the x and z in tiles var fx = fractionToTiles(playerX[i]); var fz = fractionToTiles(playerZ[i]); var ix = round(fx); var iz = round(fz); addToClass(ix, iz, clPlayer); addToClass(ix+5, iz, clPlayer); addToClass(ix, iz+5, clPlayer); addToClass(ix-5, iz, clPlayer); addToClass(ix, iz-5, clPlayer); // create starting units placeCivDefaultEntities(fx, fz, id); placeDefaultChicken(fx, fz, clBaseResource); // create berry bushes var bbAngle = randFloat(0, TWO_PI); var bbDist = 12; var bbX = round(fx + bbDist * cos(bbAngle)); var bbZ = round(fz + bbDist * sin(bbAngle)); var group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,5, 0,3)], true, clBaseResource, bbX, bbZ ); createObjectGroup(group, 0); // create metal mine var mAngle = bbAngle; while(abs(mAngle - bbAngle) < PI/3) { mAngle = randFloat(0, TWO_PI); } var mDist = 13; var mX = round(fx + mDist * cos(mAngle)); var mZ = round(fz + mDist * sin(mAngle)); group = new SimpleGroup( [new SimpleObject(oMetalLarge, 1,1, 0,0)], true, clBaseResource, mX, mZ ); createObjectGroup(group, 0); // create stone mines mAngle += randFloat(PI/8, PI/4); mX = round(fx + mDist * cos(mAngle)); mZ = round(fz + mDist * sin(mAngle)); createStoneMineFormation(mX, mZ, tDirt4); addToClass(mX, mZ, clPlayer); // create the city patch var cityRadius = radius/3; var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); var painter = new TerrainPainter(tCityTiles); createArea(placer, painter, null); var hillSize = PI * radius * radius; // create starting trees var num = floor(hillSize / 300); var tAngle = randFloat(-PI/3, 4*PI/3); var tDist = randFloat(11, 13); var tX = round(fx + tDist * cos(tAngle)); var tZ = round(fz + tDist * sin(tAngle)); group = new SimpleGroup( [new SimpleObject(oBaobab, num, num, 2,7)], false, clBaseResource, tX, tZ ); createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); } RMS.SetProgress(20); // create big patches log("Creating big patches..."); var patches = [tGrass2, tGrass3]; for (var i = 0; i < patches.length; i++) { placer = new ChainPlacer(floor(scaleByMapSize(3, 6)), floor(scaleByMapSize(10, 20)), floor(scaleByMapSize(15, 60)), 1); painter = new TerrainPainter(patches[i]); createAreas( placer, painter, avoidClasses(clPlayer, 10), scaleByMapSize(5, 20) ); } // create small patches log("Creating small patches..."); var patches = [tDirt1, tDirt2, tDirt3]; var sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; for (var i = 0; i < sizes.length; i++) { for (var j = 0; j < patches.length; ++j) { placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), sizes[i], 1); painter = new TerrainPainter(patches[j]); createAreas( placer, painter, avoidClasses(clPlayer, 12), scaleByMapSize(4, 15) ); } } // create water holes log("Creating water holes..."); placer = new ChainPlacer(1, floor(scaleByMapSize(3, 5)), floor(scaleByMapSize(20, 60)), 1); var terrainPainter = new LayeredPainter( [tShore, tWater], // terrains [1] // widths ); var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, -5, 7); createAreas( placer, [terrainPainter, elevationPainter, paintClass(clWater)], avoidClasses(clPlayer, 24), scaleByMapSize(1, 3) ); RMS.SetProgress(55); var playerConstraint = new AvoidTileClassConstraint(clPlayer, 30); var minesConstraint = new AvoidTileClassConstraint(clRock, 25); var waterConstraint = new AvoidTileClassConstraint(clWater, 10); log("Creating stone mines..."); // create stone mines for (var i = 0; i < scaleByMapSize(12,30); ++i) { - var mX = randInt(mapSize); - var mZ = randInt(mapSize); + var mX = randIntExclusive(0, mapSize); + var mZ = randIntExclusive(0, mapSize); if (playerConstraint.allows(mX, mZ) && minesConstraint.allows(mX, mZ) && waterConstraint.allows(mX, mZ)) { createStoneMineFormation(mX, mZ, tDirt4); addToClass(mX, mZ, clRock); } } log("Creating metal mines..."); // create large metal quarries group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clPlayer, 20, clMetal, 10, clRock, 8, clWater, 4), scaleByMapSize(2,8), 100 ); RMS.SetProgress(65); // create small decorative rocks log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRock, 1,3, 0,3)], true ); createObjectGroups( group, 0, avoidClasses(clPlayer, 7, clWater, 1), scaleByMapSize(200, 1200), 1 ); RMS.SetProgress(70); // create gazelle log("Creating gazelle..."); group = new SimpleGroup( [new SimpleObject(oGazelle, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), scaleByMapSize(4,12), 50 ); // create zebra log("Creating zebra..."); group = new SimpleGroup( [new SimpleObject(oZebra, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), scaleByMapSize(4,12), 50 ); // create giraffe log("Creating giraffe..."); group = new SimpleGroup( [new SimpleObject(oGiraffe, 2,4, 0,4), new SimpleObject(oGiraffeInfant, 0,2, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), scaleByMapSize(4,12), 50 ); // create elephants log("Creating elephants..."); group = new SimpleGroup( [new SimpleObject(oElephant, 2,4, 0,4), new SimpleObject(oElephantInfant, 0,2, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), scaleByMapSize(4,12), 50 ); // create lions log("Creating lions..."); group = new SimpleGroup( [new SimpleObject(oLion, 0,1, 0,4), new SimpleObject(oLioness, 2,3, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), scaleByMapSize(4,12), 50 ); // create berry bush log("Creating berry bush..."); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clPlayer, 20, clFood, 12, clRock, 7, clMetal, 6), - randInt(1, 4) * numPlayers + 2, 50 + randIntInclusive(1, 4) * numPlayers + 2, 50 ); RMS.SetProgress(85); // create straggler trees log("Creating straggler trees..."); var num = scaleByMapSize(70, 500); group = new SimpleGroup( [new SimpleObject(oBaobab, 1,1, 0,3)], true, clForest ); createObjectGroups(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clMetal, 6, clRock, 7, clWater, 1), num ); // create large grass tufts log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aBush, 2,4, 0,1.8, -PI/8,PI/8)] ); createObjectGroups(group, 0, avoidClasses(clWater, 3, clPlayer, 2, clForest, 0), scaleByMapSize(100, 1200) ); setSunColor(0.87451, 0.847059, 0.647059); setWaterColor(0.741176, 0.592157, 0.27451); setWaterTint(0.741176, 0.592157, 0.27451); setWaterWaviness(2.0); setWaterType("clap"); setWaterMurkiness(0.835938); setUnitsAmbientColor(0.57, 0.58, 0.55); setTerrainAmbientColor(0.447059, 0.509804, 0.54902); setFogFactor(0.25); setFogThickness(0.15); setFogColor(0.847059, 0.737255, 0.482353); setPPEffect("hdr"); setPPContrast(0.57031); setPPBloom(0.34); ExportMap();