=== Map Functions v1.5.6 === Created: 10/07/04 by Mikail === Last updated: 05/08/08 === Homepage: === http://isometricland.com/homeworld/homeworld.php === Discussion: === http://forums.relicnews.com/showthread.php?t=82964 === http://forums.relicnews.com/showthread.php?t=40779 (old thread) ================================================================ DESCRIPTION A collection of custom map functions, as well as a map creation API, to be used within your own maps. INSTALLATION Extract this archive into your "Homeworld2\Data\Scripts\" directory. You must have also installed the Homeworld 2 v1.1 patch in order for these functions to work. INSTRUCTIONS If you're familiar with how maps were created in the original Homeworld, then you already already have a head start in understanding how these functions work. Like Homeworld 1, most of the included functions create "fields" (or "bunches") of resources that are later populated using "distribution" tables. You don't control the position of every object in the "field"; rather, you set the position (as well as other basic properties) of the field, and the map functions fill the area randomly with the individual objects. Documentation for the basic properties of each function, and the parameters they take, can be found in the form of comments within "MapFunctions.lua" itself. USING THESE FUNCTIONS IN YOUR MAP In order to utilize the functions in this archive, you must do one of two things: 1. Copy the contents of "MapFunctions.lua" to the end of your level file. 2. Add the following line to the beginning of your level file: dofilepath("data:scripts\MapFunctions.lua") (Note: if you choose the second method, you may not be able to host your maps over GameSpy or the Internet.) Additionally, these rules must be followed: • Map functions must be called from within either the "DetermChunk" portion of your level file, or the "NonDetermChunk" portion of your level file, depending on the particular function you're trying to use (see list of functions, below). • Map functions must be defined outside of any other function (don't define the function in "DetermChunk" or "NonDetermChunk"). • Distribution tables should be defined within the "DetermChunk" portion of your level file, and must be declared before any of the functions reference them. ================================================================ HOW THE MAPS WORK This map maker uses a principle of populating a map with objects stored in containers--called 'Distributions'--that is carried over from the original Homeworld and Homeworld: Cataclysm. Distributions are an efficient means of storing data and making changes to large numbers of objects, simply and easily. Distributions exist in the form of tables (or arrays) of information. All map objects are stored in these tables. These tables contain all the information (in the form of parameters) necessary to recreate the map objects. These tables can also contain objects that reference other tables, thereby making it possible to nes objects within each other. Distribution tables are declared at the head of the 'DetermChunk' portion of a level file, and are referenced later by the map-populating functions. Each map MUST have one distribution named 'Main'. This is the top-level distribution. All objects stored in this distribution are added to the map as entered. Each distribution uses a local coordinate system, so if distributions are nested, then the coordinates from one distribution are added to the coordinates of the other distribution. The map-populating functions (such as the 'shapeAdd' function) count the number and types of objects within a distribution and place the objects on the map according to an algorithm. Any coordinates specified within the distribution are calculated in addition to whatever positional changes made by the algorithm. ================================================================ INCLUDED MAP FUNCTIONS Here is a list of some of most of the most important functions included in "MapFunctions.lua". Many more aren't listed. They can be broadly separated into two types: 1. "DETERMCHUNK" FUNCTIONS (these go in the "DetermChunk" portion of your level file): • branchAdd: Creates a branching tree. • splineAdd: Creates a spline-shaped tube connecting any two points using two control points. • ringAdd: Creates an elliptical ring. • globeAdd: Creates a series of rings in the shape of a sphere, like the lattitudinal and longitudinal lines of a globe. • shapeAdd: Creates one of several available mathematical shapes. • spiralAdd: Creates a nautilus (equiangular) or Archimedes spiral. • easyPatch: Creates a resource patch with minimal effort. 2. "NONDETERMCHUNK" FUNCTIONS (these go in the "NonDetermChunk" portion of your level file): • randomMusic: Randomly selects the level music. • randomBackground: Randomly selects the level background. ================================================================ DISTRIBUTION TABLES Distribution tables determine the number and type of objects that are used to fill a shape. Without a distribution table to tell the function what to fill a shape with, a shape created with any of the above functions would be completely empty (like an empty container). Here's an example of a distribution table: local MyDist = { {512, "Pebble", "Pebble_0", {0,0,0,}, 0, 0, 0,}, {4, "Asteroid", "Asteroid_4", {0,0,0,}, 100, 0, 0, 0, 0,}, {12, "Asteroid", "Asteroid_3", {0,0,0,}, 100, 0, 0, 0, 0,}, {100, "addCoordinate", {0,0,0,}, StoreMyCoordsTable,}, {10, "Function", easyPatch, {0,0,0,}, 100,}, {maxPlayers, "StartPoint", "StartPos", {0,0,0,}, {0,0,0,}, 1,}, {100, "Point", "MyPoint", {0,0,0,}, {0,0,0,}, 1,}, } In the example above, "MyDist" is the name of the distribution table. (This name can be changed to be anything you want). Contained within the distribution table are lists of parameters describing the actual map objects that you will use to populate the map. The first parameter in each list specifies the number of objects of that type that will get placed using the map function (e.g., 512 for the "Pebble_0" object). The second parameter in each list specifies the class of object. The remaining parameters in each list correspond to the arguments you would normally use when calling the default function for that type of object. For example, if you were populating a map with an object of class "Asteroid", then the table entries would correspond to the arguments you would normally use with the addAsteroid() function. The exceptions are when declaring an object of class "Coordinate" or "Function". In these cases, the parameter following the class name is a reference to a table or a function, respectively. ================================================================ OBJECT CLASSES There are thirteen classes of objects, at this time: "StartPoint", "Point", "Sphere", "Camera", "Squadron", "Asteroid", "Salvage", "Pebble", "Cloud", "DustCloud", "Nebula", "Coordinate" and "Function". The first eleven classes, except for the "StartPoint" class, all correspond to standard HW2 map objects. The "StartPoint", "Coordinate" and "Function" classes provide you with additional functionality. Additionally, the first five classes take an additional parameter at the end that determines whether these items' names are incremented as they are added. The "StartPoint" class is a special class of object used for creating starting positions. When creating starting positions, the third parameter in the list, after the class name, must always equal "StartPos" (with quotes). The correct number of sequentially numbered starting positions will automatically be created for you. Do make sure that, when generating starting positions using any of these functions, the total number of positions in a .level file is always equal to the value of the "maxPlayers" variable. The "Coordinate" class tells the map function to just store the calculated coordinates into a table that you can retrieve and use later. The name of this table is specified as the third item in the list, after the class name, and must already be initialized before calling the function. In the above example, "StoreMyCoordsTable" (without quotes) is the name of the table that the coordinates will be stored in. The "Function" class allows one to pass the output of one function as the input of another function. This nesting of functions makes it possible to do things like placing spirals at the vertices of a cube. In the example above, the "easyPatch" function is being used as a nested function. The "easyPatch" function is a shortcut that generates ready-made resource patches, featuring typical numbers of asteroids and RUs. It takes some of the labor out of creating resource patches by automatically placing several asteroids and pebbles around the desired location. (Note: When using a function as a parameter, take special care that you enter the name of the function without quotes and without any trailing parentheses. Also, when nesting functions, it is assumed that the very first argument that a nested function will take is a table containing X, Y and Z coordinates; so, if a function does not take XYZ coordinates as its first argument, the function may not work. Lastly, if you are nesting functions, makes sure that the distribution table is declared either at the end of the file, or within the "DetermChunk" portion of the level file, and before any functions are called (the default).) There is also another type of class, the "named item" class, which can be configured to behave slightly differently. "StartPoint", "Point", "Sphere", "Camera" and "Squadron" all take an additional (boolean) parameter at the end that determines whether the names of the objects increment each time the named object is added to the map. local MyDist = { {100, "Point", "MyPoint", {0,0,0,}, {0,0,0,}, 1,}, } In the above example, for instance, the object named "MyPoint" gets added to the map 100 times. Since the last parameter is equal to one (instead of zero), the name gets incremented 100 times. This means the first point will be named "MyPoint1" and any subsequent points will be named "MyPoint2", "MyPoint3" and so on until the hundredth point. If you set the last parameter to equal zero, then the name of each item will simply be "MyPoint" (e.g., without any numbers). Note that the last parameter is actually ignored in the case of the "StartPoint" object, as this behavior is enabled by default. ================================================================ CHANGE LOG CHANGES IN 1.56 • Fixed a bug in "makeRectangle". • More space savings. • The script now checks whether the "getn" and "tinsert" functions already exist before defining them. • Fixed a bug in the "vanglesXY" function. Values returned were the inverse of what they should have been. CHANGES IN 1.55 • Took several measures to reduce the size of the file. • Fixed bug in Boy, Kuen and Klein surfaces. CHANGES IN 1.54 • Fixed bug in "globeAdd" function. • Cloud, DustCloud and Nebula names are now incremented like the other named items if their amounts are greater than one. • Item incrementation is done slightly differently now. The final table entry for named items is no longer necessary. However, an underscore now appears between the name and the incremented number. • Added support for directional lights. • Fixed bug with the "literalAdd" function. • Fixed bugs with "addSobgroup" and "getn" functions. • Added support for Reactive Fleets and Reactive Resources. • Added a new function for adding squadrons to sobgroups that leaves the actual creation of the sobgroups to be done elsewhere. • Fixed possible bug with adding cameras. • Added documentation for each level function to "appendShape". CHANGES IN 1.53 • I introduced a bug in the last version causing all maps not to load. It's fixed now. CHANGES IN 1.52 • Named objects can now be configured to increment their names as they are added. This is in order to resolve issues where two or more items have identical names (a problem in many scripts!). This shouldn't cause errors in levels created with the previous version of this collection, but distribution tables should be updated to follow the new procedures, anyway. As a side note, these functions used to work in sort of the same way in the past. I'm not sure why I eliminated this behavior. CHANGES IN 1.51 • Can't remember. CHANGES IN 1.5 • The shapes generated by the "shapeAdd" function each now possess their own dedicated function. This means that non- random coordinates within most shapes are no longer supported. • Changed the order and position of many functions' arguments. Most functions now take the same number of arguments. • Merged the "shapeAdd" and "shapeAdd2D" functions. • Slight change to how points are positioned around the "Lissajous3D" shape. • Removed the "circumAdd" function. • Added the "Lissajous" curve I forgot to add in the last version. CHANGES IN 1.44 • Added the "Hypotrochoid", "Epitrochoid" and "Lissajous" curves to the "shapeAdd2D" function. • Added the "Lissajous" curve to the "shapeAdd" function. CHANGES IN 1.41 • Fixed a bug in the "tableinsert" function. • Added many new shapes to the "shapeAdd" function. CHANGES IN 1.4 • Fixed a major mistake: distribution tables were being indexed by their class names, potentially resulting in several table entries using the same index. Table entries are now no longer indexed explicitely. (This is the way it worked prior to v1.3.) • Coordinates can now be stored in any arbitrary table when using the "Coordinate" class. The table used to store the coordinates is passed as an argument in the distribution table. • Added the "Function" class. Functions now be nested by naming them in the distribution tables. • The "EasyPatch" class has been deprecated in favor of using the new "Function" class. • Added the "Camera" class. • Moved starting point generation to its own class, called "StartPoint". • Added incremental counters for all classes. • Added the "getlength" and "tableinsert" table manipulation functions. • Added instructions to the documentation. CHANGES IN 1.32 • The initial and ending radii can now be specified for the "splineAdd" function. Thickness is now specified using a different parameter. • Thickness for the "splineAdd" and "branchAdd" functions is now specified using pecentages (of the radius), as opposed to absolute amounts. • Added additional trigonometric functions. CHANGES IN 1.31 • Fixed a bug in the "ringAdd" function. CHANGES IN 1.3 • Major change to how distribution tables are done. Distribution table entries are now indexed by class name. The first value is always the number of objects. All other values correspond to the normal function arguments for that class of object (see the included level file for an example distribution table). Note that class names are case- sensitive. Also note that positions are now stacked -- i.e., an object's position, a shape's position, and any changes made to the position by a shape function are now summed. • Most parameter names have been shortened to four letters to save space. • Added the "Paraboloid", "Hyperboloid", "Astroid", and "Funnel" shapes to the "shapeAdd" function. • The names of the "Helix" and "Torus" shapes have been changed to "Helicoid" and "Toroid". • Fixed some errors in the commenting of the code. • The "Ellipsoid" and "Cuboid" shapes in the "shapeAdd" function, as well as all the shapes in the "shapeAdd2D" function, have been rotated so that their normals now point "upward" instead of "forward". • Fixed a bug in the "branchAdd" function. • The density of branches in the "branchAdd" function now remains constant even if the branches are made hollow. • The parameters for most of the remaining functions have been collapsed into tables. • The beginning and ending values of "t" (time) can now be specified for the "spiralAdd" function. • Removed the array argument functions that were added in v1.13, and replaced them with the "literalAdd" function (see below). • Added the "literalAdd" function. Objects listed in distribution tables can now be placed on the map without any changes being made to their position. • The "Camera" object is no longer supported in distribution tables until I can find a better way of managing them. CHANGES IN 1.2 • "Torus", "Cone" and "Cylinder" in the "shapeAdd" function can now be scaled along all three axes. • The length of the third axis has been doubled to its correct size for "Helix" in the "shapeAdd" function. • The "easyPatch" and "adjustPatch" functions have been merged, preserving their respective syntaxes. • The rotation matrices have been changed due to my having gotton the order of the Z and Y axes mixed up. This is an internal change, and should only affect the output of the "circumAdd" function. • The rotation matrices have been changed to follow the "roll- pitch-yaw" convention (i.e., rotations are done around the Z- axis ("roll") first, then the X-axis ("pitch"), and finally the Y-axis ("yaw")). This also means that objects can now be rotated around all three axes, instead of just two. • Many function arguments have been put into tables, requiring changes to how you call the functions. • More aspects of the "branchAdd" function are now randomized. • A thickness parameter has been added to the "branchAdd" function. Branches can now be made hollow. • The density of each branch produced by the "branchAdd" function now remains constant (unless it is hollow). • The "random" mode of the "branchAdd" function has been much improved cosmetically. • The name of the "mathRound" function has been changed to "round". • Added a bunch of vector functions. • Renamed the "sphereAdd" function to "globeAdd". • The "globeAdd" function now generates longitudinal lines, as well as latitudinal. • The "spiralAdd" function now has an additional height parameter that allows one to optionally spiral upward or downward. • Added the "splineAdd" function. It will connect any two points with a cubic spline, using two additional points as control points. • Added the "shapeAdd2D" function, which adds an assortment of 2D shapes. • Included an example map with the archive. CHANGES IN 1.13 • Added a bunch of array argument functions. • Thickness was fixed for "Ellipsoid" and added for "Cuboid" in the "shapeAdd" function. You can now make hollow or flat balls or boxes. • The lengths of the axes have been doubled to their correct size for "Ellipsoid" and "Cuboid" in the "shapeAdd" function. • You can now enter a value of zero as an argument in a lot of places, where before you couldn't. I've since replaced the random number function with something else [see below...]. • Added the "random2" function. It can accept zero-length intervals as arguments. • You can now use custom backgrounds with the "randomBackground" function. • Fixed a bug in the "circumAdd" function. CHANGES IN 1.12 • The "randomMusic" function can now read a custom list of tracks. CHANGES IN 1.11 • Expanded the "randomMusic" function to include the Homeworld 1 and Homeworld Cataclysm music. [...these have to be modded- in in some way] • Changed thickness to height and width to thickness in the "ringAdd", "sphereAdd", "spiralAdd" and "shapeAdd" functions. • Changed how thickness is measured in the "ringAdd" and "sphereAdd" functions. [...still not sure I have it right] CHANGES IN 1.1 • Added the "circumAdd" function. • Added the "randomBit" function. CHANGES IN 1.0 • Initial release. ================================================================ KNOWN ISSUES • I would prefer that RUs were specified by density (or by relative amount, ala HW1), as well as by absolute amount. [See the "HW1 to HW2 Map Conversion" page at the wiki for an example.] • The elliptical rings are supposed to be widest where the curvature is the least greatest (as if formed of concentric ellipses sharing the same foci). I'm not sure if this is actually happening. • Some maps sometimes crash during online-multiplayer gameplay if less than 6 players are playing and a map function is used to generate the starting positions. This may have something to do with the "startNum" global variable and the "appendShape" function. [What, I don't know.] • The name of the table that coordinates are stored should be specifiable in the distribution tables when an item's class name equals "Coordinate". However, the "tinsert" function lies outside the ".level" scope. [fixed in v1.4.] • The "shape2DAdd" function shoud be merged with the "ringAdd" and "spiralAdd" functions (though the latter have a lot of peculiarities). • Functions should optionally output shapes to tables, instead of adding them to the map, so that they can be iterated over other functions. [fixed in v1.4.] • Should allow the user to input ranges of "t". [fixed for some functions in v1.3.] • Not sure if the way I rotate shapes is compatible with how HW rotates objects. • Things like normal and tangent vectors, as well as Euler rotation angles, should be inheritable among nested functions.