forked from 0ad/0ad
Random-map-script cleanup.
Move duplicate code of the area- and object-group placing methods to retryPlacing and two coordinate-randomization functions. Remove three unused functions (println obsolete since0e0ed94926
, chooseRand and its helper argsToArray since before34f1817869
). Inline local calls to GetMapSize() and IsCircularMap(). Keep unused isCircularMap for API access. Cache variables when retrying. Map-generation can finish 2% faster. This was SVN commit r17728.
This commit is contained in:
parent
fdc67768f0
commit
6052716a78
@ -10,12 +10,12 @@ const FALLBACK_CIV = "athen";
|
||||
|
||||
function fractionToTiles(f)
|
||||
{
|
||||
return getMapSize() * f;
|
||||
return g_Map.size * f;
|
||||
}
|
||||
|
||||
function tilesToFraction(t)
|
||||
{
|
||||
return t / getMapSize();
|
||||
return t / g_Map.size;
|
||||
}
|
||||
|
||||
function fractionToSize(f)
|
||||
@ -30,7 +30,7 @@ function sizeToFraction(s)
|
||||
|
||||
function scaleByMapSize(min, max)
|
||||
{
|
||||
return min + ((max-min) * (getMapSize()-MIN_MAP_SIZE) / (MAX_MAP_SIZE-MIN_MAP_SIZE));
|
||||
return min + (max - min) * (g_Map.size - MIN_MAP_SIZE) / (MAX_MAP_SIZE - MIN_MAP_SIZE);
|
||||
}
|
||||
|
||||
function cos(x)
|
||||
@ -82,245 +82,200 @@ function min(a, b)
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
function println(x)
|
||||
{
|
||||
print(x);
|
||||
print("\n");
|
||||
}
|
||||
|
||||
function argsToArray(x)
|
||||
{
|
||||
var numArgs = x.length;
|
||||
if (numArgs != 1)
|
||||
{
|
||||
var ret = new Array(numArgs);
|
||||
for (var i=0; i < numArgs; i++)
|
||||
{
|
||||
ret[i] = x[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
return x[0];
|
||||
}
|
||||
}
|
||||
|
||||
function chooseRand()
|
||||
{
|
||||
if (arguments.length==0)
|
||||
{
|
||||
throw("chooseRand: requires at least 1 argument");
|
||||
}
|
||||
var ar = argsToArray(arguments);
|
||||
return ar[randInt(ar.length)];
|
||||
}
|
||||
|
||||
// "Inside-out" implementation of Fisher-Yates shuffle
|
||||
/**
|
||||
* "Inside-out" implementation of Fisher-Yates shuffle
|
||||
*/
|
||||
function shuffleArray(source)
|
||||
{
|
||||
if (!source.length)
|
||||
return [];
|
||||
|
||||
var result = [source[0]];
|
||||
for (var i = 1; i < source.length; i++)
|
||||
let result = [source[0]];
|
||||
for (let i = 1; i < source.length; ++i)
|
||||
{
|
||||
var j = randInt(0, i);
|
||||
let j = randInt(0, i);
|
||||
result[i] = result[j];
|
||||
result[j] = source[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function createAreas(centeredPlacer, painter, constraint, num, retryFactor)
|
||||
/**
|
||||
* Retries the given function with those arguments as often as specified.
|
||||
*/
|
||||
function retryPlacing(placeFunc, placeArgs, retryFactor, amount, getResult)
|
||||
{
|
||||
if (retryFactor === undefined)
|
||||
{
|
||||
retryFactor = 10;
|
||||
}
|
||||
|
||||
var maxFail = num * retryFactor;
|
||||
var good = 0;
|
||||
var bad = 0;
|
||||
var result = [];
|
||||
var halfSize = getMapSize()/2;
|
||||
|
||||
while(good < num && bad <= maxFail)
|
||||
{
|
||||
if (isCircularMap())
|
||||
{ // Polar coordinates
|
||||
var r = halfSize * Math.sqrt(randFloat()); // uniform distribution
|
||||
var theta = randFloat(0, 2 * PI);
|
||||
centeredPlacer.x = Math.floor(r * Math.cos(theta)) + halfSize;
|
||||
centeredPlacer.z = Math.floor(r * Math.sin(theta)) + halfSize;
|
||||
}
|
||||
else
|
||||
{ // Rectangular coordinates
|
||||
centeredPlacer.x = randInt(getMapSize());
|
||||
centeredPlacer.z = randInt(getMapSize());
|
||||
}
|
||||
|
||||
var area = g_Map.createArea(centeredPlacer, painter, constraint);
|
||||
if (area !== undefined)
|
||||
{
|
||||
good++;
|
||||
result.push(area);
|
||||
}
|
||||
else
|
||||
{
|
||||
bad++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
let maxFail = amount * retryFactor;
|
||||
|
||||
function createAreasInAreas(centeredPlacer, painter, constraint, num, retryFactor, areas)
|
||||
{
|
||||
if (retryFactor === undefined)
|
||||
{
|
||||
retryFactor = 10;
|
||||
}
|
||||
|
||||
var maxFail = num * retryFactor;
|
||||
var good = 0;
|
||||
var bad = 0;
|
||||
var result = [];
|
||||
var numAreas = areas.length;
|
||||
|
||||
while(good < num && bad <= maxFail && numAreas)
|
||||
{
|
||||
// Choose random point from area
|
||||
var i = randInt(numAreas);
|
||||
var size = areas[i].points.length;
|
||||
var pt = areas[i].points[randInt(size)];
|
||||
centeredPlacer.x = pt.x;
|
||||
centeredPlacer.z = pt.z;
|
||||
|
||||
var area = g_Map.createArea(centeredPlacer, painter, constraint);
|
||||
if (area !== undefined)
|
||||
{
|
||||
good++;
|
||||
result.push(area);
|
||||
}
|
||||
else
|
||||
{
|
||||
bad++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
let results = [];
|
||||
let good = 0;
|
||||
let bad = 0;
|
||||
|
||||
function createObjectGroups(placer, player, constraint, num, retryFactor)
|
||||
{
|
||||
if (retryFactor === undefined)
|
||||
while (good < amount && bad <= maxFail)
|
||||
{
|
||||
retryFactor = 10;
|
||||
}
|
||||
|
||||
var maxFail = num * retryFactor;
|
||||
var good = 0;
|
||||
var bad = 0;
|
||||
var halfSize = getMapSize()/2 - 3;
|
||||
while(good < num && bad <= maxFail)
|
||||
{
|
||||
if (isCircularMap())
|
||||
{ // Polar coordinates
|
||||
var r = halfSize * Math.sqrt(randFloat()); // uniform distribution
|
||||
var theta = randFloat(0, 2 * PI);
|
||||
placer.x = Math.floor(r * Math.cos(theta)) + halfSize;
|
||||
placer.z = Math.floor(r * Math.sin(theta)) + halfSize;
|
||||
}
|
||||
else
|
||||
{ // Rectangular coordinates
|
||||
placer.x = randInt(getMapSize());
|
||||
placer.z = randInt(getMapSize());
|
||||
}
|
||||
|
||||
var result = createObjectGroup(placer, player, constraint);
|
||||
let result = placeFunc(placeArgs);
|
||||
|
||||
if (result !== undefined)
|
||||
{
|
||||
good++;
|
||||
++good;
|
||||
if (getResult)
|
||||
results.push(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
bad++;
|
||||
}
|
||||
++bad;
|
||||
}
|
||||
return good;
|
||||
return getResult ? results : good;
|
||||
}
|
||||
|
||||
function createObjectGroupsByAreas(placer, player, constraint, num, retryFactor, areas)
|
||||
/**
|
||||
* Helper function for randomly placing areas and groups on the map.
|
||||
*/
|
||||
function randomizePlacerCoordinates(placer, halfMapSize)
|
||||
{
|
||||
if (retryFactor === undefined)
|
||||
if (!!g_MapSettings.CircularMap)
|
||||
{
|
||||
retryFactor = 10;
|
||||
// Polar coordinates
|
||||
let r = halfMapSize * Math.sqrt(randFloat()); // uniform distribution
|
||||
let theta = randFloat(0, 2 * PI);
|
||||
placer.x = Math.floor(r * Math.cos(theta)) + halfMapSize;
|
||||
placer.z = Math.floor(r * Math.sin(theta)) + halfMapSize;
|
||||
}
|
||||
|
||||
var maxFail = num * retryFactor;
|
||||
var good = 0;
|
||||
var bad = 0;
|
||||
var numAreas = areas.length;
|
||||
|
||||
while(good < num && bad <= maxFail && numAreas)
|
||||
else
|
||||
{
|
||||
// Choose random point from area
|
||||
var i = randInt(numAreas);
|
||||
var size = areas[i].points.length;
|
||||
var pt = areas[i].points[randInt(size)];
|
||||
placer.x = pt.x;
|
||||
placer.z = pt.z;
|
||||
|
||||
var result = createObjectGroup(placer, player, constraint);
|
||||
if (result !== undefined)
|
||||
{
|
||||
good++;
|
||||
}
|
||||
else
|
||||
{
|
||||
bad++;
|
||||
}
|
||||
// Rectangular coordinates
|
||||
placer.x = randInt(g_Map.size);
|
||||
placer.z = randInt(g_Map.size);
|
||||
}
|
||||
return good;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for randomly placing areas and groups in the given areas.
|
||||
*/
|
||||
function randomizePlacerCoordinatesFromAreas(placer, areas)
|
||||
{
|
||||
let i = randInt(areas.length);
|
||||
let pt = areas[i].points[randInt(areas[i].points.length)];
|
||||
|
||||
placer.x = pt.x;
|
||||
placer.z = pt.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to place the given number of areas in random places of the map.
|
||||
* Returns actually placed areas.
|
||||
*/
|
||||
function createAreas(centeredPlacer, painter, constraint, amount, retryFactor = 10)
|
||||
{
|
||||
let placeFunc = function (args) {
|
||||
randomizePlacerCoordinates(args.placer, args.halfMapSize);
|
||||
return g_Map.createArea(args.placer, args.painter, args.constraint);
|
||||
};
|
||||
|
||||
let args = {
|
||||
"placer": centeredPlacer,
|
||||
"painter": painter,
|
||||
"constraint": constraint,
|
||||
"halfMapSize": g_Map.size / 2
|
||||
};
|
||||
|
||||
return retryPlacing(placeFunc, args, retryFactor, amount, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to place the given number of areas in random places of the given areas.
|
||||
* Returns actually placed areas.
|
||||
*/
|
||||
function createAreasInAreas(centeredPlacer, painter, constraint, amount, retryFactor, areas)
|
||||
{
|
||||
if (!areas.length)
|
||||
return [];
|
||||
|
||||
let placeFunc = function (args) {
|
||||
randomizePlacerCoordinatesFromAreas(args.placer, args.areas);
|
||||
return g_Map.createArea(args.placer, args.painter, args.constraint);
|
||||
};
|
||||
|
||||
let args = {
|
||||
"placer": centeredPlacer,
|
||||
"painter": painter,
|
||||
"constraint": constraint,
|
||||
"areas": areas,
|
||||
"halfMapSize": g_Map.size / 2
|
||||
};
|
||||
|
||||
return retryPlacing(placeFunc, args, retryFactor, amount, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to place the given number of groups in random places of the map.
|
||||
* Returns the number of actually placed groups.
|
||||
*/
|
||||
function createObjectGroups(placer, player, constraint, amount, retryFactor = 10)
|
||||
{
|
||||
let placeFunc = function (args) {
|
||||
randomizePlacerCoordinates(args.placer, args.halfMapSize);
|
||||
return createObjectGroup(args.placer, args.player, args.constraint);
|
||||
};
|
||||
|
||||
let args = {
|
||||
"placer": placer,
|
||||
"player": player,
|
||||
"constraint": constraint,
|
||||
"halfMapSize": g_Map.size / 2 - 3
|
||||
};
|
||||
|
||||
return retryPlacing(placeFunc, args, retryFactor, amount, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to place the given number of groups in random places of the given areas.
|
||||
* Returns the number of actually placed groups.
|
||||
*/
|
||||
function createObjectGroupsByAreas(placer, player, constraint, amount, retryFactor, areas)
|
||||
{
|
||||
if (!areas.length)
|
||||
return 0;
|
||||
|
||||
let placeFunc = function (args) {
|
||||
randomizePlacerCoordinatesFromAreas(args.placer, args.areas);
|
||||
return createObjectGroup(args.placer, args.player, args.constraint);
|
||||
};
|
||||
|
||||
let args = {
|
||||
"placer": placer,
|
||||
"player": player,
|
||||
"constraint": constraint,
|
||||
"areas": areas
|
||||
};
|
||||
|
||||
return retryPlacing(placeFunc, args, retryFactor, amount, false);
|
||||
}
|
||||
|
||||
function createTerrain(terrain)
|
||||
{
|
||||
if (terrain instanceof Array)
|
||||
{
|
||||
var terrainList = [];
|
||||
|
||||
for (var i = 0; i < terrain.length; ++i)
|
||||
{
|
||||
terrainList.push(createTerrain(terrain[i]));
|
||||
}
|
||||
|
||||
return new RandomTerrain(terrainList);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(terrain instanceof Array))
|
||||
return createSimpleTerrain(terrain);
|
||||
}
|
||||
|
||||
let terrainList = [];
|
||||
|
||||
for (let i = 0; i < terrain.length; ++i)
|
||||
terrainList.push(createTerrain(terrain[i]));
|
||||
|
||||
return new RandomTerrain(terrainList);
|
||||
}
|
||||
|
||||
function createSimpleTerrain(terrain)
|
||||
{
|
||||
if (typeof(terrain) == "string")
|
||||
{ // Split string by pipe | character, this allows specifying terrain + tree type in single string
|
||||
var params = terrain.split(TERRAIN_SEPARATOR, 2);
|
||||
|
||||
if (params.length != 2)
|
||||
{
|
||||
return new SimpleTerrain(terrain);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SimpleTerrain(params[0], params[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (typeof(terrain) != "string")
|
||||
throw("createSimpleTerrain expects string as input, received "+terrain);
|
||||
}
|
||||
|
||||
// Split string by pipe | character, this allows specifying terrain + tree type in single string
|
||||
let params = terrain.split(TERRAIN_SEPARATOR, 2);
|
||||
|
||||
if (params.length != 2)
|
||||
return new SimpleTerrain(terrain);
|
||||
|
||||
return new SimpleTerrain(params[0], params[1]);
|
||||
}
|
||||
|
||||
function placeObject(x, z, type, player, angle)
|
||||
@ -420,7 +375,7 @@ function primeSortPlayers(playerIndices)
|
||||
if (!playerIndices.length)
|
||||
return [];
|
||||
|
||||
let prime = []
|
||||
let prime = [];
|
||||
for (let i = 0; i < Math.ceil(playerIndices.length / 2); ++i)
|
||||
{
|
||||
prime.push(playerIndices[i]);
|
||||
|
Loading…
Reference in New Issue
Block a user