1
0
forked from mirrors/0ad

Move rmgen player location functions from library.js to player.js, refs #4804.

Doesn't change the code besides abstracting distributePointsOnCircle and
attempting to improve the documentation, refs #4831.

This was SVN commit r20416.
This commit is contained in:
elexis
2017-11-06 13:40:10 +00:00
parent df14c914e6
commit 6fb6a65fc5
3 changed files with 137 additions and 111 deletions
@@ -400,106 +400,6 @@ function getPlayerTeam(player)
return g_MapSettings.PlayerData[player+1].Team;
}
/**
* Sorts an array of player IDs by team index. Players without teams come first.
* Randomize order for players of the same team.
*/
function sortPlayers(playerIndices)
{
return shuffleArray(playerIndices).sort((p1, p2) => getPlayerTeam(p1 - 1) - getPlayerTeam(p2 - 1));
}
/**
* Mix player indices but sort by team.
*
* @returns {Array} - every item is an array of player indices
*/
function sortAllPlayers()
{
let playerIDs = [];
for (let i = 0; i < getNumPlayers(); ++i)
playerIDs.push(i+1);
return sortPlayers(playerIDs);
}
function primeSortPlayers(playerIndices)
{
if (!playerIndices.length)
return [];
let prime = [];
for (let i = 0; i < Math.ceil(playerIndices.length / 2); ++i)
{
prime.push(playerIndices[i]);
prime.push(playerIndices[playerIndices.length - 1 - i]);
}
return prime;
}
function primeSortAllPlayers()
{
return primeSortPlayers(sortAllPlayers());
}
function radialPlayerPlacement(percentRadius = 0.35)
{
let playerIDs = sortAllPlayers();
let playerX = [];
let playerZ = [];
let playerAngle = [];
let startAngle = randFloat(0, TWO_PI);
for (let i = 0; i < getNumPlayers(); ++i)
{
playerAngle[i] = startAngle + i * TWO_PI / getNumPlayers();
playerX[i] = 0.5 + percentRadius * Math.cos(playerAngle[i]);
playerZ[i] = 0.5 + percentRadius * Math.sin(playerAngle[i]);
}
return [playerIDs, playerX, playerZ, playerAngle, startAngle];
}
/**
* Returns an array of percent numbers indicating the player location on river maps.
* For example [0.2, 0.2, 0.4, 0.4, 0.6, 0.6, 0.8, 0.8] for a 4v4 or
* [0.25, 0.33, 0.5, 0.67, 0.75] for a 2v3.
*/
function placePlayersRiver()
{
let playerPos = [];
let numPlayers = getNumPlayers();
let numPlayersEven = numPlayers % 2 == 0;
for (let i = 0; i < numPlayers; ++i)
{
let currentPlayerEven = i % 2 == 0;
let offsetDivident = numPlayersEven || currentPlayerEven ? (i + 1) % 2 : 0;
let offsetDivisor = numPlayersEven ? 0 : currentPlayerEven ? +1 : -1;
playerPos[i] = ((i - 1 + offsetDivident) / 2 + 1) / ((numPlayers + offsetDivisor) / 2 + 1);
}
return playerPos;
}
function getStartingEntities(player)
{
let civ = getCivCode(player);
if (!g_CivData[civ] || !g_CivData[civ].StartEntities || !g_CivData[civ].StartEntities.length)
{
warn("Invalid or unimplemented civ '"+civ+"' specified, falling back to '" + FALLBACK_CIV + "'");
civ = FALLBACK_CIV;
}
return g_CivData[civ].StartEntities;
}
function getHeight(x, z)
{
return g_Map.getHeight(x, z);
@@ -621,17 +521,6 @@ function getTerrainTexture(x, y)
return g_Map.getTexture(x, y);
}
function addCivicCenterAreaToClass(ix, iz, tileClass)
{
addToClass(ix, iz, tileClass);
addToClass(ix, iz + 5, tileClass);
addToClass(ix, iz - 5, tileClass);
addToClass(ix + 5, iz, tileClass);
addToClass(ix - 5, iz, tileClass);
}
/**
* Returns the order to go through the points for the shortest closed path (array of indices)
* @param {array} [points] - Points to be sorted of the form { "x": x_value, "y": y_value }
@@ -12,6 +12,9 @@ function getAngle(x1, z1, x2, z2)
return Math.atan2(z2 - z1, x2 - x1);
}
/**
* Revolve the given point around the given rotation center.
*/
function rotateCoordinates(x, z, angle, centerX = 0.5, centerZ = 0.5)
{
let sin = Math.sin(angle);
@@ -22,6 +25,26 @@ function rotateCoordinates(x, z, angle, centerX = 0.5, centerZ = 0.5)
sin * (x - centerX) + cos * (z - centerZ) + centerZ
];
}
/**
* Get pointCount points equidistantly located on a circle.
*/
function distributePointsOnCircle(pointCount, startAngle, radius, centerX, centerZ)
{
let x = [];
let z = [];
let angle = [];
for (let i = 0; i < pointCount; ++i)
{
angle[i] = startAngle + 2 * Math.PI * i / pointCount;
x[i] = centerX + radius * Math.cos(angle[i]);
z[i] = centerZ + radius * Math.sin(angle[i]);
}
return [x, z, angle];
}
/**
* Returns the distance of a point from a line.
*/
@@ -1,3 +1,23 @@
/**
* @file These functions locate and place the starting entities of players.
*/
/**
* Gets the default starting entities for the civ of the given player, as defined by the civ file.
*/
function getStartingEntities(playerID)
{
let civ = getCivCode(playerID);
if (!g_CivData[civ] || !g_CivData[civ].StartEntities || !g_CivData[civ].StartEntities.length)
{
warn("Invalid or unimplemented civ '" + civ + "' specified, falling back to '" + FALLBACK_CIV + "'");
civ = FALLBACK_CIV;
}
return g_CivData[civ].StartEntities;
}
/**
* Places the given entities at the given location (typically a civic center and starting units).
* @param civEntities - An array of objects with the Template property and optionally a Count property.
@@ -47,3 +67,97 @@ function placeCivDefaultEntities(fx, fz, playerID, kwargs, dist = 6, orientation
placeGenericFortress(fx, fz, 20, playerID);
}
}
/**
* Marks the corner and center tiles of an area that is about the size of a Civic Center with the given TileClass.
* Used to prevent resource collisions with the Civic Center.
*/
function addCivicCenterAreaToClass(ix, iz, tileClass)
{
addToClass(ix, iz, tileClass);
addToClass(ix, iz + 5, tileClass);
addToClass(ix, iz - 5, tileClass);
addToClass(ix + 5, iz, tileClass);
addToClass(ix - 5, iz, tileClass);
}
/**
* Sorts an array of player IDs by team index. Players without teams come first.
* Randomize order for players of the same team.
*/
function sortPlayers(playerIDs)
{
return shuffleArray(playerIDs).sort((p1, p2) => getPlayerTeam(p1 - 1) - getPlayerTeam(p2 - 1));
}
/**
* Randomize playerIDs but sort by team.
*
* @returns {Array} - every item is an array of player indices
*/
function sortAllPlayers()
{
let playerIDs = [];
for (let i = 0; i < getNumPlayers(); ++i)
playerIDs.push(i+1);
return sortPlayers(playerIDs);
}
/**
* Rearrange order so that teams of neighboring players alternate (if the given IDs are sorted by team).
*/
function primeSortPlayers(playerIDs)
{
if (!playerIDs.length)
return [];
let prime = [];
for (let i = 0; i < Math.ceil(playerIDs.length / 2); ++i)
{
prime.push(playerIDs[i]);
prime.push(playerIDs[playerIDs.length - 1 - i]);
}
return prime;
}
function primeSortAllPlayers()
{
return primeSortPlayers(sortAllPlayers());
}
/**
* Determine player starting positions on a circular pattern.
*/
function radialPlayerPlacement(radius = 0.35, startingAngle = undefined, centerX = 0.5, centerZ = 0.5)
{
let startAngle = startingAngle !== undefined ? startingAngle : randFloat(0, 2 * Math.PI);
return [sortAllPlayers(), ...distributePointsOnCircle(getNumPlayers(), startAngle, radius, centerX, centerZ), startAngle];
}
/**
* Returns an array of percent numbers indicating the player location on river maps.
* For example [0.2, 0.2, 0.4, 0.4, 0.6, 0.6, 0.8, 0.8] for a 4v4 or
* [0.25, 0.33, 0.5, 0.67, 0.75] for a 2v3.
*/
function placePlayersRiver()
{
let playerPos = [];
let numPlayers = getNumPlayers();
let numPlayersEven = numPlayers % 2 == 0;
for (let i = 0; i < numPlayers; ++i)
{
let currentPlayerEven = i % 2 == 0;
let offsetDivident = numPlayersEven || currentPlayerEven ? (i + 1) % 2 : 0;
let offsetDivisor = numPlayersEven ? 0 : currentPlayerEven ? +1 : -1;
playerPos[i] = ((i - 1 + offsetDivident) / 2 + 1) / ((numPlayers + offsetDivisor) / 2 + 1);
}
return playerPos;
}