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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user