Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/ambush.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/ambush.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/ambush.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/ambush.png (revision 17903) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/ambush.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/empire.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/empire.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/empire.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/empire.png (revision 17903) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/empire.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/frontier.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/frontier.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/frontier.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/frontier.png (revision 17903) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/frontier.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hells_pass.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hells_pass.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hells_pass.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hells_pass.png (revision 17903) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/hells_pass.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/lions_den.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/lions_den.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/lions_den.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/lions_den.png (revision 17903) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/lions_den.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/stronghold.png =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/stronghold.png =================================================================== --- ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/stronghold.png (nonexistent) +++ ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/stronghold.png (revision 17903) Property changes on: ps/trunk/binaries/data/mods/public/art/textures/ui/session/icons/mappreview/stronghold.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: ps/trunk/binaries/data/mods/public/maps/random/ambush.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ambush.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/ambush.js (revision 17903) @@ -0,0 +1,172 @@ +RMS.LoadLibrary("rmgen"); + +InitMap(); + +randomizeBiome(); +initMapSettings(); +initTileClasses(); + +resetTerrain(g_Terrains.mainTerrain, g_TileClasses.land, 2); +RMS.SetProgress(10); + +var pos = randomStartingPositionPattern(); +addBases(pos.setup, pos.distance, pos.separation); +RMS.SetProgress(20); + +addElements([ + { + "func": addBluffs, + "avoid": [ + g_TileClasses.bluff, 12, + g_TileClasses.hill, 5, + g_TileClasses.player, 35 + ], + "sizes": ["normal", "big", "huge"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.player, 20 + ], + "sizes": ["normal", "big"], + "mixes": ["normal"], + "amounts": ["tons"] + } +]); +RMS.SetProgress(30); + +addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 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.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } +]); +RMS.SetProgress(50); + +addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.bluff, 5], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.bluff, 5], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "stay": [g_TileClasses.bluff, 5], + "sizes": ["big", "huge"], + "mixes": ["normal"], + "amounts": ["tons"] + } +])); +RMS.SetProgress(70); + +addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.bluff, 5, g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3 + ], + "sizes": ["tiny"], + "mixes": ["same"], + "amounts": ["scarce"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.water, 3 + ], + "sizes": ["tiny"], + "mixes": ["same"], + "amounts": ["scarce"] + }, + { + "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.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5 + ], + "sizes": ["tiny"], + "mixes": ["same"], + "amounts": ["many"] + } +])); +RMS.SetProgress(90); + +ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/ambush.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ambush.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/ambush.json (revision 17903) @@ -0,0 +1,11 @@ +{ + "settings" : { + "Name" : "Ambush", + "Script" : "ambush.js", + "Description" : "High bluffs overlook the terrain below. Bountiful resources await on the cliffs, but beware of enemies planning an ambush.", + "BaseTerrain" : ["medit_sea_depths"], + "BaseHeight" : 2, + "Preview" : "ambush.png", + "CircularMap" : true + } +} Index: ps/trunk/binaries/data/mods/public/maps/random/empire.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/empire.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/empire.js (revision 17903) @@ -0,0 +1,217 @@ +RMS.LoadLibrary("rmgen"); +InitMap(); + +randomizeBiome(); +initMapSettings(); +initTileClasses(); + +resetTerrain(g_Terrains.mainTerrain, g_TileClasses.land, randInt(5)); +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/empire.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/empire.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/empire.json (revision 17903) @@ -0,0 +1,12 @@ +{ + "settings" : { + "Name" : "Empire", + "Script" : "empire.js", + "Description" : "A neighboring province has pledged alegiance to your rule. It's up to you to command them to victory.", + "BaseTerrain" : ["medit_sea_depths"], + "BaseHeight" : 2, + "Keywords": ["demo"], + "Preview" : "empire.png", + "CircularMap" : true + } +} Index: ps/trunk/binaries/data/mods/public/maps/random/frontier.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/frontier.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/frontier.js (revision 17903) @@ -0,0 +1,267 @@ +RMS.LoadLibrary("rmgen"); +InitMap(); + +randomizeBiome(); +initMapSettings(); +initTileClasses(); + +RMS.SetProgress(10); + +// Pick a random elevation with a bias towards lower elevations +var randElevation = randInt(30); +if (randElevation < 25) + randElevation = 1 + randInt(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 = 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 = 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/frontier.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/frontier.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/frontier.json (revision 17903) @@ -0,0 +1,11 @@ +{ + "settings" : { + "Name" : "Frontier", + "Script" : "frontier.js", + "Description" : "A wild, unknown landscape awaits rival explorers.", + "BaseTerrain" : ["medit_sea_depths"], + "Preview" : "frontier.png", + "BaseHeight" : 2, + "CircularMap" : true + } +} Index: ps/trunk/binaries/data/mods/public/maps/random/hells_pass.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/hells_pass.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/hells_pass.js (revision 17903) @@ -0,0 +1,303 @@ +RMS.LoadLibrary("rmgen"); +InitMap(); + +randomizeBiome(); +initMapSettings(); +initTileClasses(); + +resetTerrain(g_Terrains.mainTerrain, g_TileClasses.land, 1); +RMS.SetProgress(10); + +addBases("line", 0.2, 0.08); +RMS.SetProgress(20); + +placeBarriers(); +RMS.SetProgress(40); + +addElements(shuffleArray([ + { + "func": addBluffs, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.hill, 5, + g_TileClasses.mountain, 20, + g_TileClasses.plateau, 20, + g_TileClasses.player, 30, + g_TileClasses.spine, 15, + g_TileClasses.valley, 5, + g_TileClasses.water, 7 + ], + "sizes": ["normal", "big"], + "mixes": ["varied"], + "amounts": ["few"] + }, + { + "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.spine, 15, + g_TileClasses.valley, 2, + g_TileClasses.water, 2 + ], + "sizes": ["normal", "big"], + "mixes": ["varied"], + "amounts": ["few"] + }, + { + "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.spine, 15, + g_TileClasses.valley, 10, + g_TileClasses.water, 25 + ], + "sizes": ["big", "huge"], + "mixes": ["varied", "unique"], + "amounts": ["few"] + } +])); +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.spine, 5, + 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.spine, 5, + 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.spine, 5, + 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.spine, 5, + 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.spine, 5, + 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.spine, 2, + 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.spine, 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.spine, 2, + g_TileClasses.water, 5 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } +])); +RMS.SetProgress(90); + +ExportMap(); + +// place the mountainous barriers between the teams +function placeBarriers() +{ + var spineTerrain = g_Terrains.dirt; + + if (g_MapInfo.biome == 2) + spineTerrain = g_Terrains.tier1Terrain; + + if (g_MapInfo.biome == 4 || g_MapInfo.biome == 6) + spineTerrain = g_Terrains.tier2Terrain; + + if (g_MapInfo.biome == 8) + spineTerrain = g_Terrains.tier4Terrain; + + // create mountain ranges + for (var i = 0; i < g_MapInfo.teams.length; ++i) + { + var tang = g_MapInfo.startAngle + (i + 0.5) * TWO_PI / g_MapInfo.teams.length; + + var fx = fractionToTiles(0.5); + var fz = fractionToTiles(0.5); + var ix = round(fx); + var iz = round(fz); + + var mStartCo = 0.07; + var mStopCo = 0.42; + var mSize = 8; + var mWaviness = 0.6; + var mOffset = 0.5; + var mTaper = -1.5; + + if (g_MapInfo.teams.length > 3 || g_MapInfo.mapSize <= 192) + { + mWaviness = 0.2; + mOffset = 0.2; + mTaper = -1; + } + + if (g_MapInfo.teams.length >= 5) + { + mSize = 4; + mWaviness = 0.2; + mOffset = 0.2; + mTaper = -0.7; + } + + // place barrier + var placer = new PathPlacer(fractionToTiles(0.5 + mStartCo * cos(tang)), fractionToTiles(0.5 + mStartCo * sin(tang)), fractionToTiles(0.5 + mStopCo * cos(tang)), fractionToTiles(0.5 + mStopCo * sin(tang)), scaleByMapSize(14, mSize), mWaviness, 0.1, mOffset, mTaper); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, spineTerrain], [2]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 30, 2); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.spine)], avoidClasses(g_TileClasses.player, 5, g_TileClasses.baseResource, 5)); + } + + addElements([ + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.spine, 5], + "sizes": ["huge"], + "mixes": ["unique"], + "amounts": ["tons"] + } + ]); + + addElements([ + { + "func": addProps, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.player, 2, + g_TileClasses.prop, 20, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.spine, 8], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["scarce"] + } + ]); +} Index: ps/trunk/binaries/data/mods/public/maps/random/hells_pass.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/hells_pass.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/hells_pass.json (revision 17903) @@ -0,0 +1,11 @@ +{ + "settings" : { + "Name" : "Hell's Pass", + "Script" : "hells_pass.js", + "Description" : "A narrow pass between steep mountains promotes tight, defensive combat. With bountiful resources far from the front lines, teams may choose to support their exposed teammates financially, or retreat to more fertile, but less defensible ground.", + "BaseTerrain" : ["medit_sea_depths"], + "BaseHeight" : 1, + "Preview" : "hells_pass.png", + "CircularMap" : true + } +} Index: ps/trunk/binaries/data/mods/public/maps/random/lions_den.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/lions_den.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/lions_den.js (revision 17903) @@ -0,0 +1,501 @@ +RMS.LoadLibrary("rmgen"); +InitMap(); + +randomizeBiome(); +initMapSettings(); +initTileClasses(["step"]); + +var topTerrain = g_Terrains.tier2Terrain; + +resetTerrain(topTerrain, g_TileClasses.land, 50); +RMS.SetProgress(10); + +var players = addBases("radial", 0.4, randFloat(0.05, 0.1)); +RMS.SetProgress(20); + +createSunkenTerrain(players); +RMS.SetProgress(30); + +addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.step, 5 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2 + ], + "stay": [g_TileClasses.player, 1], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [g_TileClasses.forest, 2], + "stay": [g_TileClasses.player, 1], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.step, 2 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12 + ], + "stay": [g_TileClasses.step, 7], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["scarce"] + } +]); +RMS.SetProgress(40); + +addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.player, 10, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.mountain, 5, + g_TileClasses.step, 5 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.player, 10, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 5, + g_TileClasses.step, 5 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 18, + g_TileClasses.metal, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 3 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": ["normal", "big"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 3, + g_TileClasses.forest, 18, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.player, 5, + g_TileClasses.rock, 3, + g_TileClasses.step, 1 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": ["normal", "big"], + "mixes": ["same"], + "amounts": ["tons"] + } +])); +RMS.SetProgress(60); + +addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.player, 20, + g_TileClasses.rock, 10 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["tons"] + }, + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 5, + g_TileClasses.player, 10, + g_TileClasses.rock, 10, + g_TileClasses.step, 5 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 0, + g_TileClasses.metal, 1, + g_TileClasses.player, 20, + g_TileClasses.rock, 1 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["tons"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 0, + g_TileClasses.metal, 1, + g_TileClasses.mountain, 5, + g_TileClasses.player, 10, + g_TileClasses.rock, 1, + g_TileClasses.step, 5 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 3, + g_TileClasses.player, 12, + g_TileClasses.rock, 3 + ], + "stay": [g_TileClasses.settlement, 7], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["tons"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.player, 10, + g_TileClasses.rock, 3, + g_TileClasses.step, 5 + ], + "stay": [g_TileClasses.valley, 7], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["normal", "many", "tons"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.metal, 5, + g_TileClasses.rock, 5 + ], + "stay": [g_TileClasses.player, 1], + "sizes": ["huge"], + "mixes": ["same"], + "amounts": ["tons"] + } +])); +RMS.SetProgress(75); + +addElements([ + { + "func": addDecoration, + "avoid": [ + g_TileClasses.valley, 4, + g_TileClasses.player, 4, + g_TileClasses.settlement, 4, + g_TileClasses.step, 4 + ], + "stay": [g_TileClasses.land, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["tons"] + } +]); +RMS.SetProgress(80); + +addElements([ + { + "func": addProps, + "avoid": [ + g_TileClasses.valley, 4, + g_TileClasses.player, 4, + g_TileClasses.settlement, 4, + g_TileClasses.step, 4 + ], + "stay": [g_TileClasses.land, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["scarce"] + } +]); +RMS.SetProgress(85); + +addElements([ + { + "func": addDecoration, + "avoid": [ + g_TileClasses.player, 4, + g_TileClasses.settlement, 4, + g_TileClasses.step, 4 + ], + "stay": [g_TileClasses.mountain, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["tons"] + } +]); +RMS.SetProgress(90); + +addElements([ + { + "func": addProps, + "avoid": [ + g_TileClasses.player, 4, + g_TileClasses.settlement, 4, + g_TileClasses.step, 4 + ], + "stay": [g_TileClasses.mountain, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["scarce"] + } +]); +RMS.SetProgress(95); + +ExportMap(); + +// Create the sunken terrain +function createSunkenTerrain(players) +{ + var base = g_Terrains.mainTerrain; + var middle = g_Terrains.dirt; + var lower = g_Terrains.tier2Terrain; + var road = g_Terrains.road; + + if (g_MapInfo.biome == 2) + { + middle = g_Terrains.tier2Terrain; + lower = g_Terrains.tier1Terrain; + } + + if (g_MapInfo.biome == 4) + { + middle = g_Terrains.shore; + lower = g_Terrains.tier4Terrain; + } + + if (g_MapInfo.biome == 5) + { + middle = g_Terrains.tier1Terrain; + lower = g_Terrains.forestFloor1; + } + + if (g_MapInfo.biome == 6) + { + middle = g_Terrains.tier2Terrain; + lower = g_Terrains.tier4Terrain; + } + + if (g_MapInfo.biome == 7 || g_MapInfo.biome == 8) + road = g_Terrains.roadWild; + + if (g_MapInfo.biome == 8) + middle = g_Terrains.shore; + + var expSize = g_MapInfo.mapArea * 0.015 / (g_MapInfo.numPlayers / 4); + var expDist = 0.1 + (g_MapInfo.numPlayers / 200); + if (g_MapInfo.numPlayers == 2) + expSize = g_MapInfo.mapArea * 0.015 / 0.7; + + var nRoad = 0.44; + var nExp = 0.425; + + if (g_MapInfo.numPlayers < 4) + { + nRoad = 0.42; + nExp = 0.4; + } + + // Create central valley + var placer = new ClumpPlacer(g_MapInfo.mapArea * 0.26, 1, 1, 1, g_MapInfo.centerOfMap, g_MapInfo.centerOfMap); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, lower], [3]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 0, 3); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.valley)]); + + // Create the center hill + var placer = new ClumpPlacer(g_MapInfo.mapArea * 0.14, 1, 1, 1, g_MapInfo.centerOfMap, g_MapInfo.centerOfMap); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, topTerrain], [3]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, g_MapInfo.mapHeight, 3); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.mountain)]); + + for(var i = 0; i < players.length; ++i) + { + var playerAngle = g_MapInfo.startAngle + i * TWO_PI / g_MapInfo.numPlayers; + var pX = round(fractionToTiles(0.5 + 0.4 * cos(playerAngle))); + var pZ = round(fractionToTiles(0.5 + 0.4 * sin(playerAngle))); + var expX = round(fractionToTiles(0.5 + expDist * cos(g_MapInfo.startAngle + (i + 0.75) * TWO_PI / g_MapInfo.numPlayers))); + var expZ = round(fractionToTiles(0.5 + expDist * sin(g_MapInfo.startAngle + (i + 0.75) * TWO_PI / g_MapInfo.numPlayers))); + var rearX = round(fractionToTiles(0.5 + 0.47 * cos(playerAngle))); + var rearZ = round(fractionToTiles(0.5 + 0.47 * sin(playerAngle))); + var prePlayerAngle = g_MapInfo.startAngle + (i - 0.5) * TWO_PI / g_MapInfo.numPlayers; + var preX = round(fractionToTiles(0.5 + nRoad * cos(prePlayerAngle))); + var preZ = round(fractionToTiles(0.5 + nRoad * sin(prePlayerAngle))); + var nextPlayerAngle = g_MapInfo.startAngle + (i + 0.5) * TWO_PI / g_MapInfo.numPlayers; + var nextX = round(fractionToTiles(0.5 + nRoad * cos(nextPlayerAngle))); + var nextZ = round(fractionToTiles(0.5 + nRoad * sin(nextPlayerAngle))); + + // Create path to expansion + var placer = new PathPlacer(pX, pZ, expX, expZ, scaleByMapSize(12, 12), 0.7, 0.5, 0.1, -1); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, middle, road], [3, 4]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 10, 3); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.step)]); + + // Create path to neighbor + var placer = new PathPlacer(rearX, rearZ, nextX, nextZ, scaleByMapSize(19, 19), 0.4, 0.5, 0.1, -0.6); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, middle, road], [3, 6]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 10, 3); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.step)]); + + // Create path to neighbor + var placer = new PathPlacer(rearX, rearZ, preX, preZ, scaleByMapSize(19, 19), 0.4, 0.5, 0.1, -0.6); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, middle, road], [3, 6]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 10, 3); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.step)]); + + // Create the den + var placer = new ClumpPlacer(g_MapInfo.mapArea * 0.03, 0.9, 0.3, 1, pX, pZ); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, base], [3]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 15, 3); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.valley)]); + + // Create the expansion + var placer = new ClumpPlacer(expSize, 0.9, 0.3, 1, expX, expZ); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, base], [3]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 15, 3); + var area = createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.settlement)], [avoidClasses(g_TileClasses.settlement, 2)]); + var unpainter = new TileClassUnPainter(new TileClass(g_MapInfo.mapSize, g_TileClasses.mountain)); + unpainter.paint(area); + } + + // Create the neighbor expansions + for (var i = 0; i < g_MapInfo.numPlayers; ++i) + { + var nextPlayerAngle = g_MapInfo.startAngle + (i + 0.5) * TWO_PI / g_MapInfo.numPlayers; + var nextX = round(fractionToTiles(0.5 + nExp * cos(nextPlayerAngle))); + var nextZ = round(fractionToTiles(0.5 + nExp * sin(nextPlayerAngle))); + + // Create the neightbor expansion + var placer = new ClumpPlacer(expSize, 0.9, 0.3, 1, nextX, nextZ); + var terrainPainter = new LayeredPainter([g_Terrains.cliff, lower], [3]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 0, 3); + var area = createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.settlement)]); + } +} Index: ps/trunk/binaries/data/mods/public/maps/random/lions_den.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/lions_den.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/lions_den.json (revision 17903) @@ -0,0 +1,12 @@ +{ + "settings" : { + "Name" : "Lion's Den", + "Script" : "lions_den.js", + "Description" : "High cliffs protect each player's main base. Venturing into the unknown can be risky, but necessary.", + "BaseTerrain" : ["medit_sea_depths"], + "BaseHeight" : 50, + "Preview" : "lions_den.png", + "Keywords": ["demo"], + "CircularMap" : true + } +} Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/gaia.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/gaia.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/gaia.js (revision 17903) @@ -0,0 +1,1295 @@ +const 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", + "blood": "actor|props/units/blood_01.xml", + "bigBlood": "actor|props/units/blood_whale.xml" +}; + +const 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 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, g_Terrains.tier2Terrain], [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); + var area = points.length; + + // 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 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; + } + + // Found a bluff that can't be accessed, so turn it into a plateau + if (retries == 5) + removeBluff(points); + + // If we couldn't find the slope lines, turn it into a plateau + if (bluffCat == 1) + continue; + + var ground = createTerrain(g_Terrains.mainTerrain); + + var slopeLength = 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", "many", "tons"] + }, + { + "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", "many", "tons"] + } + ])); + + 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": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["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 == 7) + 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 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 == 0 || g_MapInfo.biome == 1 || g_MapInfo.biome == 7) + lakeTile = g_Terrains.dirt; + + if (g_MapInfo.biome == 5) + lakeTile = g_Terrains.tier2Terrain; + + if (g_MapInfo.biome == 8) + 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 == 2) + plateauTile = g_Terrains.tier1Terrain; + + if (g_MapInfo.biome == 4 || g_MapInfo.biome == 6) + plateauTile = g_Terrains.tier2Terrain; + + if (g_MapInfo.biome == 8) + 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 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.blood, 1 * offset, 2 * offset, 0, 1 * offset + 3), + new SimpleObject(g_Props.bigBlood, 1 * offset, 3 * offset, 0, 2 * offset + 3) + ], + [ + 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 rivers. + */ +function addRivers(constraint, size, deviation, fill) +{ + deviation = deviation || g_DefaultDeviation; + size = size || 1; + fill = fill || 1; + + var count = 5; + var minSize = scaleByMapSize(15, 15); + var maxSize = scaleByMapSize(15, 15); + var elevation = -2; + var spread = scaleByMapSize(5, 5); + + for (var i = 0; i < count; ++i) + { + var offset = getRandomDeviation(size, deviation); + + var startAngle = randFloat(0, 2 * PI); + var endAngle = startAngle + randFloat(PI * 0.5, PI * 1.5); + + var startX = g_MapInfo.centerOfMap + Math.floor(g_MapInfo.centerOfMap * Math.cos(startAngle)); + var startZ = g_MapInfo.centerOfMap + Math.floor(g_MapInfo.centerOfMap * Math.sin(startAngle)); + + var endX = g_MapInfo.centerOfMap + Math.floor(g_MapInfo.centerOfMap * Math.cos(endAngle)); + var endZ = g_MapInfo.centerOfMap + Math.floor(g_MapInfo.centerOfMap * Math.sin(endAngle)); + + var pMinSize = Math.floor(minSize * offset); + var pMaxSize = Math.floor(maxSize * offset); + var pSpread = Math.floor(spread * offset); + + var placer = new PathPlacer(startX, startZ, endX, endZ, 12, 0.25, 1, 0.05, 0.3); + var terrainPainter = new LayeredPainter([g_Terrains.water, g_Terrains.shore], [2]); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, elevation, 2); + createArea(placer, [terrainPainter, elevationPainter, paintClass(g_TileClasses.water)], constraint); + } +} + +/** + * 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 == 0) + { + valleySlope = g_Terrains.dirt; + valleyFloor = g_Terrains.tier2Terrain; + } + + if (g_MapInfo.biome == 3) + { + valleySlope = g_Terrains.tier3Terrain; + valleyFloor = g_Terrains.dirt; + } + + if (g_MapInfo.biome == 5) + { + valleySlope = g_Terrains.tier2Terrain; + valleyFloor = g_Terrains.dirt; + } + + if (g_MapInfo.biome == 4 || g_MapInfo.biome == 6) + valleyFloor = g_Terrains.tier2Terrain; + + if (g_MapInfo.biome == 7) + valleySlope = g_Terrains.dirt; + + if (g_MapInfo.biome == 8) + 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 == 6) + 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); + } +} + +/** + * 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 == 6) + { + 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 == 6) + { + 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 == 3 || g_MapInfo.biome == 5)) + 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. + */ +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) || checkIfInClass(endLine.x1, endLine.z1, g_TileClasses.player)) && + (!g_Map.validT(endLine.x2, endLine.z2) || checkIfInClass(endLine.x2, endLine.z2, g_TileClasses.player))) + 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; + return deviation.toFixed(2); +} Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/setup.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/setup.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/setup.js (revision 17903) @@ -0,0 +1,627 @@ +const g_Amounts = { + "scarce": 0.2, + "few": 0.5, + "normal": 1, + "many": 1.75, + "tons": 3 +}; + +const g_Mixes = { + "same": 0, + "similar": 0.1, + "normal": 0.25, + "varied": 0.5, + "unique": 0.75 +}; + +const g_Sizes = { + "tiny": 0.5, + "small": 0.75, + "normal": 1, + "big": 1.25, + "huge": 1.5, +}; + +const g_AllAmounts = Object.keys(g_Amounts); +const g_AllMixes = Object.keys(g_Mixes); +const g_AllSizes = Object.keys(g_Sizes); + +const g_DefaultTileClasses = [ + "animals", + "baseResource", + "berries", + "bluff", + "bluffSlope", + "dirt", + "fish", + "food", + "forest", + "hill", + "land", + "map", + "metal", + "mountain", + "plateau", + "player", + "prop", + "ramp", + "rock", + "settlement", + "spine", + "valley", + "water" +]; + +var g_MapInfo; +var g_TileClasses; + +var g_Terrains; +var g_Gaia; +var g_Decoratives; +var g_Forests; + +/** + * Adds an array of elements to the map. + */ +function addElements(els) +{ + for (var i = 0; i < els.length; ++i) + { + var stay = null; + if (els[i].stay !== undefined) + stay = els[i].stay; + + els[i].func( + [avoidClasses.apply(null, els[i].avoid), stayClasses.apply(null, stay)], + pickSize(els[i].sizes), + pickMix(els[i].mixes), + pickAmount(els[i].amounts) + ); + } +} + +/** + * Converts "amount" terms to numbers. + */ +function pickAmount(amounts) +{ + var amount = amounts[randInt(amounts.length)]; + + if (amount in g_Amounts) + return g_Amounts[amount]; + + return g_Mixes.normal; +} + +/** + * Converts "mix" terms to numbers. + */ +function pickMix(mixes) +{ + var mix = mixes[randInt(mixes.length)]; + + if (mix in g_Mixes) + return g_Mixes[mix]; + + return g_Mixes.normal; +} + +/** + * Converts "size" terms to numbers. + */ +function pickSize(sizes) +{ + var size = sizes[randInt(sizes.length)]; + + if (size in g_Sizes) + return g_Sizes[size]; + + return g_Sizes.normal; +} + +/** + * Paints the entire map with a single tile type. + */ +function resetTerrain(terrain, tc, elevation) +{ + g_MapInfo.mapSize = getMapSize(); + g_MapInfo.mapArea = g_MapInfo.mapSize * g_MapInfo.mapSize; + g_MapInfo.centerOfMap = Math.floor(g_MapInfo.mapSize / 2); + g_MapInfo.mapRadius = -PI / 4; + + var placer = new ClumpPlacer(g_MapInfo.mapArea, 1, 1, 1, g_MapInfo.centerOfMap, g_MapInfo.centerOfMap); + var terrainPainter = new LayeredPainter([terrain], []); + var elevationPainter = new SmoothElevationPainter(ELEVATION_SET, elevation, 1); + createArea(placer, [terrainPainter, elevationPainter, paintClass(tc)], null); + + g_MapInfo.mapHeight = elevation; +} + +/** + * Euclidian distance between two points. + */ +function euclid_distance(x1, z1, x2, z2) +{ + return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(z2 - z1, 2)); +} + +/** + * Chose starting locations for the given players. + * + * @param {string} type - "radial", "stacked", "stronghold", "random" + * @param {number} distance - radial distance from the center of the map + */ +function addBases(type, distance, groupedDistance) +{ + type = type || "radial"; + distance = distance || 0.3; + groupedDistance = groupedDistance || 0.05; + + var playerIDs = randomizePlayers(); + var players = {}; + + switch(type) + { + case "line": + players = placeLine(playerIDs, distance, groupedDistance); + break; + case "radial": + players = placeRadial(playerIDs, distance); + break; + case "random": + players = placeRandom(playerIDs); + break; + case "stronghold": + players = placeStronghold(playerIDs, distance, groupedDistance); + break; + } + + return players; +} + +/** + * Create the base for a single player. + * + * @param {Object} - contains id, angle, x, z + * @param {boolean} - Whether or not iberian gets starting walls + */ +function createBase(player, walls) +{ + // Get the x and z in tiles + var fx = fractionToTiles(player.x); + var fz = fractionToTiles(player.z); + var ix = round(fx); + var iz = round(fz); + addToClass(ix, iz, g_TileClasses.player); + addToClass(ix + 5, iz, g_TileClasses.player); + addToClass(ix, iz + 5, g_TileClasses.player); + addToClass(ix - 5, iz, g_TileClasses.player); + addToClass(ix, iz - 5, g_TileClasses.player); + + // Create starting units + if ((walls || walls === undefined) && g_MapInfo.mapSize > 192) + placeCivDefaultEntities(fx, fz, player.id, g_MapInfo.mapRadius); + else + placeCivDefaultEntities(fx, fz, player.id, g_MapInfo.mapRadius, { 'iberWall': false }); + + // Create the city patch + var cityRadius = scaleByMapSize(15, 25) / 3; + var placer = new ClumpPlacer(PI * cityRadius * cityRadius, 0.6, 0.3, 10, ix, iz); + var painter = new LayeredPainter([g_Terrains.roadWild, g_Terrains.road], [1]); + createArea(placer, painter, null); + + // Custom base terrain function + + // Create animals + for (var j = 0; j < 2; ++j) + { + var aAngle = randFloat(0, TWO_PI); + var aDist = 7; + var aX = round(fx + aDist * cos(aAngle)); + var aZ = round(fz + aDist * sin(aAngle)); + var group = new SimpleGroup( + [new SimpleObject(g_Gaia.chicken, 5, 5, 0, 2)], + true, g_TileClasses.baseResource, aX, aZ + ); + createObjectGroup(group, 0, avoidClasses(g_TileClasses.baseResource, 2)); + } + + // 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)); + group = new SimpleGroup( + [new SimpleObject(g_Gaia.fruitBush, 5, 5, 0, 3)], + true, g_TileClasses.baseResource, bbX, bbZ + ); + createObjectGroup(group, 0, avoidClasses(g_TileClasses.baseResource, 2)); + + // 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(g_Gaia.metalLarge, 1, 1, 0, 0)], + true, g_TileClasses.baseResource, mX, mZ + ); + createObjectGroup(group, 0, avoidClasses(g_TileClasses.baseResource, 2)); + + // 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(g_Gaia.stoneLarge, 1, 1, 0, 2)], + true, g_TileClasses.baseResource, mX, mZ + ); + createObjectGroup(group, 0, avoidClasses(g_TileClasses.baseResource, 2)); + + var hillSize = PI * g_MapInfo.mapRadius * g_MapInfo.mapRadius; + + // Create starting trees + var num = 5; + var tAngle = randFloat(0, TWO_PI); + var tDist = randFloat(12, 13); + var tX = round(fx + tDist * cos(tAngle)); + var tZ = round(fz + tDist * sin(tAngle)); + + group = new SimpleGroup( + [new SimpleObject(g_Gaia.tree1, num, num, 0, 3)], + false, g_TileClasses.baseResource, tX, tZ + ); + createObjectGroup(group, 0, avoidClasses(g_TileClasses.baseResource, 2)); + + // Create grass tufts + var num = hillSize / 250; + for (var j = 0; j < num; ++j) + { + var gAngle = randFloat(0, TWO_PI); + var gDist = g_MapInfo.mapRadius - (5 + randInt(7)); + var gX = round(fx + gDist * cos(gAngle)); + var gZ = round(fz + gDist * sin(gAngle)); + group = new SimpleGroup( + [new SimpleObject(g_Decoratives.grassShort, 2, 5, 0, 1, -PI / 8, PI / 8)], + false, g_TileClasses.baseResource, gX, gZ + ); + createObjectGroup(group, 0, avoidClasses(g_TileClasses.baseResource, 2)); + } +} + +/** + * Return an array where each element is an array of playerIndices of a team. + */ +function getTeams(numPlayers) +{ + // Group players by team + var teams = []; + for (var i = 0; i < numPlayers; ++i) + { + let team = getPlayerTeam(i); + if (team == -1) + continue; + + if (!teams[team]) + teams[team] = []; + + teams[team].push(i+1); + } + + // Players without a team get a custom index + for (var i = 0; i < numPlayers; ++i) + if (getPlayerTeam(i) == -1) + teams.push([i+1]); + + // Remove unused indices + return teams.filter(team => true); +} + +/** + * Chose a random pattern for placing the bases of the players. + */ +function randomStartingPositionPattern() +{ + var formats = ["radial"]; + + // Enable stronghold if we have a few teams and a big enough map + if (g_MapInfo.teams.length >= 2 && g_MapInfo.numPlayers >= 4 && g_MapInfo.mapSize >= 256) + formats.push("stronghold"); + + // Enable random if we have enough teams or enough players on a big enough map + if (g_MapInfo.mapSize >= 256 && (g_MapInfo.teams.length >= 3 || g_MapInfo.numPlayers > 4)) + formats.push("random"); + + // Enable line if we have enough teams and players on a big enough map + if (g_MapInfo.teams.length >= 2 && g_MapInfo.numPlayers >= 4 && g_MapInfo.mapSize >= 384) + formats.push("line"); + + return { + "setup": formats[randInt(formats.length)], + "distance": randFloat(0.2, 0.35), + "separation": randFloat(0.05, 0.1) + }; +} + +/** + * Mix player indices but sort by team. + * + * @returns {Array} - every item is an array of player indices + */ +function randomizePlayers() +{ + var playerIDs = []; + for (var i = 0; i < g_MapInfo.numPlayers; ++i) + playerIDs.push(i + 1); + + return sortPlayers(playerIDs); +} + +/** + * Place teams in a line-pattern. + * + * @param {Array} playerIDs - typically randomized indices of players of a single team + * @param {number} distance - radial distance from the center of the map + * @param {number} groupedDistance - distance between players + * + * @returns {Array} - contains id, angle, x, z for every player + */ +function placeLine(playerIDs, distance, groupedDistance) +{ + var players = []; + + for (var i = 0; i < g_MapInfo.teams.length; ++i) + { + var safeDist = distance; + if (distance + g_MapInfo.teams[i].length * groupedDistance > 0.45) + safeDist = 0.45 - g_MapInfo.teams[i].length * groupedDistance; + + var teamAngle = g_MapInfo.startAngle + (i + 1) * TWO_PI / g_MapInfo.teams.length; + + // Create player base + for (var p = 0; p < g_MapInfo.teams[i].length; ++p) + { + players[g_MapInfo.teams[i][p]] = { + "id": g_MapInfo.teams[i][p], + "angle": g_MapInfo.startAngle + (p + 1) * TWO_PI / g_MapInfo.teams[i].length, + "x": 0.5 + (safeDist + p * groupedDistance) * cos(teamAngle), + "z": 0.5 + (safeDist + p * groupedDistance) * sin(teamAngle) + }; + createBase(players[g_MapInfo.teams[i][p]], false); + } + } + + return players; +} + +/** + * Place players in a circle-pattern. + * + * @param {number} distance - radial distance from the center of the map + */ +function placeRadial(playerIDs, distance) +{ + var players = new Array(g_MapInfo.numPlayers); + + for (var i = 0; i < g_MapInfo.numPlayers; ++i) + { + var angle = g_MapInfo.startAngle + i * TWO_PI / g_MapInfo.numPlayers; + players[i] = { + "id": playerIDs[i], + "angle": angle, + "x": 0.5 + distance * cos(angle), + "z": 0.5 + distance * sin(angle) + }; + createBase(players[i]); + } + + return players; +} + +/** + * Chose arbitrary starting locations. + */ +function placeRandom(playerIDs) +{ + var players = []; + var placed = []; + + for (var i = 0; i < g_MapInfo.numPlayers; ++i) + { + var attempts = 0; + var playerAngle = randFloat(0, TWO_PI); + var distance = randFloat(0, 0.42); + var x = 0.5 + distance * cos(playerAngle); + var z = 0.5 + distance * sin(playerAngle); + + var tooClose = false; + for (var j = 0; j < placed.length; ++j) + { + var sep = euclid_distance(x, z, placed[j].x, placed[j].z); + if (sep < 0.25) + { + tooClose = true; + break; + } + } + + if (tooClose) + { + --i; + ++attempts; + + // Reset if we're in what looks like an infinite loop + if (attempts > 100) + { + players = []; + placed = []; + i = -1; + attempts = 0; + } + + continue; + } + + players[i] = { + "id": playerIDs[i], + "angle": playerAngle, + "x": x, + "z": z + }; + + placed.push(players[i]); + } + + // Create the bases + for (var i = 0; i < g_MapInfo.numPlayers; ++i) + createBase(players[i]); + + return players; +} + +/** + * Place given players in a stronghold-pattern. + * + * @param distance - radial distance from the center of the map + * @param groupedDistance - distance between neighboring players + */ +function placeStronghold(playerIDs, distance, groupedDistance) +{ + var players = []; + + for (var i = 0; i < g_MapInfo.teams.length; ++i) + { + var teamAngle = g_MapInfo.startAngle + (i + 1) * TWO_PI / g_MapInfo.teams.length; + var fractionX = 0.5 + distance * cos(teamAngle); + var fractionZ = 0.5 + distance * sin(teamAngle); + + // If we have a team of above average size, make sure they're spread out + if (g_MapInfo.teams[i].length > 4) + groupedDistance = randFloat(0.08, 0.12); + + // If we have a team of below average size, make sure they're together + if (g_MapInfo.teams[i].length < 3) + groupedDistance = randFloat(0.04, 0.06); + + // If we have a solo player, place them on the center of the team's location + if (g_MapInfo.teams[i].length == 1) + groupedDistance = 0; + + // Create player base + for (var p = 0; p < g_MapInfo.teams[i].length; ++p) + { + var angle = g_MapInfo.startAngle + (p + 1) * TWO_PI / g_MapInfo.teams[i].length; + players[g_MapInfo.teams[i][p]] = { + "id": g_MapInfo.teams[i][p], + "angle": angle, + "x": fractionX + groupedDistance * cos(angle), + "z": fractionZ + groupedDistance * sin(angle) + }; + createBase(players[g_MapInfo.teams[i][p]], false); + } + } + + return players; +} + +/** + * Creates tileClass for the default classes and every class given. + * + * @param {Array} newClasses + * @returns {Object} - maps from classname to ID + */ +function initTileClasses(newClasses) +{ + var classNames = g_DefaultTileClasses; + + if (newClasses !== undefined) + classNames = classNames.concat(newClasses); + + g_TileClasses = {}; + for (var className of classNames) + g_TileClasses[className] = createTileClass(); +} + +/** + * Get biome-specific names of entities and terrain after randomization. + */ +function initBiome() +{ + g_Terrains = { + "mainTerrain": rBiomeT1(), + "forestFloor1": rBiomeT2(), + "forestFloor2": rBiomeT3(), + "cliff": rBiomeT4(), + "tier1Terrain": rBiomeT5(), + "tier2Terrain": rBiomeT6(), + "tier3Terrain": rBiomeT7(), + "hill": rBiomeT8(), + "dirt": rBiomeT9(), + "road": rBiomeT10(), + "roadWild": rBiomeT11(), + "tier4Terrain": rBiomeT12(), + "shoreBlend": rBiomeT13(), + "shore": rBiomeT14(), + "water": rBiomeT15() + }; + + g_Gaia = { + "tree1": rBiomeE1(), + "tree2": rBiomeE2(), + "tree3": rBiomeE3(), + "tree4": rBiomeE4(), + "tree5": rBiomeE5(), + "fruitBush": rBiomeE6(), + "chicken": rBiomeE7(), + "mainHuntableAnimal": rBiomeE8(), + "fish": rBiomeE9(), + "secondaryHuntableAnimal": rBiomeE10(), + "stoneLarge": rBiomeE11(), + "stoneSmall": rBiomeE12(), + "metalLarge": rBiomeE13() + }; + + g_Decoratives = { + "grass": rBiomeA1(), + "grassShort": rBiomeA2(), + "reeds": rBiomeA3(), + "lillies": rBiomeA4(), + "rockLarge": rBiomeA5(), + "rockMedium": rBiomeA6(), + "bushMedium": rBiomeA7(), + "bushSmall": rBiomeA8(), + "tree": rBiomeA9() + }; + + g_Forests = { + "forest1": [ + g_Terrains.forestFloor2 + TERRAIN_SEPARATOR + g_Gaia.tree1, + g_Terrains.forestFloor2 + TERRAIN_SEPARATOR + g_Gaia.tree2, + g_Terrains.forestFloor2 + ], + "forest2": [ + g_Terrains.forestFloor1 + TERRAIN_SEPARATOR + g_Gaia.tree4, + g_Terrains.forestFloor1 + TERRAIN_SEPARATOR + g_Gaia.tree5, + g_Terrains.forestFloor1 + ] + }; +} + +/** + * Creates an object of commonly used functions. + */ +function initMapSettings() +{ + initBiome(); + + let numPlayers = getNumPlayers(); + g_MapInfo = { + "biome": biomeID, + "numPlayers": numPlayers, + "teams": getTeams(numPlayers), + "startAngle": randFloat(0, TWO_PI) + }; +} Index: ps/trunk/binaries/data/mods/public/maps/random/stronghold.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/stronghold.js (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/stronghold.js (revision 17903) @@ -0,0 +1,237 @@ +RMS.LoadLibrary("rmgen"); +InitMap(); + +randomizeBiome(); +initMapSettings(); +initTileClasses(); + +resetTerrain(g_Terrains.mainTerrain, g_TileClasses.land, 30); +RMS.SetProgress(20); + +addBases("stronghold", randFloat(0.2, 0.35), randFloat(0.05, 0.1)); +RMS.SetProgress(30); + +addElements(shuffleArray([ + { + "func": addBluffs, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.hill, 5, + g_TileClasses.mountain, 20, + g_TileClasses.plateau, 20, + g_TileClasses.player, 30, + g_TileClasses.valley, 5, + g_TileClasses.water, 7 + ], + "sizes": ["big", "huge"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.valley, 2, + g_TileClasses.water, 2 + ], + "sizes": ["normal", "big"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "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": ["big", "huge"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addPlateaus, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 25, + g_TileClasses.player, 40, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["big", "huge"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addValleys, + "avoid": [g_TileClasses.bluff, 5, + g_TileClasses.hill, 5, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 10, + g_TileClasses.player, 40, + g_TileClasses.valley, 15, + g_TileClasses.water, 10 + ], + "sizes": ["normal", "big"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } +])); +RMS.SetProgress(60); + +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.valley, 5, + 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(70); + +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(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.spine, 2, + 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.spine, 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.spine, 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/stronghold.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/stronghold.json (nonexistent) +++ ps/trunk/binaries/data/mods/public/maps/random/stronghold.json (revision 17903) @@ -0,0 +1,11 @@ +{ + "settings" : { + "Name" : "Stronghold", + "Script" : "stronghold.js", + "Description" : "Teams start off with nearly adjacent town centers, offering easy military and construction cooperation. With slivers of personal territory, teammates must rely on each other to defend their rear.", + "BaseTerrain" : ["medit_sea_depths"], + "BaseHeight" : 30, + "Preview" : "stronghold.png", + "CircularMap" : true + } +}