mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
df5cdbe8f1
Because its a function `GenerateMap` is renamed to `generateMap`. Allows to rewrite the libraries as modules and to remove the costum `Engine.LoadLibrary` mechanism in the future.
412 lines
15 KiB
JavaScript
412 lines
15 KiB
JavaScript
Engine.LoadLibrary("rmgen");
|
|
Engine.LoadLibrary("rmgen-common");
|
|
|
|
export function* generateMap()
|
|
{
|
|
globalThis.g_Map = new RandomMap(0, "grass1");
|
|
|
|
/**
|
|
* Demonstration code for wall placement.
|
|
*
|
|
* Some notes/reminders:
|
|
* - All angles (orientation) are in radians.
|
|
* - When looking at the map, with the x-axis being horizontal and the
|
|
* y-axis vertical:
|
|
* -- The origin point (0,0) of the map is in the bottom-left corner,
|
|
* -- A wall orientated at 0 has its "outside" facing right and its
|
|
* "inside" facing left.
|
|
* -- A wall orientated at Pi is reversed (obviously).
|
|
* -- A wall orientated at Pi/2 has its "outside" facing down and its
|
|
* "inside" facing up.
|
|
* - As a general rule, walls are drawn in a anti-clockwise direction.
|
|
*
|
|
* Some general notes concerning the arguments:
|
|
*
|
|
* - The first two arguments for most placement functions are x/y
|
|
* co-ordinates needed to position the wall. These are received via
|
|
* separate arguments, like in placeEntityPassable and their exact
|
|
* meaning differs between methods, but should be mostly self
|
|
* explanatory. The exception to this is placeLinearWall(), where the
|
|
* first four arguments are co-ordinates. However, whether two argument
|
|
* or four, the initial x/y co-ordinates are required parameters.
|
|
*
|
|
* - For some functions, the next argument is radius, indicating how far
|
|
* from a central point the wall should be drawn. The functions that
|
|
* use this are marked as doing so below.
|
|
*
|
|
* - The next argument is usually an array containing wall element type
|
|
* strings. (See the block comment for getWallElement() for a list of
|
|
* accepted type strings.) The exception to this is placeFortress(),
|
|
* which accepts a string here instead, identifying which of the
|
|
* predefined fortresses designs you wish to use. (See the example
|
|
* provided below for details.)
|
|
*
|
|
* Most functions will ask that you do not include "bending" wall
|
|
* elements in your array ("cornerIn", "cornerOut", "turn_{x}") and
|
|
* will complain if you attempt to do so. The ones that do this are
|
|
* clearly marked below.
|
|
*
|
|
* The array will generally look like:
|
|
* ["start", "medium", "tower", "gate", "tower", "medium", "end"]
|
|
*
|
|
* Remember that walls are drawn in an anti-clockwise direction. Thus,
|
|
* when looking at a wall element in-game, with the "outside" facing
|
|
* up, then the *next* wall element will be drawn to the left of *this*
|
|
* element.
|
|
*
|
|
* This argument is optional, and each function has a different default
|
|
* value.
|
|
*
|
|
* - The next argument is a string denoting the style of the wall. These
|
|
* are derived from the names of wallsets defined in 0ad: for example
|
|
* "athen_wallset_stone" becomes "athen_stone", and
|
|
* "rome_wallset_siege" becomes "rome_siege". (A full list can be found
|
|
* stored as the keys of the
|
|
* global constant g_WallStyles.) This argument is optional, and if not
|
|
* set, the civ's basic stone wallset will be used.
|
|
*
|
|
* - The next argument is the player-id of the player that is to own the
|
|
* wall. This argument is optional, and defaults to 0 (gaia).
|
|
*
|
|
* - The next argument is an angle defining the angle of orientation of
|
|
* the wall. The exact use differs slightly between functions, but
|
|
* hopefully the comments on the examples below should help. Also see
|
|
* the notes above about wall orientation. This argument is optional,
|
|
* and defaults to 0.
|
|
*
|
|
* - Any remaining arguments differ from function to function, but are all
|
|
* optional. Please read the comments below, and also the block comment
|
|
* of the function in wall_builder.js for further details.
|
|
*
|
|
* And have fun!
|
|
*/
|
|
|
|
const mapSize = g_Map.getSize();
|
|
|
|
/**
|
|
* General wall placement setup
|
|
*/
|
|
const distToMapBorder = 5;
|
|
const distToOtherWalls = 10;
|
|
const buildableMapSize = mapSize - 2 * distToMapBorder;
|
|
|
|
const position = new Vector2D(distToMapBorder, distToMapBorder);
|
|
const playerID = 0;
|
|
const wallStyleList = Object.keys(g_WallStyles);
|
|
|
|
/**
|
|
* Custom wall placement (element based).
|
|
*
|
|
* Like most wall placement functions, we have to supply an x/y position.
|
|
* In this case, the x/y position marks the start of the wall.
|
|
*
|
|
* For this function, orientation indicates the angle at which the first
|
|
* wall element should be drawn. (The direction that the outside of the
|
|
* first wall element faces towards.)
|
|
*
|
|
* This function permits bending wall elements.
|
|
*/
|
|
for (const styleIndex in wallStyleList)
|
|
{
|
|
const pos = Vector2D.add(position,
|
|
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length));
|
|
const wall = [
|
|
'start',
|
|
'long',
|
|
'tower',
|
|
'tower',
|
|
'tower',
|
|
'medium',
|
|
'outpost',
|
|
'medium',
|
|
'cornerOut',
|
|
'medium',
|
|
'cornerIn',
|
|
'medium',
|
|
'house',
|
|
'end',
|
|
'entryTower',
|
|
'start',
|
|
'short',
|
|
'barracks',
|
|
'gate',
|
|
'tower',
|
|
'medium',
|
|
'fort',
|
|
'medium',
|
|
'end'
|
|
];
|
|
const style = wallStyleList[styleIndex];
|
|
const orientation = Math.PI / 16 * Math.sin(styleIndex * Math.PI / 4);
|
|
placeWall(pos, wall, style, playerID, orientation);
|
|
}
|
|
|
|
position.y += 80 + distToOtherWalls;
|
|
|
|
/**
|
|
* Default fortress placement (chosen by fortress type string)
|
|
*
|
|
* The x/y position in this case marks the center point of the fortress.
|
|
* To make it clearer, we add an obilisk as a visual marker.
|
|
*
|
|
* This is the only wall placement function that does not take an array
|
|
* of elements as an argument. Instead, we provide a "type" that
|
|
* identifies a predefined design to draw. The list of possible types are:
|
|
* "tiny", "small", "medium", "normal", "large", "veryLarge", and "giant".
|
|
*
|
|
* For this function, orientation is the direction in which the main gate
|
|
* is facing.
|
|
*/
|
|
// The space the fortresses take in average. Just for design of this map.
|
|
// Not passed to the function.
|
|
const fortressRadius = 15;
|
|
for (const styleIndex in wallStyleList)
|
|
{
|
|
const type = "tiny";
|
|
const style = wallStyleList[styleIndex];
|
|
const orientation = styleIndex * Math.PI / 32;
|
|
|
|
const pos = Vector2D.sum([
|
|
position,
|
|
new Vector2D(1, 1).mult(fortressRadius),
|
|
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
|
]);
|
|
|
|
g_Map.placeEntityPassable("structures/obelisk", playerID, pos, orientation);
|
|
placeFortress(pos, type, style, playerID, orientation);
|
|
}
|
|
|
|
position.y += 2 * fortressRadius + distToOtherWalls;
|
|
|
|
/**
|
|
* 'Generic' fortress placement (iberian wall circuit code)
|
|
*
|
|
* The function used here is unusual in that the owner and style arguments
|
|
* are swapped. It is also unusual in that we do not supply an
|
|
* orientation.
|
|
*
|
|
* The x/y position in this case marks the center point of the fortress.
|
|
* To make it clearer, we add an obilisk as a visual marker.
|
|
*
|
|
* We also supply a radius value to dictate how wide the circuit of walls
|
|
* should be.
|
|
*/
|
|
let radius = Math.min((mapSize - position.y - distToOtherWalls) / 3,
|
|
(buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
|
for (const styleIndex in wallStyleList)
|
|
{
|
|
const style = wallStyleList[styleIndex];
|
|
|
|
const pos = Vector2D.sum([
|
|
position,
|
|
new Vector2D(radius, radius),
|
|
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
|
]);
|
|
|
|
g_Map.placeEntityPassable("structures/obelisk", playerID, pos, 0);
|
|
placeGenericFortress(pos, radius, playerID, style);
|
|
}
|
|
|
|
position.y += 2 * radius + distToOtherWalls;
|
|
|
|
/**
|
|
* Circular wall placement
|
|
*
|
|
* It is possible with this function to draw complete circles, or arcs.
|
|
* Each side of the wall consists of the contents of the provided wall
|
|
* array, with the code calculating the number and angle of turns and
|
|
* sides automatically based on the calculated length of each side and
|
|
* the given radius.
|
|
*
|
|
* This function does not permit the use of bending wall elements.
|
|
*
|
|
* In this case, the x/y co-ordinates are the center point around which
|
|
* to draw the walls. To make this clearer, we add an obelisk as a visual
|
|
* marker.
|
|
*
|
|
* We also provide a radius to define the distance between the center
|
|
* point and the walls.
|
|
*
|
|
* For this function, orientation is the direction that the opening of an
|
|
* arc faces. If the wall is to be a complete circle, then this is used as
|
|
* the orientation of the first wall piece.
|
|
*/
|
|
radius = Math.min((mapSize - position.y - distToOtherWalls) / 3,
|
|
(buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
|
for (const styleIndex in wallStyleList)
|
|
{
|
|
const center = Vector2D.sum(
|
|
[
|
|
position,
|
|
new Vector2D(1, 1).mult(radius),
|
|
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
|
]);
|
|
const wallPart = ['tower', 'medium', 'house'];
|
|
const style = wallStyleList[styleIndex];
|
|
const orientation = styleIndex * Math.PI / 16;
|
|
|
|
// maxAngle is how far the wall should circumscribe the center.
|
|
// If equal to Pi * 2, then the wall will be a full circle.
|
|
// If less than Pi * 2, then the wall will be an arc.
|
|
const maxAngle = Math.PI / 2 * (styleIndex % 3 + 2);
|
|
|
|
g_Map.placeEntityPassable("structures/obelisk", playerID, center, orientation);
|
|
placeCircularWall(center, radius, wallPart, style, playerID, orientation, maxAngle);
|
|
}
|
|
|
|
position.y += 2 * radius + distToOtherWalls;
|
|
|
|
/**
|
|
* Regular Polygonal wall placement
|
|
*
|
|
* This function draws a regular polygonal wall around a given point. All
|
|
* the sides follow the same pattern, and the (automatically calculated)
|
|
* angles at the corners are identical. We define how many corners we
|
|
* want.
|
|
*
|
|
* This function does not permit the use of bending wall elements.
|
|
*
|
|
* In this case, the x/y co-ordinates are the center point around which
|
|
* to draw the walls. To make this clearer, we add an obelisk as a visual
|
|
* marker.
|
|
*
|
|
* We also provide a radius to define the distance between the center
|
|
* point and the walls.
|
|
*
|
|
* After the usual array of wall elements to use, and before the style
|
|
* argument, we provide the name of a single wall element to use as a
|
|
* corner piece.
|
|
*
|
|
* In this function, orientation is the direction the first wall has its
|
|
* outward side facing or, if the `skipFirstWall` argument is true, the
|
|
* opening in the wall.
|
|
*/
|
|
|
|
radius = Math.min((mapSize - position.y - distToOtherWalls) / 2,
|
|
(buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
|
for (const styleIndex in wallStyleList)
|
|
{
|
|
const centerPosition = Vector2D.sum(
|
|
[
|
|
position,
|
|
new Vector2D(1, 1).mult(radius),
|
|
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
|
]);
|
|
// Function default: ['long', 'tower']
|
|
const wallParts = ['medium', 'tower'];
|
|
|
|
// Which wall element to use for the corners of the polygon
|
|
const cornerWallElement = 'tower';
|
|
|
|
const style = wallStyleList[styleIndex];
|
|
const orientation = styleIndex * Math.PI / 16;
|
|
|
|
// How many corners the polygon should have:
|
|
const numCorners = styleIndex % 6 + 3;
|
|
|
|
// If true, the first side will not be drawn, leaving the wall open.
|
|
const skipFirstWall = true;
|
|
|
|
g_Map.placeEntityPassable("structures/obelisk", playerID, centerPosition, orientation);
|
|
placePolygonalWall(centerPosition, radius, wallParts, cornerWallElement, style, playerID,
|
|
orientation, numCorners, skipFirstWall);
|
|
}
|
|
|
|
position.y += 2 * radius + distToOtherWalls;
|
|
|
|
/**
|
|
* Irregular Polygonal wall placement
|
|
*
|
|
* This function draws an irregular polygonal wall around a given point.
|
|
* Each side of the wall is different, each element used selected at
|
|
* pesudo-random from an assortment. The angles at the corners also differ.
|
|
* We can control this randomness by changing the irregularity argument.
|
|
*
|
|
* This function does not permit the use of bending wall elements.
|
|
*
|
|
* In this case, the x/y co-ordinates are the center point around which
|
|
* to draw the walls. To make this clearer, we add an obelisk as a visual
|
|
* marker.
|
|
*
|
|
* We also provide a radius to define the distance between the center
|
|
* point and the walls.
|
|
*
|
|
* The usual array of wall elements is left out here, instead we provide
|
|
* the name of a single wall element to use as a corner piece.
|
|
*
|
|
* In this function, orientation is the direction the first wall has its
|
|
* outward side facing or, if the `skipFirstWall` argument is true, the
|
|
* opening in the wall.
|
|
*
|
|
* The very last argument is the collection of wallparts used to build
|
|
* the wall. It is not defined in this example (so as to use the defaults)
|
|
* as it is not easy to comprehend.
|
|
*/
|
|
// The radius of wall polygons
|
|
radius = Math.min((mapSize - position.y - distToOtherWalls) / 2,
|
|
(buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
|
for (const styleIndex in wallStyleList)
|
|
{
|
|
const centerPosition = Vector2D.sum([
|
|
position,
|
|
new Vector2D(1, 1).mult(radius),
|
|
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
|
]);
|
|
|
|
// Which wall element type will be used for the corners of the
|
|
// polygon.
|
|
const cornerWallElement = 'tower';
|
|
|
|
const style = wallStyleList[styleIndex];
|
|
const orientation = styleIndex * Math.PI / 16;
|
|
|
|
// How many corners the polygon will have
|
|
const numCorners = styleIndex % 6 + 3;
|
|
|
|
// Irregularity of the polygon.
|
|
const irregularity = 0.5;
|
|
|
|
// If true, the first side will not be drawn, leaving the wall open.
|
|
const skipFirstWall = true;
|
|
|
|
g_Map.placeEntityPassable("structures/obelisk", playerID, centerPosition, orientation);
|
|
placeIrregularPolygonalWall(centerPosition, radius, cornerWallElement, style, playerID,
|
|
orientation, numCorners, irregularity, skipFirstWall);
|
|
}
|
|
|
|
position.y += 2 * radius + distToOtherWalls;
|
|
|
|
/**
|
|
* Linear wall placement
|
|
*
|
|
* This function draws a straight wall between two given points.
|
|
*
|
|
* This function does not permit the use of bending wall elements.
|
|
*
|
|
* This function has no orientation parameter, the wall pieces are angled
|
|
* automatically. Remember: each piece is placed to the left of the
|
|
* previous piece. Thus, if the start point is at the right-hand side of
|
|
* the screen and the end point is at the left-hand side, the "outside"
|
|
* of the walls is facing the top of the screen.
|
|
*/
|
|
// Two vars, just for this map; firstly how long the longest wall will be.
|
|
const maxWallLength = (mapSize - position.y - distToMapBorder - distToOtherWalls);
|
|
// And secondly, how many walls of the same style will be placed.
|
|
const numWallsPerStyle = Math.floor(buildableMapSize / distToOtherWalls / wallStyleList.length);
|
|
|
|
for (const styleIndex in wallStyleList)
|
|
for (let wallIndex = 0; wallIndex < numWallsPerStyle; ++wallIndex)
|
|
{
|
|
const offsetX = (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize /
|
|
wallStyleList.length / numWallsPerStyle;
|
|
const start = Vector2D.add(position, new Vector2D(offsetX, 0));
|
|
|
|
const offsetY = (wallIndex + 1) * maxWallLength / numWallsPerStyle;
|
|
const end = Vector2D.add(position, new Vector2D(offsetX, offsetY));
|
|
|
|
placeLinearWall(start, end, ['tower', 'medium'], wallStyleList[styleIndex], playerID);
|
|
}
|
|
|
|
return g_Map;
|
|
}
|