Ticket #2944: gen_wall_builder2015-08-23.diff

File gen_wall_builder2015-08-23.diff, 225.4 KB (added by FeXoR, 9 years ago)

Some functions added and changed coment style

  • binaries/data/mods/public/globalscripts/Templates.js

     
    251251            "templates": {
    252252                "tower": template.WallSet.Templates.Tower,
    253253                "gate": template.WallSet.Templates.Gate,
     254                "fort": template.WallSet.Templates.Fort || "structures/{civ}_fortress",
    254255                "long": template.WallSet.Templates.WallLong,
    255256                "medium": template.WallSet.Templates.WallMedium,
    256257                "short": template.WallSet.Templates.WallShort,
     
    258259            "maxTowerOverlap": +template.WallSet.MaxTowerOverlap,
    259260            "minTowerOverlap": +template.WallSet.MinTowerOverlap,
    260261        };
     262        if (template.WallSet.Templates.WallEnd)
     263            ret.wallSet.templates.end = template.WallSet.Templates.WallEnd;
     264        if (template.WallSet.Templates.WallCurveQuarter)
     265            ret.wallSet.templates.quarterCurve = template.WallSet.Templates.WallCurveQuarter;
     266        if (template.WallSet.Templates.WallCurveEighth)
     267            ret.wallSet.templates.eighthCurve = template.WallSet.Templates.WallCurveEighth;
    261268    }
    262269
    263270    if (template.WallPiece)
    264         ret.wallPiece = {"length": +template.WallPiece.Length};
     271        ret.wallPiece = {
     272            "length": +template.WallPiece.Length,
     273            "angle": +(template.WallPiece.Orientation || 1) * Math.PI,
     274            "indent": +(template.WallPiece.Indent || 0),
     275            "bend": +(template.WallPiece.Bend || 0) * Math.PI,
     276        };
    265277
    266278    return ret;
    267279}
  • binaries/data/mods/public/maps/random/belgian_uplands.js

     
    1 // Prepare progress calculation
     1/**
     2 * Prepare progress calculation
     3 */
    24var timeArray = [];
    35timeArray.push(new Date().getTime());
    46
    5 // Importing rmgen libraries
     7/**
     8 * Importing rmgen libraries
     9 */
    610RMS.LoadLibrary("rmgen");
    711
    812const BUILDING_ANGlE = -PI/4;
    913
    10 // initialize map
    11 
     14/**
     15 * initialize map
     16 */
    1217log("Initializing map...");
    1318
    1419InitMap();
     
    1722var mapSize = getMapSize();
    1823
    1924
    20 //////////
    21 // Heightmap functionality
    22 //////////
     25/**
     26 * Heightmap functionality
     27 */
    2328
    24 // Some general heightmap settings
    25 const MIN_HEIGHT = - SEA_LEVEL; // 20, should be set in the libs!
    26 const MAX_HEIGHT = 0xFFFF/HEIGHT_UNITS_PER_METRE - SEA_LEVEL; // A bit smaler than 90, should be set in the libs!
    27 
    28 // Add random heightmap generation functionality
     29/**
     30 * Add random heightmap generation functionality
     31 */
    2932function getRandomReliefmap(minHeight, maxHeight)
    3033{
    3134    minHeight = (minHeight || MIN_HEIGHT);
     
    3538    if (maxHeight > MAX_HEIGHT)
    3639        warn("getRandomReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight)
    3740    var reliefmap = [];
    38     for (var x = 0; x <= mapSize; x++)
     41    for (var x = 0; x <= mapSize; ++x)
    3942    {
    4043        reliefmap.push([]);
    41         for (var y = 0; y <= mapSize; y++)
     44        for (var y = 0; y <= mapSize; ++y)
    4245        {
    4346            reliefmap[x].push(randFloat(minHeight, maxHeight));
    4447        }
     
    4649    return reliefmap;
    4750}
    4851
    49 // Apply a heightmap
     52/**
     53 * Apply a heightmap
     54 */
    5055function setReliefmap(reliefmap)
    5156{
    5257    // g_Map.height = reliefmap;
    53     for (var x = 0; x <= mapSize; x++)
     58    for (var x = 0; x <= mapSize; ++x)
    5459    {
    55         for (var y = 0; y <= mapSize; y++)
     60        for (var y = 0; y <= mapSize; ++y)
    5661        {
    5762            setHeight(x, y, reliefmap[x][y]);
    5863        }
    5964    }
    6065}
    6166
    62 // Get minimum and maxumum height used in a heightmap
     67/**
     68 * Get minimum and maxumum height used in a heightmap
     69 */
    6370function getMinAndMaxHeight(reliefmap)
    6471{
    6572    var height = {};
    6673    height.min = Infinity;
    6774    height.max = -Infinity;
    68     for (var x = 0; x <= mapSize; x++)
     75    for (var x = 0; x <= mapSize; ++x)
    6976    {
    70         for (var y = 0; y <= mapSize; y++)
     77        for (var y = 0; y <= mapSize; ++y)
    7178        {
    7279            if (reliefmap[x][y] < height.min)
    7380                height.min = reliefmap[x][y];
     
    7885    return height;
    7986}
    8087
    81 // Rescale a heightmap (Waterlevel is not taken into consideration!)
     88/**
     89 * Rescale a heightmap (Waterlevel is not taken into consideration!)
     90 */
    8291function getRescaledReliefmap(reliefmap, minHeight, maxHeight)
    8392{
    8493    var newReliefmap = deepcopy(reliefmap);
     
    8998    if (maxHeight > MAX_HEIGHT)
    9099        warn("getRescaledReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight)
    91100    var oldHeightRange = getMinAndMaxHeight(reliefmap);
    92     for (var x = 0; x <= mapSize; x++)
     101    for (var x = 0; x <= mapSize; ++x)
    93102    {
    94         for (var y = 0; y <= mapSize; y++)
     103        for (var y = 0; y <= mapSize; ++y)
    95104        {
    96105            newReliefmap[x][y] = minHeight + (reliefmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight);
    97106        }
     
    99108    return newReliefmap
    100109}
    101110
    102 // Applying decay errosion (terrain independent)
     111/**
     112 * Applying decay errosion (terrain independent)
     113 */
    103114function getHeightErrosionedReliefmap(reliefmap, strength)
    104115{
    105116    var newReliefmap = deepcopy(reliefmap);
    106117    strength = (strength || 1.0); // Values much higher then 1 (1.32+ for an 8 tile map, 1.45+ for a 12 tile map, 1.62+ @ 20 tile map, 0.99 @ 4 tiles) will result in a resonance disaster/self interference
    107118    var map = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]; // Default
    108     for (var x = 0; x <= mapSize; x++)
     119    for (var x = 0; x <= mapSize; ++x)
    109120    {
    110         for (var y = 0; y <= mapSize; y++)
     121        for (var y = 0; y <= mapSize; ++y)
    111122        {
    112123            var div = 0;
    113             for (var i = 0; i < map.length; i++)
     124            for (var i = 0; i < map.length; ++i)
    114125                newReliefmap[x][y] += strength / map.length * (reliefmap[(x + map[i][0] + mapSize + 1) % (mapSize + 1)][(y + map[i][1] + mapSize + 1) % (mapSize + 1)] - reliefmap[x][y]); // Not entirely sure if scaling with map.length is perfect but tested values seam to indicate it is
    115126        }
    116127    }
     
    118129}
    119130
    120131
    121 //////////
    122 // Prepare for hightmap munipulation
    123 //////////
     132/**
     133 * Prepare for hightmap munipulation
     134 */
    124135
    125 // Set target min and max height depending on map size to make average stepness the same on all map sizes
     136/**
     137 * Set target min and max height depending on map size to make average stepness the same on all map sizes
     138 */
    126139var heightRange = {"min": MIN_HEIGHT * mapSize / 8192, "max": MAX_HEIGHT * mapSize / 8192};
    127140
    128 // Set average water coverage
     141/**
     142 * Set average water coverage
     143 */
    129144var averageWaterCoverage = 1/3; // NOTE: Since errosion is not predictable actual water coverage might differ much with the same value
    130145if (mapSize < 200) // Sink the waterlevel on tiny maps to ensure enough space
    131146    averageWaterCoverage = 2/3 * averageWaterCoverage;
     
    134149setWaterHeight(waterHeight);
    135150
    136151
    137 //////////
    138 // Prepare terrain texture by height placement
    139 //////////
    140 
     152/**
     153 * Prepare terrain texture by height placement
     154 */
    141155var textueByHeight = [];
    142156
    143 // Deep water
     157/**
     158 * Deep water
     159 */
    144160textueByHeight.push({"upperHeightLimit": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_sea_rocks"});
    145 // Medium deep water (with fish)
     161/**
     162 * Medium deep water (with fish)
     163 */
    146164var terreins = ["temp_sea_weed"];
    147165terreins = terreins.concat(terreins, terreins, terreins, terreins);
    148166terreins = terreins.concat(terreins, terreins, terreins, terreins);
    149167terreins.push("temp_sea_weed|gaia/fauna_fish");
    150168textueByHeight.push({"upperHeightLimit": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "terrain": terreins});
    151 // Flat Water
     169/**
     170 * Flat Water
     171 */
    152172textueByHeight.push({"upperHeightLimit": heightRange.min + 3/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_mud_a"});
    153 // Water surroundings/bog (with stone/metal some rabits and bushes)
     173/**
     174 * Water surroundings/bog (with stone/metal some rabits and bushes)
     175 */
    154176var terreins = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"];
    155177terreins = terreins.concat(terreins, terreins, terreins, terreins, terreins);
    156178terreins = ["temp_plants_bog|gaia/flora_bush_temperate"].concat(terreins, terreins);
    157179terreins = ["temp_dirt_gravel_plants|gaia/geology_metal_temperate", "temp_dirt_gravel_plants|gaia/geology_stone_temperate", "temp_plants_bog|gaia/fauna_rabbit"].concat(terreins, terreins);
    158180terreins = ["temp_plants_bog_aut|gaia/flora_tree_dead"].concat(terreins, terreins);
    159181textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 1/6 * (heightRange.max - waterHeightAdjusted), "terrain": terreins});
    160 // Juicy grass near bog
     182/**
     183 * Juicy grass near bog
     184 */
    161185textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 2/6 * (heightRange.max - waterHeightAdjusted),
    162186    "terrain": ["temp_grass", "temp_grass_d", "temp_grass_long_b", "temp_grass_plants"]});
    163 // Medium level grass
    164 // var testActor = "actor|geology/decal_stone_medit_a.xml";
     187/**
     188 * Medium level grass
     189 */
    165190textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 3/6 * (heightRange.max - waterHeightAdjusted),
    166191    "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_mossy"]});
    167 // Long grass near forest border
     192/**
     193 * Long grass near forest border
     194 */
    168195textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 4/6 * (heightRange.max - waterHeightAdjusted),
    169196    "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]});
    170 // Forest border (With wood/food plants/deer/rabits)
     197/**
     198 * Forest border (With wood/food plants/deer/rabits)
     199 */
    171200var terreins = ["temp_grass_plants|gaia/flora_tree_euro_beech", "temp_grass_mossy|gaia/flora_tree_poplar", "temp_grass_mossy|gaia/flora_tree_poplar_lombardy",
    172201    "temp_grass_long|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_badlands",
    173202    "temp_grass_long|gaia/flora_tree_apple", "temp_grass_clovers|gaia/flora_bush_berry", "temp_grass_clovers_2|gaia/flora_bush_grapes",
    174203    "temp_grass_plants|gaia/fauna_deer", "temp_grass_long_b|gaia/fauna_rabbit"];
    175204var numTerreins = terreins.length;
    176 for (var i = 0; i < numTerreins; i++)
     205for (var i = 0; i < numTerreins; ++i)
    177206    terreins.push("temp_grass_plants");
    178207textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 5/6 * (heightRange.max - waterHeightAdjusted), "terrain": terreins});
    179 // Unpassable woods
     208/**
     209 * Unpassable woods
     210 */
    180211textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 6/6 * (heightRange.max - waterHeightAdjusted),
    181212    "terrain": ["temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine",
    182213    "temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine",
     
    184215    "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", "temp_forestfloor_autumn|gaia/flora_tree_carob"]});
    185216var minTerrainDistToBorder = 3;
    186217
    187 // Time check 1
     218/**
     219 * Time check 1
     220 */
    188221timeArray.push(new Date().getTime());
    189222RMS.SetProgress(5);
    190223
    191 
    192 // START THE GIANT WHILE LOOP:
    193 // - Generate Heightmap
    194 // - Search valid start position tiles
    195 // - Choose a good start position derivation (largest distance between closest players)
    196 // - Restart the loop if start positions are invalid or two players are to close to each other
     224/**
     225 * START THE GIANT WHILE LOOP:
     226 * - Generate Heightmap
     227 * - Search valid start position tiles
     228 * - Choose a good start position derivation (largest distance between closest players)
     229 * - Restart the loop if start positions are invalid or two players are to close to each other
     230 */
    197231var goodStartPositionsFound = false;
    198232var minDistBetweenPlayers = 16 + mapSize / 16; // Don't set this higher than 25 for tiny maps! It will take forever with 8 players!
    199233var enoughTiles = false;
    200234var tries = 0;
    201235while (!goodStartPositionsFound)
    202236{
    203     tries++;
     237    ++tries;
    204238    log("Starting giant while loop try " + tries);
    205239    // Generate reliefmap
    206240    var myReliefmap = getRandomReliefmap(heightRange.min, heightRange.max);
    207     for (var i = 0; i < 50 + mapSize/4; i++) // Cycles depend on mapsize (more cycles -> bigger structures)
     241    for (var i = 0; i < 50 + mapSize/4; ++i) // Cycles depend on mapsize (more cycles -> bigger structures)
    208242        myReliefmap = getHeightErrosionedReliefmap(myReliefmap, 1);
    209243    myReliefmap = getRescaledReliefmap(myReliefmap, heightRange.min, heightRange.max);
    210244    setReliefmap(myReliefmap);
     
    217251    var lowerHeightLimit = textueByHeight[3].upperHeightLimit;
    218252    var upperHeightLimit = textueByHeight[6].upperHeightLimit;
    219253    // Check for valid points by height
    220     for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; x++)
     254    for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; ++x)
    221255    {
    222         for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; y++)
     256        for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; ++y)
    223257        {
    224258            var actualHeight = getHeight(x, y);
    225259            if (actualHeight > lowerHeightLimit && actualHeight < upperHeightLimit)
    226260            {
    227261                // Check for points within a valid area by height (rectangular since faster)
    228262                var isPossible = true;
    229                 for (var offX = - neededDistance; offX <= neededDistance; offX++)
     263                for (var offX = - neededDistance; offX <= neededDistance; ++offX)
    230264                {
    231                     for (var offY = - neededDistance; offY <= neededDistance; offY++)
     265                    for (var offY = - neededDistance; offY <= neededDistance; ++offY)
    232266                    {
    233267                        var testHeight = getHeight(x + offX, y + offY);
    234268                        if (testHeight <= lowerHeightLimit || testHeight >= upperHeightLimit)
     
    252286    // Reduce to tiles in a circle of mapSize / 2 distance to the center (to avoid players placed in corners)
    253287    var possibleStartPositionsTemp = [];
    254288    var maxDistToCenter = mapSize / 2;
    255     for (var i = 0; i < possibleStartPositions.length; i++)
     289    for (var i = 0; i < possibleStartPositions.length; ++i)
    256290    {
    257291        var deltaX = possibleStartPositions[i][0] - mapSize / 2;
    258292        var deltaY = possibleStartPositions[i][1] - mapSize / 2;
     
    270304    var maxDistToResources = distToBorder; // Has to be <= distToBorder!
    271305    var minNumLowTiles = 10;
    272306    var minNumHighTiles = 10;
    273     for (var i = 0; i < possibleStartPositions.length; i++)
     307    for (var i = 0; i < possibleStartPositions.length; ++i)
    274308    {
    275309        var numLowTiles = 0;
    276310        var numHighTiles = 0;
    277         for (var dx = - maxDistToResources; dx < maxDistToResources; dx++)
     311        for (var dx = - maxDistToResources; dx < maxDistToResources; ++dx)
    278312        {
    279             for (var dy = - maxDistToResources; dy < maxDistToResources; dy++)
     313            for (var dy = - maxDistToResources; dy < maxDistToResources; ++dy)
    280314            {
    281315                var testHeight = getHeight(possibleStartPositions[i][0] + dx, possibleStartPositions[i][1] + dy);
    282316                if (testHeight < lowerHeightLimit)
    283                     numLowTiles++;
     317                    ++numLowTiles;
    284318                if (testHeight > upperHeightLimit)
    285                     numHighTiles++;
     319                    ++numHighTiles;
    286320                if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles)
    287321                    break;
    288322            }
     
    311345        // Get some random start location derivations. NOTE: Itterating over all possible derivations is just to much (valid points ** numPlayers)
    312346        var maxTries = 100000; // floor(800000 / (Math.pow(numPlayers, 2) / 2));
    313347        var possibleDerivations = [];
    314         for (var i = 0; i < maxTries; i++)
     348        for (var i = 0; i < maxTries; ++i)
    315349        {
    316350            var vector = [];
    317             for (var p = 0; p < numPlayers; p++)
     351            for (var p = 0; p < numPlayers; ++p)
    318352                vector.push(randInt(possibleStartPositions.length));
    319353            possibleDerivations.push(vector);
    320354        }
    321355       
    322356        // Choose the start location derivation with the greatest minimum distance between players
    323357        var maxMinDist = 0;
    324         for (var d = 0; d < possibleDerivations.length; d++)
     358        for (var d = 0; d < possibleDerivations.length; ++d)
    325359        {
    326360            var minDist = 2 * mapSize;
    327             for (var p1 = 0; p1 < numPlayers - 1; p1++)
     361            for (var p1 = 0; p1 < numPlayers - 1; ++p1)
    328362            {
    329                 for (var p2 = p1 + 1; p2 < numPlayers; p2++)
     363                for (var p2 = p1 + 1; p2 < numPlayers; ++p2)
    330364                {
    331365                    if (p1 != p2)
    332366                    {
     
    358392    } // End of derivation check
    359393} // END THE GIANT WHILE LOOP
    360394
    361 // Time check 2
     395/**
     396 * Time check 2
     397 */
    362398timeArray.push(new Date().getTime());
    363399RMS.SetProgress(60);
    364400
    365401
    366 ////////
    367 // Paint terrain by height and add props
    368 ////////
     402/**
     403 * Paint terrain by height and add props
     404 */
    369405
    370406var propDensity = 1; // 1 means as determined in the loop, less for large maps as set below
    371407if (mapSize > 500)
    372408    propDensity = 1/4;
    373409else if (mapSize > 400)
    374410    propDensity = 3/4;
    375 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++)
     411for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; ++x)
    376412{
    377     for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; y++)
     413    for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; ++y)
    378414    {
    379415        var textureMinHeight = heightRange.min;
    380         for (var i = 0; i < textueByHeight.length; i++)
     416        for (var i = 0; i < textueByHeight.length; ++i)
    381417        {
    382418            if (getHeight(x, y) >= textureMinHeight && getHeight(x, y) <= textueByHeight[i].upperHeightLimit)
    383419            {
     
    488524    }
    489525}
    490526
    491 // Time check 3
     527/**
     528 * Time check 3
     529 */
    492530timeArray.push(new Date().getTime());
    493531RMS.SetProgress(90);
    494532
    495533
    496 ////////
    497 // Place players and start resources
    498 ////////
     534/**
     535 * Place players and start resources
     536 */
    499537
    500 for (var p = 0; p < numPlayers; p++)
     538for (var p = 0; p < numPlayers; ++p)
    501539{
    502540    var actualX = possibleStartPositions[bestDerivation[p]][0];
    503541    var actualY = possibleStartPositions[bestDerivation[p]][1];
     
    509547    {
    510548        var uAngle = BUILDING_ANGlE - PI * (2-j) / 2;
    511549        var count = 4;
    512         for (var numberofentities = 0; numberofentities < count; numberofentities++)
     550        for (var numberofentities = 0; numberofentities < count; ++numberofentities)
    513551        {
    514552            var ux = actualX + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
    515553            var uz = actualY + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
     
    521559    }
    522560}
    523561
    524 
    525 // Export map data
     562/**
     563 * Export map data
     564 */
    526565ExportMap();
    527566
    528 // Time check 7
     567/**
     568 * Time check 7
     569 */
    529570timeArray.push(new Date().getTime());
    530571
    531 // Calculate progress percentage with the time checks
     572/**
     573 * Calculate progress percentage with the time checks
     574 */
    532575var generationTime = timeArray[timeArray.length - 1] - timeArray[0];
    533576log("Total generation time (ms): " + generationTime);
    534 for (var i = 0; i < timeArray.length; i++)
     577for (var i = 0; i < timeArray.length; ++i)
    535578{
    536579    var timeSinceStart = timeArray[i] - timeArray[0];
    537580    var progressPercentage = 100 * timeSinceStart / generationTime;
  • binaries/data/mods/public/maps/random/rmgen/library.js

     
    1 
    2 /////////////////////////////////////////////////////////////////////////////////////////////
    3 //  Constant definitions
    4 /////////////////////////////////////////////////////////////////////////////////////////////
    5 
     1/**
     2 * Constant definitions
     3 */
    64const PI = Math.PI;
    7 const TWO_PI = 2 * Math.PI;
     5const TWO_PI = 2 * Math.PI; // mathematically known as 'tau'
    86const TERRAIN_SEPARATOR = "|";
    9 const SEA_LEVEL = 20.0;
     7const SEA_LEVEL = 160.0;
    108const CELL_SIZE = 4;
    119const HEIGHT_UNITS_PER_METRE = 92;
    1210const MIN_MAP_SIZE = 128;
    1311const MAX_MAP_SIZE = 512;
    1412const FALLBACK_CIV = "athen";
    1513
    16 /////////////////////////////////////////////////////////////////////////////////////////////
    17 //  Utility functions
    18 /////////////////////////////////////////////////////////////////////////////////////////////
     14/**
     15 * Constants needed for heightmap_manipulation.js
     16 */
     17const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE // Engine limit, Roughly 700 meters
     18const MIN_HEIGHT = - SEA_LEVEL;
     19const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL;
     20/**
     21 * Entity template structure keys that might change, for easier mod support
     22 */
     23const CIV_PLACEHOLDER_STRING = "{civ}";
     24const START_ENTITY_KEYS = ["StartEntities"];
     25const START_ENTITY_TEMPLATE_KEYS = ["Template"];
     26const BUILDER_TEMPLATEPATH_KEYS = ["Builder", "Entities", "_string"];
     27const PRODUCTION_TEMPLATEPATH_KEYS = ["ProductionQueue", "Entities", "_string"];
     28const WALLSET_KEYS = ["WallSet"];
     29const BUILDING_KEYS = ["Obstruction", "Static"];
    1930
     31
     32/**
     33 * Utility functions
     34 */
     35
    2036function fractionToTiles(f)
    2137{
    2238    return getMapSize() * f;
     
    103119    if (numArgs != 1)
    104120    {
    105121        var ret = new Array(numArgs);
    106         for (var i=0; i < numArgs; i++)
     122        for (var i=0; i < numArgs; ++i)
    107123        {
    108124            ret[i] = x[i];
    109125        }
     
    125141    return ar[randInt(ar.length)];
    126142}
    127143
    128 // "Inside-out" implementation of Fisher-Yates shuffle
     144/**
     145 * "Inside-out" implementation of Fisher-Yates shuffle
     146 */
    129147function shuffleArray(source)
    130148{
    131149    if (!source.length)
    132150        return [];
    133151
    134152    var result = [source[0]];
    135     for (var i = 1; i < source.length; i++)
     153    for (var i = 1; i < source.length; ++i)
    136154    {
    137155        var j = randInt(0, i);
    138156        result[i] = result[j];
     
    172190        var area = g_Map.createArea(centeredPlacer, painter, constraint);
    173191        if (area !== undefined)
    174192        {
    175             good++;
     193            ++good;
    176194            result.push(area);
    177195        }
    178196        else
    179197        {
    180             bad++;
     198            ++bad;
    181199        }
    182200    }
    183201    return result;
     
    208226        var area = g_Map.createArea(centeredPlacer, painter, constraint);
    209227        if (area !== undefined)
    210228        {
    211             good++;
     229            ++good;
    212230            result.push(area);
    213231        }
    214232        else
    215233        {
    216             bad++;
     234            ++bad;
    217235        }
    218236    }
    219237    return result;
     
    248266        var result = createObjectGroup(placer, player, constraint);
    249267        if (result !== undefined)
    250268        {
    251             good++;
     269            ++good;
    252270        }
    253271        else
    254272        {
    255             bad++;
     273            ++bad;
    256274        }
    257275    }
    258276    return good;
     
    282300        var result = createObjectGroup(placer, player, constraint);
    283301        if (result !== undefined)
    284302        {
    285             good++;
     303            ++good;
    286304        }
    287305        else
    288306        {
    289             bad++;
     307            ++bad;
    290308        }
    291309    }
    292310    return good;
     
    349367    return (g_MapSettings.CircularMap ? true : false);
    350368}
    351369
    352 /////////////////////////////////////////////////////////////////////////////////////////////
    353 //  Access global map variable
    354 /////////////////////////////////////////////////////////////////////////////////////////////
     370/**
     371 * Access global map variable
     372 */
    355373
    356374function createTileClass()
    357375{
     
    394412    return g_MapSettings.PlayerData.length - 1;
    395413}
    396414
     415/**
     416 * Takes nothing, returns an array of strings representing all available civilizations
     417 */
     418function getCivList()
     419{
     420    var raw_civData = RMS.GetCivData();
     421    var civList = [];
     422    for (var i = 0; i < raw_civData.length; ++i)
     423        civList.push(JSON.parse(raw_civData[i]).Code);
     424   
     425    return civList;
     426}
     427
     428/**
     429 * Takes nothing, returns an associative array with civ strings as keys containing all unpacked civ data (Templates need to be unpacked with RMS.GetTemplate() if needed)
     430 */
     431function getFullCivData()
     432{
     433    var rawCivData = RMS.GetCivData();
     434    var unpackedCivData = {};
     435    for (var i = 0; i < rawCivData.length; ++i)
     436    {
     437        var singleCivData = JSON.parse(rawCivData[i]);
     438        unpackedCivData[singleCivData.Code] = singleCivData;
     439    }
     440   
     441    return unpackedCivData;
     442}
     443
     444/**
     445 * Takes a player number (0-7, so Gaia excluded). Returns this players civ string
     446 * ToDo: If the player number is to high an error will occur (and the fallback won't be reached)!
     447 */
    397448function getCivCode(player)
    398449{
    399450    if (g_MapSettings.PlayerData[player+1].Civ)
    400451        return g_MapSettings.PlayerData[player+1].Civ;
    401452
    402     warn("undefined civ specified for player " + (player + 1) + ", falling back to '" + FALLBACK_CIV + "'");
     453    warn("Undefined civ specified for player " + (player + 1) + ", falling back to '" + FALLBACK_CIV + "'");
    403454    return FALLBACK_CIV;
    404455}
    405456
     457/**
     458 * Takes an entity path and a key list to get the templates value
     459 */
     460function getTemplateValue(entPath, key_list)
     461{
     462    var subdata = RMS.GetTemplate(entPath);
     463    for (var i = 0; i < key_list.length; ++i)
     464    {
     465        if (!subdata[key_list[i]])
     466            {return false};
     467        subdata = subdata[key_list[i]];
     468    }
     469    return subdata;
     470}
     471
     472/**
     473 * Returns a list of all templates paths available to the given civ
     474 */
     475function getTempatePathList(civ)
     476{
     477    var templatePaths = getFullCivData();
     478    if (!templatePaths[civ])
     479    {
     480        warn("getTempatePathList: Unknown civ '" + civ + "' not in " + Object.keys(templatePaths));
     481        return false;
     482    }
     483    templatePaths = templatePaths[civ];
     484   
     485    if (!templatePaths[START_ENTITY_KEYS])
     486    {
     487        warn("getTempatePathList: Civ has no starting entities as defined in START_ENTITY_KEYS (" + START_ENTITY_KEYS + "): " + Object.keys(templatePaths));
     488        return false;
     489    }
     490    templatePaths = templatePaths[START_ENTITY_KEYS];
     491   
     492    for (var i = 0; i < templatePaths.length; ++i)
     493    {
     494        if (!templatePaths[i][START_ENTITY_TEMPLATE_KEYS])
     495        {
     496            warn("getTempatePathList: Starting entity list item has no template as defined in START_ENTITY_TEMPLATE_KEYS (" + START_ENTITY_TEMPLATE_KEYS + "): " + Object.keys(templatePaths));
     497            return false;
     498        }
     499        templatePaths[i] = templatePaths[i][START_ENTITY_TEMPLATE_KEYS];
     500    }
     501    var foundNew = 1;
     502    while (foundNew > 0)
     503    {
     504        foundNew = 0;
     505        var methods = [BUILDER_TEMPLATEPATH_KEYS, PRODUCTION_TEMPLATEPATH_KEYS];
     506        for (var m = 0; m < methods.length; ++m)
     507        {
     508            for (var t = 0; t < templatePaths.length; ++t)
     509            {
     510                var pathsToCheck = getTemplateValue(templatePaths[t], methods[m]);
     511                if (typeof(pathsToCheck) === typeof(""))
     512                {
     513                    pathsToCheck = pathsToCheck.split(/\s+/);
     514                    for (var c = 0; c < pathsToCheck.length; ++c)
     515                    {
     516                        var actualPath = pathsToCheck[c].replace(CIV_PLACEHOLDER_STRING, civ);
     517                        if (templatePaths.indexOf(actualPath) == -1 && RMS.TemplateExists(actualPath))
     518                        {
     519                            templatePaths.push(actualPath);
     520                            ++foundNew;
     521                        }
     522                    }
     523                }
     524            }
     525        }
     526    }
     527    return templatePaths;
     528}
     529
     530/**
     531 * Takes a list of entity path strings and returns a list with only those remaining that have the specified keys
     532 */
     533function filterByKeys(entPaths, keys)
     534{
     535    let filteredEntPaths = [];
     536    for (let i = 0; i < entPaths.length; ++i)
     537    {
     538        if (getTemplateValue(entPaths[i], keys))
     539            filteredEntPaths.push(entPaths[i]);
     540    }
     541    return filteredEntPaths;
     542}
     543
    406544function areAllies(player1, player2)
    407545{
    408546    if ((g_MapSettings.PlayerData[player1+1].Team === undefined) || (g_MapSettings.PlayerData[player2+1].Team === undefined) || (g_MapSettings.PlayerData[player2+1].Team == -1) || (g_MapSettings.PlayerData[player1+1].Team == -1))
     
    434572
    435573    var result = new Array(0);
    436574    var team = new Array(5);
    437     for (var q = 0; q < 5; q++)
     575    for (var q = 0; q < 5; ++q)
    438576    {
    439577        team[q] = new Array(1);
    440578    }
    441579
    442     for (var i = -1; i < 4; i++)
     580    for (var i = -1; i < 4; ++i)
    443581    {
    444         for (var j = 0; j < source.length; j++)
     582        for (var j = 0; j < source.length; ++j)
    445583        {
    446584            if (getPlayerTeam(j) == i)
    447585            {
     
    461599
    462600    var prime = new Array(source.length);
    463601
    464     for (var i = 0; i < round(source.length/2); i++)
     602    for (var i = 0; i < round(source.length/2); ++i)
    465603    {
    466604        prime[2*i]=source[i];
    467605        prime[2*i+1]=source[source.length-1-i];
     
    492630    g_Map.setHeight(x, z, height);
    493631}
    494632
    495 /////////////////////////////////////////////////////////////////////////////////////////////
    496 //  Utility functions for classes
    497 /////////////////////////////////////////////////////////////////////////////////////////////
    498633
     634/**
     635 *  Utility functions for classes
     636 */
    499637
    500 // Add point to given class by id
     638/**
     639 * Add point to given class by id
     640 */
    501641function addToClass(x, z, id)
    502642{
    503643    var tileClass = getTileClass(id);
     
    508648    }
    509649}
    510650
    511 // Remove point from the given class by id
     651/**
     652 * Remove point from the given class by id
     653 */
    512654function removeFromClass(x, z, id)
    513655{
    514656    var tileClass = getTileClass(id);
     
    519661    }
    520662}
    521663
    522 // Create a painter for the given class
     664/**
     665 * Create a painter for the given class
     666 */
    523667function paintClass(id)
    524668{
    525669    return new TileClassPainter(getTileClass(id));
    526670}
    527671
    528 // Create a painter for the given class
     672/**
     673 * Create a painter for the given class
     674 */
    529675function unPaintClass(id)
    530676{
    531677    return new TileClassUnPainter(getTileClass(id));
    532678}
    533679
    534 // Create an avoid constraint for the given classes by the given distances
     680/**
     681 * Create an avoid constraint for the given classes by the given distances
     682 */
    535683function avoidClasses(/*class1, dist1, class2, dist2, etc*/)
    536684{
    537685    var ar = new Array(arguments.length/2);
    538     for (var i = 0; i < arguments.length/2; i++)
     686    for (var i = 0; i < arguments.length/2; ++i)
    539687    {
    540688        ar[i] = new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1]);
    541689    }
     
    551699    }
    552700}
    553701
    554 // Create a stay constraint for the given classes by the given distances
     702/**
     703 * Create a stay constraint for the given classes by the given distances
     704 */
    555705function stayClasses(/*class1, dist1, class2, dist2, etc*/)
    556706{
    557707    var ar = new Array(arguments.length/2);
    558     for (var i = 0; i < arguments.length/2; i++)
     708    for (var i = 0; i < arguments.length/2; ++i)
    559709    {
    560710        ar[i] = new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1]);
    561711    }
     
    571721    }
    572722}
    573723
    574 // Create a border constraint for the given classes by the given distances
     724/**
     725 * Create a border constraint for the given classes by the given distances
     726 */
    575727function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/)
    576728{
    577729    var ar = new Array(arguments.length/3);
    578     for (var i = 0; i < arguments.length/3; i++)
     730    for (var i = 0; i < arguments.length/3; ++i)
    579731    {
    580732        ar[i] = new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2]);
    581733    }
     
    591743    }
    592744}
    593745
    594 // Checks if the given tile is in class "id"
     746/**
     747 * Checks if the given tile is in class "id"
     748 */
    595749function checkIfInClass(x, z, id)
    596750{
    597751    var tileClass = getTileClass(id);
     
    612766    }
    613767}
    614768
    615 
    616 // Returns the distance between 2 points
     769/**
     770 * Returns the distance between 2 points
     771 */
    617772function getDistance(x1, z1, x2, z2)
    618773{
    619774    return Math.pow(Math.pow(x1 - x2, 2) + Math.pow(z1 - z2, 2), 1/2);
    620775}
    621776
    622 // Returns the angle of the vector between point 1 and point 2.  The angle is anticlockwise from the positive x axis.
     777/**
     778 * Returns the angle of the vector between point 1 and point 2.  The angle is anticlockwise from the positive x axis.
     779 */
    623780function getAngle(x1, z1, x2, z2)
    624781{
    625782    return Math.atan2(z2 - z1, x2 - x1);
    626783}
    627784
    628 // Returns the gradient of the line between point 1 and 2 in the form dz/dx
     785/**
     786 * Returns the gradient of the line between point 1 and 2 in the form dz/dx
     787 */
    629788function getGradient(x1, z1, x2, z2)
    630789{
    631790    if (x1 == x2 && z1 == z2)
     
    642801{
    643802    return g_Map.getTexture(x, y);
    644803}
    645 
  • binaries/data/mods/public/maps/random/rmgen/misc.js

     
    1 /////////////////////////////////////////////////////////////////////////////////////////
    2 //  passageMaker
    3 //
    4 //  Function for creating shallow water between two given points by changing the heiight of all tiles in
    5 //  the path with height less than or equal to "maxheight" to "height"
    6 //
    7 //  x1,z1:  Starting point of path
    8 //  x2,z2:  Ending point of path
    9 //  width:  Width of the shallow
    10 //  maxheight:      Maximum height that it changes
    11 //  height:     Height of the shallow
    12 //  smooth:     smooth elevation in borders
    13 //  tileclass:      (Optianal) - Adds those tiles to the class given
    14 //  terrain:        (Optional) - Changes the texture of the elevated land
    15 //
    16 /////////////////////////////////////////////////////////////////////////////////////////
    17 
     1/**
     2 *  passageMaker
     3 *
     4 *  Function for creating shallow water between two given points by changing the heiight of all tiles in
     5 *  the path with height less than or equal to "maxheight" to "height"
     6 *
     7 *  x1,z1:  Starting point of path
     8 *  x2,z2:  Ending point of path
     9 *  width:  Width of the shallow
     10 *  maxheight:      Maximum height that it changes
     11 *  height:     Height of the shallow
     12 *  smooth:     smooth elevation in borders
     13 *  tileclass:      (Optianal) - Adds those tiles to the class given
     14 *  terrain:        (Optional) - Changes the texture of the elevated land
     15 */
    1816function passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain, riverheight)
    1917{
    2018    var tchm = TILE_CENTERED_HEIGHT_MAP;
    2119    TILE_CENTERED_HEIGHT_MAP = true;
    2220    var mapSize = g_Map.size;
    23     for (var ix = 0; ix < mapSize; ix++)
     21    for (var ix = 0; ix < mapSize; ++ix)
    2422    {
    25         for (var iz = 0; iz < mapSize; iz++)
     23        for (var iz = 0; iz < mapSize; ++iz)
    2624        {
    2725            var a = z1-z2;
    2826            var b = x2-x1;
     
    7371    TILE_CENTERED_HEIGHT_MAP = tchm;
    7472}
    7573
    76 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    77 //rndRiver is a fuction that creates random values useful for making a jagged river.
    78 //
    79 //it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi
    80 //it needs the "seed" parameter to use it to make random curves that don't get broken.
    81 //seed must be created using randFloat(). or else it won't work
    82 //
    83 //  f:  Input: Same as angle in a sine function
    84 //  seed:   Random Seed: Best to implement is to use randFloat()
    85 //
    86 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    87 
     74/**
     75 *rndRiver is a fuction that creates random values useful for making a jagged river.
     76 *
     77 *it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi
     78 *it needs the "seed" parameter to use it to make random curves that don't get broken.
     79 *seed must be created using randFloat(). or else it won't work
     80 *
     81 *  f:  Input: Same as angle in a sine function
     82 *  seed:   Random Seed: Best to implement is to use randFloat()
     83 */
    8884function rndRiver(f, seed)
    8985{
    9086    var rndRq = seed;
     
    9288    var rndRe = 0;
    9389    var rndRr = f-floor(f);
    9490    var rndRa = 0;
    95     for (var rndRx=0; rndRx<=floor(f); rndRx++)
     91    for (var rndRx=0; rndRx<=floor(f); ++rndRx)
    9692    {
    9793        rndRw = 10*(rndRw-floor(rndRw));
    9894    }
     
    129125}
    130126
    131127
    132 /////////////////////////////////////////////////////////////////////////////////////////
    133 // createStartingPlayerEntities
    134 //
    135 //  Creates the starting player entities
    136 //  fx&fz: position of player base
    137 //  playerid: id of player
    138 //  civEntities: use getStartingEntities(id-1) fo this one
    139 //  BUILDING_ANGlE: angle of main base building
    140 //
    141 ///////////////////////////////////////////////////////////////////////////////////////////
     128/**
     129 * createStartingPlayerEntities
     130 *
     131 *  Creates the starting player entities
     132 *  fx&fz: position of player base
     133 *  playerid: id of player
     134 *  civEntities: use getStartingEntities(id-1) fo this one
     135 *  BUILDING_ANGlE: angle of main base building
     136 */
    142137function createStartingPlayerEntities(fx, fz, playerid, civEntities, BUILDING_ANGlE)
    143138{
    144139    var uDist = 6;
     
    148143    {
    149144        var uAngle = BUILDING_ANGlE - PI * (2-j) / 2;
    150145        var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1);
    151         for (var numberofentities = 0; numberofentities < count; numberofentities++)
     146        for (var numberofentities = 0; numberofentities < count; ++numberofentities)
    152147        {
    153148            var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
    154149            var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
     
    157152    }
    158153}
    159154
    160 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    161 // placeCivDefaultEntities
    162 //
    163 //  Creates the default starting player entities depending on the players civ
    164 //  fx&fy: position of player base
    165 //  playerid: id of player
    166 //  angle: angle of main base building, optional, default is BUILDING_ANGlE
    167 //  kwargs: Takes some optional keyword arguments to tweek things
    168 //      'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus
    169 //
    170 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     155/**
     156 * placeCivDefaultEntities
     157 *
     158 *  Creates the default starting player entities depending on the players civ
     159 *  fx&fy: position of player base
     160 *  playerid: id of player
     161 *  angle: angle of main base building, optional, default is BUILDING_ANGlE
     162 *  kwargs: Optional. Takes an associative array with keyword arguments to tweak things:
     163 *      Known keys: 'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus
     164 */
    171165function placeCivDefaultEntities(fx, fz, playerid, angle, kwargs)
    172166{
    173167    // Unpack kwargs
     
    187181    {
    188182        var uAngle = angle - PI * (2-j) / 2;
    189183        var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1);
    190         for (var numberofentities = 0; numberofentities < count; numberofentities++)
     184        for (var numberofentities = 0; numberofentities < count; ++numberofentities)
    191185        {
    192186            var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
    193187            var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
     
    205199}
    206200
    207201
    208 /////////////////////////////////////////////////////////////////////////////////////////
    209 // paintTerrainBasedOnHeight
    210 //
    211 //  paints the tiles which have a height between minheight and maxheight with the given terrain
    212 //  minheight: minimum height of the tile
    213 //  maxheight: maximum height of the tile
    214 //  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
    215 //  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
    216 //  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
    217 //  terrain: intended terrain texture
    218 //
    219 ///////////////////////////////////////////////////////////////////////////////////////////
     202/**
     203 * paintTerrainBasedOnHeight
     204 *
     205 *  paints the tiles which have a height between minheight and maxheight with the given terrain
     206 *  minheight: minimum height of the tile
     207 *  maxheight: maximum height of the tile
     208 *  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
     209 *  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
     210 *  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
     211 *  terrain: intended terrain texture
     212 */
    220213
    221214function paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain)
    222215{
    223216    var mSize = g_Map.size;
    224     for (var qx = 0; qx < mSize; qx++)
     217    for (var qx = 0; qx < mSize; ++qx)
    225218    {
    226         for (var qz = 0; qz < mSize; qz++)
     219        for (var qz = 0; qz < mSize; ++qz)
    227220        {
    228221            if (mode == 0)
    229222            {
     
    257250    }
    258251}
    259252
    260 /////////////////////////////////////////////////////////////////////////////////////////
    261 // paintTileClassBasedOnHeight and unPaintTileClassBasedOnHeight
    262 //
    263 //  paints or unpaints the tiles which have a height between minheight and maxheight with the given tile class
    264 //  minheight: minimum height of the tile
    265 //  maxheight: maximum height of the tile
    266 //  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
    267 //  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
    268 //  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
    269 //  tileclass: intended tile class
    270 //
    271 ///////////////////////////////////////////////////////////////////////////////////////////
    272 
     253/**
     254 * paintTileClassBasedOnHeight and unPaintTileClassBasedOnHeight
     255 *
     256 *  paints or unpaints the tiles which have a height between minheight and maxheight with the given tile class
     257 *  minheight: minimum height of the tile
     258 *  maxheight: maximum height of the tile
     259 *  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
     260 *  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
     261 *  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
     262 *  tileclass: intended tile class
     263 */
    273264function paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass)
    274265{
    275266    var mSize = g_Map.size;
    276     for (var qx = 0; qx < mSize; qx++)
     267    for (var qx = 0; qx < mSize; ++qx)
    277268    {
    278         for (var qz = 0; qz < mSize; qz++)
     269        for (var qz = 0; qz < mSize; ++qz)
    279270        {
    280271            if (mode == 0)
    281272            {
     
    313304function unPaintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass)
    314305{
    315306    var mSize = g_Map.size;
    316     for (var qx = 0; qx < mSize; qx++)
     307    for (var qx = 0; qx < mSize; ++qx)
    317308    {
    318         for (var qz = 0; qz < mSize; qz++)
     309        for (var qz = 0; qz < mSize; ++qz)
    319310        {
    320311            if (mode == 0)
    321312            {
     
    349340    }
    350341}
    351342
    352 /////////////////////////////////////////////////////////////////////////////////////////
    353 // getTIPIADBON
    354 //
    355 //  "get The Intended Point In A Direction Based On Height"
    356 //  gets the N'th point with a specific height in a line and returns it as a [x, y] array
    357 //  startPoint: [x, y] array defining the start point
    358 //  endPoint: [x, y] array defining the ending point
    359 //  heightRange: [min, max] array defining the range which the height of the intended point can be. includes both "min" and "max"
    360 //  step: how much tile units per turn should the search go. more value means faster but less accurate
    361 //  n: how many points to skip before ending the search. skips """n-1 points""".
    362 //
    363 ///////////////////////////////////////////////////////////////////////////////////////////
    364 
     343/**
     344 * getTIPIADBON
     345 *
     346 *  "get The Intended Point In A Direction Based On Height"
     347 *  gets the N'th point with a specific height in a line and returns it as a [x, y] array
     348 *  startPoint: [x, y] array defining the start point
     349 *  endPoint: [x, y] array defining the ending point
     350 *  heightRange: [min, max] array defining the range which the height of the intended point can be. includes both "min" and "max"
     351 *  step: how much tile units per turn should the search go. more value means faster but less accurate
     352 *  n: how many points to skip before ending the search. skips """n-1 points""".
     353 */
    365354function getTIPIADBON(startPoint, endPoint, heightRange, step, n)
    366355{
    367356    var stepX = step*(endPoint[0]-startPoint[0])/(sqrt((endPoint[0]-startPoint[0])*(endPoint[0]-startPoint[0]) + step*(endPoint[1]-startPoint[1])*(endPoint[1]-startPoint[1])));
     
    394383    return undefined;
    395384}
    396385
    397 /////////////////////////////////////////////////////////////////////////////////////////
    398 // doIntersect
    399 //
    400 //  determines if two lines with the width "width" intersect or collide with each other
    401 //  x1, y1, x2, y2: determine the position of the first line
    402 //  x3, y3, x4, y4: determine the position of the second line
    403 //  width: determines the width of the lines
    404 //
    405 ///////////////////////////////////////////////////////////////////////////////////////////
    406 
     386/**
     387 * doIntersect
     388 *
     389 *  determines if two lines with the width "width" intersect or collide with each other
     390 *  x1, y1, x2, y2: determine the position of the first line
     391 *  x3, y3, x4, y4: determine the position of the second line
     392 *  width: determines the width of the lines
     393 */
    407394function checkIfIntersect (x1, y1, x2, y2, x3, y3, x4, y4, width)
    408395{
    409396    if (x1 == x2)
     
    445432    return false;
    446433}
    447434
    448 /////////////////////////////////////////////////////////////////////////////////////////
    449 // distanceOfPointFromLine
    450 //
    451 //  returns the distance of a point from a line
    452 //  x1, y1, x2, y2: determine the position of the line
    453 //  x3, y3: determine the position of the point
    454 //
    455 ///////////////////////////////////////////////////////////////////////////////////////////
    456 
     435/**
     436 * distanceOfPointFromLine
     437 *
     438 *  returns the distance of a point from a line
     439 *  x1, y1, x2, y2: determine the position of the line
     440 *  x3, y3: determine the position of the point
     441 */
    457442function distanceOfPointFromLine (x1, y1, x2, y2, x3, y3)
    458443{
    459444    if (x1 == x2)
     
    473458    }
    474459}
    475460
    476 /////////////////////////////////////////////////////////////////////////////////////////
    477 // createRamp
    478 //
    479 //  creates a ramp from point (x1, y1) to (x2, y2).
    480 //  x1, y1, x2, y2: determine the position of the start and end of the ramp
    481 //  minHeight, maxHeight: determine the height levels of the start and end point
    482 //  width: determines the width of the ramp
    483 //  smoothLevel: determines the smooth level around the edges of the ramp
    484 //  mainTerrain: (Optional) determines the terrain texture for the ramp
    485 //  edgeTerrain: (Optional) determines the terrain texture for the edges
    486 //  tileclass: (Optional) adds the ramp to this tile class
    487 //
    488 ///////////////////////////////////////////////////////////////////////////////////////////
    489 
     461/**
     462 * createRamp
     463 *
     464 *  creates a ramp from point (x1, y1) to (x2, y2).
     465 *  x1, y1, x2, y2: determine the position of the start and end of the ramp
     466 *  minHeight, maxHeight: determine the height levels of the start and end point
     467 *  width: determines the width of the ramp
     468 *  smoothLevel: determines the smooth level around the edges of the ramp
     469 *  mainTerrain: (Optional) determines the terrain texture for the ramp
     470 *  edgeTerrain: (Optional) determines the terrain texture for the edges
     471 *  tileclass: (Optional) adds the ramp to this tile class
     472 */
    490473function createRamp (x1, y1, x2, y2, minHeight, maxHeight, width, smoothLevel, mainTerrain, edgeTerrain, tileclass)
    491474{
    492475    var halfWidth = width / 2;
     
    540523    }
    541524}
    542525
    543 /////////////////////////////////////////////////////////////////////////////////////////
    544 // createMountain
    545 //
    546 //  creates a mountain using a tecnique very similar to chain placer.
    547 //
    548 ///////////////////////////////////////////////////////////////////////////////////////////
     526/**
     527 * createMountain
     528 *
     529 *  creates a mountain using a tecnique very similar to chain placer.
     530 *
     531 */
    549532
    550533function createMountain(maxHeight, minRadius, maxRadius, numCircles, constraint, x, z, terrain, tileclass, fcc, q)
    551534{
     
    617600       
    618601        for (var ix = sx; ix <= lx; ++ix)
    619602        {
    620             for (var iz = sz; iz <= lz; ++ iz)
     603            for (var iz = sz; iz <= lz; ++iz)
    621604            {
    622605                dx = ix - cx;
    623606                dz = iz - cz;
     
    666649       
    667650        for (var ix = sx; ix <= lx; ++ix)
    668651        {
    669             for (var iz = sz; iz <= lz; ++ iz)
     652            for (var iz = sz; iz <= lz; ++iz)
    670653            {
    671654                if (fcc)
    672655                    if ((x - ix) > fcc || (ix - x) > fcc || (z - iz) > fcc || (iz - z) > fcc)
     
    737720       
    738721        for (var ix = sx; ix <= lx; ++ix)
    739722        {
    740             for (var iz = sz; iz <= lz; ++ iz)
     723            for (var iz = sz; iz <= lz; ++iz)
    741724            {
    742725                dx = ix - cx;
    743726                dz = iz - cz;
  • binaries/data/mods/public/maps/random/rmgen/wall_builder.js

     
    1 ////////////////////////////////////////////////////////////////////
    2 // This file contains functionality to place walls on random maps //
    3 ////////////////////////////////////////////////////////////////////
     1/**
     2 * This file contains functionality to place walls on random maps
     3 *
     4 *
     5 * To do:
     6 * Check if all wall placement methods work with wall elements with entity === undefined (some still might raise errors in that case)
     7 * Rename wall elements to fit the entity names so that entity = "structures/" + "civ + "_" + wallElement.type in the common case (as far as possible)
     8 * Perhaps add Roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength
     9 * Perhaps add further wall elements cornerInHalf, cornerOutHalf (banding PI/4) and adjust default fortress types to better fit in the octagonal territory of a civil center
     10 * Perhaps swap angle and width in WallElement class(?) definition
     11 * Adjust argument order to be always the same:
     12 *  Coordinates (center/start/target)
     13 *  Wall element arguments (wall/wallPart/fortressType/cornerElement)
     14 *  playerId (optional, default is 0/gaia)
     15 *  wallStyle (optional, default is the players civ/"palisades for gaia")
     16 *  angle/orientation (optional, default is 0)
     17 *  other (all optional) arguments especially those hard to define (wallPartsAssortment, maybe make an own function for it)
     18 *  Some arguments don't clearly match to this concept:
     19 *      endWithFirst (wall or other)
     20 *      skipFirstWall (wall or other)
     21 *      gateOccurence (wall or other)
     22 *      numCorners (wall or other)
     23 *      skipFirstWall (wall or other)
     24 *      maxAngle (angle or other)
     25 *      maxBendOff (angle or other, unused ATM!!!)
     26 *      irregularity
     27 *      maxTrys
     28 * Add treasures to wall style "others"
     29 * Adjust documentation
     30 * ?Use available civ-type wall elements rather than palisades: Remove "end" as a default wall element and adjust default palisade fortress types?
     31 * ?Adjust generic fortress types palisades?
     32 * ?Think of something to enable splitting walls into two walls so more complex walls can be built?
     33 * ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending?
     34 */
    435
    5 // To do:
    6 // Check if all wall placement methods work with wall elements with entity === undefined (some still might raise errors in that case)
    7 // Rename wall elements to fit the entity names so that entity = "structures/" + "civ + "_" + wallElement.type in the common case (as far as possible)
    8 // Perhaps add Roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength
    9 // Perhaps add further wall elements cornerInHalf, cornerOutHalf (banding PI/4) and adjust default fortress types to better fit in the octagonal territory of a civil center
    10 // Perhaps swap angle and width in WallElement class(?) definition
    11 // Adjust argument order to be always the same:
    12 //  Coordinates (center/start/target)
    13 //  Wall element arguments (wall/wallPart/fortressType/cornerElement)
    14 //  playerId (optional, default is 0/gaia)
    15 //  wallStyle (optional, default is the players civ/"palisades for gaia")
    16 //  angle/orientation (optional, default is 0)
    17 //  other (all optional) arguments especially those hard to define (wallPartsAssortment, maybe make an own function for it)
    18 //  Some arguments don't clearly match to this concept:
    19 //      endWithFirst (wall or other)
    20 //      skipFirstWall (wall or other)
    21 //      gateOccurence (wall or other)
    22 //      numCorners (wall or other)
    23 //      skipFirstWall (wall or other)
    24 //      maxAngle (angle or other)
    25 //      maxBendOff (angle or other, unused ATM!!!)
    26 //      irregularity
    27 //      maxTrys
    28 // Add treasures to wall style "others"
    29 // Adjust documentation
    30 // Perhaps rename "endLeft" to "start" and "endRight" to "end"
    31 // ?Use available civ-type wall elements rather than palisades: Remove "endLeft" and "endRight" as default wall elements and adjust default palisade fortress types?
    32 // ?Remove "endRight", "endLeft" and adjust generic fortress types palisades?
    33 // ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads?
    34 // ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending?
     36/**
     37 * Set some globals for this module
     38 */
     39var g_WallStyles = {};
     40var g_WallStyleList = [];
     41var g_CivData = getFullCivData();
     42var g_CivList = Object.keys(g_CivData);
     43var g_FortressTypes = {};
     44var g_FortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"];
    3545
     46/**
     47 * Basic Initialisation
     48 *
     49 * Fetches wallsets from {civ}.json files, and then uses them to load
     50 * basic wall elements
     51 */
     52for (let civ of g_CivList)
     53{
     54    let civInfo = g_CivData[civ];
     55    if (!civInfo.WallSets)
     56        continue;
    3657
    37 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    38 //  WallElement class definition
    39 //
    40 //  Concept: If placed unrotated the wall's course is towards positive Y (top) with "outside" right (+X) and "inside" left (-X) like unrotated entities has their drop-points right (in rmgen)
    41 //  The course of the wall will be changed by corners (bending != 0) and so the "inside"/"outside" direction
    42 //
    43 //  type    Descriptive string, example: "wallLong". NOTE: Not really needed. Mainly for custom wall elements and to get the wall element type in code
    44 //  entity  Optional. Template name string of the entity to be placed, example: "structures/cart_wall_long". Default is undefined (No entity placed)
    45 //  angle   Optional. The angle (float) added to place the entity so "outside" is right when the wall element is placed unrotated. Default is 0
    46 //  width   Optional. How far this wall element lengthens the wall (float), if unrotated the Y space needed. Default is 0
    47 //  indent  Optional. The lateral indentation of the entity, drawn "inside" (positive values) or pushed "outside" (negative values). Default is 0
    48 //  bending Optional. How the course of the wall is changed after this element, positive is bending "in"/left/counter clockwise (like entity placement)
    49 //      NOTE: Bending is not supported by all placement functions (see there)
    50 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    51 function WallElement(type, entity, angle, width, indent, bending)
    52 {
    53     this.type = type;
    54     // Default wall element type documentation:
    55     // Lengthening straight blocking (mainly left/right symmetric) wall elements (Walls and wall fortifications)
    56         // "wall"          A blocking straight wall element that mainly lengthens the wall, self-explanatory
    57         // "wallShort"     self-explanatory
    58         // "wallLong"      self-explanatory
    59         // "tower"         A blocking straight wall element with damage potential (but for palisades) that slightly lengthens the wall, example: wall tower, palisade tower(No attack)
    60         // "wallFort"      A blocking straight wall element with massive damage potential that lengthens the wall, example: fortress, palisade fort
    61     // Lengthening straight non/custom blocking (mainly left/right symmetric) wall elements (Gates and entries)
    62         // "gate"          A blocking straight wall element with passability determined by owner, example: gate (Functionality not yet implemented)
    63         // "entry"         A non-blocking straight wall element (same width as gate) but without an actual template or just a flag/column/obelisk
    64         // "entryTower"    A non-blocking straight wall element (same width as gate) represented by a single (maybe indented) template, example: defence tower, wall tower, outpost, watchtower
    65         // "entryFort"     A non-blocking straight wall element represented by a single (maybe indented) template, example: fortress, palisade fort
    66     // Bending wall elements (Wall corners)
    67         // "cornerIn"      A wall element bending the wall by PI/2 "inside" (left, +, see above), example: wall tower, palisade curve
    68         // "cornerOut"     A wall element bending the wall by PI/2 "outside" (right, -, see above), example: wall tower, palisade curve
    69         // "cornerHalfIn"  A wall element bending the wall by PI/4 "inside" (left, +, see above), example: wall tower, palisade curve. NOTE: Not yet implemented
    70         // "cornerHalfOut" A wall element bending the wall by PI/4 "outside" (right, -, see above), example: wall tower, palisade curve. NOTE: Not yet implemented
    71     // Zero length straight indented (mainly left/right symmetric) wall elements (Outposts/watchtowers and non-defensive base structures)
    72         // "outpost"       A zero-length wall element without bending far indented so it stands outside the wall, example: outpost, defence tower, watchtower
    73         // "house"         A zero-length wall element without bending far indented so it stands inside the wall that grants population bonus, example: house, hut, longhouse
    74         // "barracks"      A zero-length wall element without bending far indented so it stands inside the wall that grants unit production, example: barracks, tavern, ...
    75     this.entity = entity;
    76     this.angle = (angle !== undefined) ? angle : 0*PI;
    77     this.width = (width !== undefined) ? width : 0;
    78     this.indent = (indent !== undefined) ? indent : 0;
    79     this.bending = (bending !== undefined) ? bending : 0*PI;
     58    for (let path of civInfo.WallSets)
     59    {
     60        let style = path.split("/")[1].split("_");
     61        style = (style[0]=="wallset") ? style[1] : style[0]+"_"+style[2];
     62
     63        if (g_WallStyleList.indexOf(style) == -1)
     64        {
     65            g_WallStyleList.push(style);
     66            g_WallStyles[style] = {};
     67            let wallset = GetTemplateDataHelper(RMS.GetTemplate(path)).wallSet;
     68            for (let element in wallset.templates)
     69                setWallElement(style, element, wallset.templates[element].replace("{civ}",civ))
     70            g_WallStyles[style]["@overlap"] = wallset.minTowerOverlap * getWallElement(style, "tower").length;
     71        }
     72    }
    8073}
    8174
    82 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    83 //  Fortress class definition
    84 //
    85 //  A "fortress" here is a closed wall build of multiple wall elements attached together defined in Fortress.wall
    86 //  It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles)
    87 //
    88 //  type                  Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements
    89 //  wall                  Optional. Array of wall element strings. Can be set afterwards. Default is an epty array.
    90 //      Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"]
    91 //  centerToFirstElement  Optional. Object with properties "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined
    92 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     75/**
     76 *  Fortress class definition
     77 *
     78 *  A "fortress" here is a closed wall build of multiple wall elements attached together defined in Fortress.wall
     79 *  It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles)
     80 *
     81 *  type                  Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements
     82 *  wall                  Optional. Array of wall element strings. Can be set afterwards. Default is an empty array.
     83 *      Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"]
     84 *  centerToFirstElement  Optional. Object with properties "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined
     85 */
    9386function Fortress(type, wall, centerToFirstElement)
    9487{
    95     this.type = type; // Only usefull to get the type of the actual fortress
    96     this.wall = (wall !== undefined) ? wall : [];
    97     this.centerToFirstElement = undefined;
     88    this.type = type;
     89    this.wall = wall || [];
     90    this.centerToFirstElement = centerToFirstElement;
    9891}
    9992
     93/**
     94 *  g_FortressTypes data structure for some default fortress types (defined above)
     95 *
     96 *  A fortress type is just an instance of the Fortress class with actually something in it
     97 *  fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size)
     98 *  Examples: "tiny", "veryLarge"
     99 */
    100100
    101 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    102 //  wallStyles data structure for default wall styles
    103 //
    104 //  A wall style is an associative array with all wall elements of that style in it associated with the wall element type string
    105 //  wallStyles holds all the wall styles within an associative array with the civ string or another descriptive strings as key
    106 //  Examples: "athen", "rome_siege", "palisades", "fence", "road"
    107 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    108 var wallStyles = {};
     101 /**
     102 * Set some default fortress types
     103 */
     104for (let key of g_FortressTypeKeys)
     105    g_FortressTypes[key] = new Fortress(key);
    109106
    110 // Generic civ dependent wall style definition. "rome_siege" needs some tweek...
    111 var wallScaleByType = {"athen" : 1.5, "brit" : 1.5, "cart" : 1.8, "gaul" : 1.5, "iber" : 1.5, "mace" : 1.5, "maur": 1.5, "pers" : 1.5, "ptol" : 1.5, "rome" : 1.5, "sele" : 1.5, "spart" : 1.5, "rome_siege" : 1.5};
    112 for (var style in wallScaleByType)
     107g_FortressTypes["tiny"].wall = ["gate", "tower", "short", "cornerIn", "short", "tower"];
     108g_FortressTypes["small"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "tower"];
     109g_FortressTypes["medium"].wall = ["gate", "tower", "long", "cornerIn", "long", "tower"];
     110g_FortressTypes["normal"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "medium", "cornerIn", "medium", "tower"];
     111g_FortressTypes["large"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"];
     112g_FortressTypes["veryLarge"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "long", "cornerIn", "long", "cornerOut", "medium", "cornerIn", "medium", "tower"];
     113g_FortressTypes["giant"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"];
     114
     115for (let type in g_FortressTypes)
    113116{
    114     var civ = style;
    115     if (style == "rome_siege")
    116         civ = "rome";
    117     wallStyles[style] = {};
    118     // Default wall elements
    119     wallStyles[style]["tower"] = new WallElement("tower", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]);
    120     wallStyles[style]["endLeft"] = new WallElement("endLeft", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
    121     wallStyles[style]["endRight"] = new WallElement("endRight", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
    122     wallStyles[style]["cornerIn"] = new WallElement("cornerIn", "structures/" + style + "_wall_tower", 5*PI/4, 0, 0.35*wallScaleByType[style], PI/2); // 2^0.5 / 4 ~= 0.35 ~= 1/3
    123     wallStyles[style]["cornerOut"] = new WallElement("cornerOut", "structures/" + style + "_wall_tower", 3*PI/4, 0.71*wallScaleByType[style], 0, -PI/2); // // 2^0.5 / 2 ~= 0.71 ~= 2/3
    124     wallStyles[style]["wallShort"] = new WallElement("wallShort", "structures/" + style + "_wall_short", 0*PI, 2*wallScaleByType[style]);
    125     wallStyles[style]["wall"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]);
    126     wallStyles[style]["wallMedium"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]);
    127     wallStyles[style]["wallLong"] = new WallElement("wallLong", "structures/" + style + "_wall_long", 0*PI, 6*wallScaleByType[style]);
    128     // Gate and entrance wall elements
    129     var gateWidth = 6*wallScaleByType[style];
    130     wallStyles[style]["gate"] = new WallElement("gate", "structures/" + style + "_wall_gate", PI, gateWidth);
    131     wallStyles[style]["entry"] = new WallElement("entry", undefined, 0*PI, gateWidth);
    132     wallStyles[style]["entryTower"] = new WallElement("entryTower", "structures/" + civ + "_defense_tower", PI, gateWidth, -4*wallScaleByType[style]);
    133     wallStyles[style]["entryFort"] = new WallElement("entryFort", "structures/" + civ + "_fortress", 0*PI, 8*wallScaleByType[style], 6*wallScaleByType[style]);
    134     // Defensive wall elements with 0 width outside the wall
    135     wallStyles[style]["outpost"] = new WallElement("outpost", "structures/" + civ + "_outpost", PI, 0, -4*wallScaleByType[style]);
    136     wallStyles[style]["defenseTower"] = new WallElement("defenseTower", "structures/" + civ + "_defense_tower", PI, 0, -4*wallScaleByType[style]);
    137     // Base buildings wall elements with 0 width inside the wall
    138     wallStyles[style]["barracks"] = new WallElement("barracks", "structures/" + civ + "_barracks", PI, 0, 4.5*wallScaleByType[style]);
    139     wallStyles[style]["civilCentre"] = new WallElement("civilCentre", "structures/" + civ + "_civil_centre", PI, 0, 4.5*wallScaleByType[style]);
    140     wallStyles[style]["farmstead"] = new WallElement("farmstead", "structures/" + civ + "_farmstead", PI, 0, 4.5*wallScaleByType[style]);
    141     wallStyles[style]["field"] = new WallElement("field", "structures/" + civ + "_field", PI, 0, 4.5*wallScaleByType[style]);
    142     wallStyles[style]["fortress"] = new WallElement("fortress", "structures/" + civ + "_fortress", PI, 0, 4.5*wallScaleByType[style]);
    143     wallStyles[style]["house"] = new WallElement("house", "structures/" + civ + "_house", PI, 0, 4.5*wallScaleByType[style]);
    144     wallStyles[style]["market"] = new WallElement("market", "structures/" + civ + "_market", PI, 0, 4.5*wallScaleByType[style]);
    145     wallStyles[style]["storehouse"] = new WallElement("storehouse", "structures/" + civ + "_storehouse", PI, 0, 4.5*wallScaleByType[style]);
    146     wallStyles[style]["temple"] = new WallElement("temple", "structures/" + civ + "_temple", PI, 0, 4.5*wallScaleByType[style]);
    147     // Generic space/gap wall elements
    148     wallStyles[style]["space1"] = new WallElement("space1", undefined, 0*PI, wallScaleByType[style]);
    149     wallStyles[style]["space2"] = new WallElement("space2", undefined, 0*PI, 2*wallScaleByType[style]);
    150     wallStyles[style]["space3"] = new WallElement("space3", undefined, 0*PI, 3*wallScaleByType[style]);
    151     wallStyles[style]["space4"] = new WallElement("space4", undefined, 0*PI, 4*wallScaleByType[style]);
     117    let wallPart = g_FortressTypes[type].wall;
     118    g_FortressTypes[type].wall = wallPart.concat(wallPart, wallPart, wallPart);
    152119}
    153 // Add wall fortresses for all generic styles
    154 wallStyles["athen"]["wallFort"] = new WallElement("wallFort", "structures/athen_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
    155 wallStyles["brit"]["wallFort"] = new WallElement("wallFort", "structures/brit_fortress", PI, 2.8);
    156 wallStyles["cart"]["wallFort"] = new WallElement("wallFort", "structures/cart_fortress", PI, 5.1, 1.6);
    157 wallStyles["gaul"]["wallFort"] = new WallElement("wallFort", "structures/gaul_fortress", PI, 4.2, 1.5);
    158 wallStyles["iber"]["wallFort"] = new WallElement("wallFort", "structures/iber_fortress", PI, 5, 0.2);
    159 wallStyles["mace"]["wallFort"] = new WallElement("wallFort", "structures/mace_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
    160 wallStyles["maur"]["wallFort"] = new WallElement("wallFort", "structures/maur_fortress", PI, 5.5);
    161 wallStyles["pers"]["wallFort"] = new WallElement("wallFort", "structures/pers_fortress", PI, 5.6/*5.5*/, 1.9/*1.7*/);
    162 wallStyles["ptol"]["wallFort"] = new WallElement("wallFort", "structures/ptol_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
    163 wallStyles["rome"]["wallFort"] = new WallElement("wallFort", "structures/rome_fortress", PI, 6.3, 2.1);
    164 wallStyles["sele"]["wallFort"] = new WallElement("wallFort", "structures/sele_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
    165 wallStyles["spart"]["wallFort"] = new WallElement("wallFort", "structures/spart_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
    166 // Adjust "rome_siege" style
    167 wallStyles["rome_siege"]["wallFort"] = new WallElement("wallFort", "structures/rome_army_camp", PI, 7.2, 2);
    168 wallStyles["rome_siege"]["entryFort"] = new WallElement("entryFort", "structures/rome_army_camp", PI, 12, 7);
    169 wallStyles["rome_siege"]["house"] = new WallElement("house", "structures/rome_tent", PI, 0, 4);
    170120
    171 // Add special wall styles not well to implement generic (and to show how custom styles can be added)
    172 
    173 // Add wall style "palisades"
    174 wallScaleByType["palisades"] = 0.55;
    175 wallStyles["palisades"] = {};
    176 wallStyles["palisades"]["wall"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3);
    177 wallStyles["palisades"]["wallMedium"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3);
    178 wallStyles["palisades"]["wallLong"] = new WallElement("wall", "other/palisades_rocks_long", 0*PI, 3.5);
    179 wallStyles["palisades"]["wallShort"] = new WallElement("wall", "other/palisades_rocks_short", 0*PI, 1.2);
    180 wallStyles["palisades"]["tower"] = new WallElement("tower", "other/palisades_rocks_tower", -PI/2, 0.7);
    181 wallStyles["palisades"]["wallFort"] = new WallElement("wallFort", "other/palisades_rocks_fort", PI, 1.7);
    182 wallStyles["palisades"]["gate"] = new WallElement("gate", "other/palisades_rocks_gate", PI, 3.6);
    183 wallStyles["palisades"]["entry"] = new WallElement("entry", undefined, wallStyles["palisades"]["gate"].angle, wallStyles["palisades"]["gate"].width);
    184 wallStyles["palisades"]["entryTower"] = new WallElement("entryTower", "other/palisades_rocks_watchtower", 0*PI, wallStyles["palisades"]["gate"].width, -3);
    185 wallStyles["palisades"]["entryFort"] = new WallElement("entryFort", "other/palisades_rocks_fort", PI, 6, 3);
    186 wallStyles["palisades"]["cornerIn"] = new WallElement("cornerIn", "other/palisades_rocks_curve", 3*PI/4, 2.1, 0.7, PI/2);
    187 wallStyles["palisades"]["cornerOut"] = new WallElement("cornerOut", "other/palisades_rocks_curve", 5*PI/4, 2.1, -0.7, -PI/2);
    188 wallStyles["palisades"]["outpost"] = new WallElement("outpost", "other/palisades_rocks_outpost", PI, 0, -2);
    189 wallStyles["palisades"]["house"] = new WallElement("house", "other/celt_hut", PI, 0, 5);
    190 wallStyles["palisades"]["barracks"] = new WallElement("barracks", "structures/gaul_tavern", PI, 0, 5);
    191 wallStyles["palisades"]["endRight"] = new WallElement("endRight", "other/palisades_rocks_end", -PI/2, 0.2);
    192 wallStyles["palisades"]["endLeft"] = new WallElement("endLeft", "other/palisades_rocks_end", PI/2, 0.2);
    193 
    194 // Add special wall style "road"
    195 // NOTE: This is not a wall style in the common sense. Use with care!
    196 wallStyles["road"] = {};
    197 wallStyles["road"]["short"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5);
    198 wallStyles["road"]["long"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5);
    199 wallStyles["road"]["cornerLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_corner.xml", -PI/2, 4.5-2*1.25, 1.25, PI/2); // Correct width by -2*indent to fit xStraicht/corner
    200 wallStyles["road"]["cornerRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_corner.xml", 0*PI, 4.5-2*1.25, -1.25, -PI/2); // Correct width by -2*indent to fit xStraicht/corner
    201 wallStyles["road"]["curveLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_curve_small.xml", -PI/2, 4.5+2*0.2, -0.2, PI/2); // Correct width by -2*indent to fit xStraicht/corner
    202 wallStyles["road"]["curveRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_curve_small.xml", 0*PI, 4.5+2*0.2, 0.2, -PI/2); // Correct width by -2*indent to fit xStraicht/corner
    203 wallStyles["road"]["start"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2);
    204 wallStyles["road"]["end"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2);
    205 wallStyles["road"]["xStraight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5);
    206 wallStyles["road"]["xLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, PI/2);
    207 wallStyles["road"]["xRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, -PI/2);
    208 wallStyles["road"]["tLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25);
    209 wallStyles["road"]["tRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0*PI, 4.5, -1.25);
    210 
    211 // Add special wall element collection "other"
    212 // NOTE: This is not a wall style in the common sense. Use with care!
    213 wallStyles["other"] = {};
    214 wallStyles["other"]["fence"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1);
    215 wallStyles["other"]["fence_medium"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1);
    216 wallStyles["other"]["fence_short"] = new WallElement("fence_short", "other/fence_short", -PI/2, 1.5);
    217 wallStyles["other"]["fence_stone"] = new WallElement("fence_stone", "other/fence_stone", -PI/2, 2.5);
    218 wallStyles["other"]["palisade"] = new WallElement("palisade", "other/palisades_rocks_short", 0, 1.2);
    219 wallStyles["other"]["column"] = new WallElement("column", "other/column_doric", 0, 1);
    220 wallStyles["other"]["obelisk"] = new WallElement("obelisk", "other/obelisk", 0, 2);
    221 wallStyles["other"]["spike"] = new WallElement("spike", "other/palisades_angle_spike", -PI/2, 1);
    222 wallStyles["other"]["bench"] = new WallElement("bench", "other/bench", PI/2, 1.5);
    223 wallStyles["other"]["benchForTable"] = new WallElement("benchForTable", "other/bench", 0, 0.5);
    224 wallStyles["other"]["table"] = new WallElement("table", "other/table_rectangle", 0, 1);
    225 wallStyles["other"]["table_square"] = new WallElement("table_square", "other/table_square", PI/2, 1);
    226 wallStyles["other"]["flag"] = new WallElement("flag", "special/rallypoint", PI, 1);
    227 wallStyles["other"]["standing_stone"] = new WallElement("standing_stone", "gaia/special_ruins_standing_stone", PI, 1);
    228 wallStyles["other"]["settlement"] = new WallElement("settlement", "gaia/special_settlement", PI, 6);
    229 wallStyles["other"]["gap"] = new WallElement("gap", undefined, 0, 2);
    230 wallStyles["other"]["gapSmall"] = new WallElement("gapSmall", undefined, 0, 1);
    231 wallStyles["other"]["gapLarge"] = new WallElement("gapLarge", undefined, 0, 4);
    232 wallStyles["other"]["cornerIn"] = new WallElement("cornerIn", undefined, 0, 0, 0, PI/2);
    233 wallStyles["other"]["cornerOut"] = new WallElement("cornerOut", undefined, 0, 0, 0, -PI/2);
    234 
    235 
    236 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    237 //  fortressTypes data structure for some default fortress types
    238 //
    239 //  A fortress type is just an instance of the Fortress class with actually something in it
    240 //  fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size)
    241 //  Examples: "tiny", "veryLarge"
    242 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    243 var fortressTypes = {};
    244 // Setup some default fortress types
    245 // Add fortress type "tiny"
    246 fortressTypes["tiny"] = new Fortress("tiny");
    247 var wallPart = ["gate", "tower", "wallShort", "cornerIn", "wallShort", "tower"];
    248 fortressTypes["tiny"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    249 // Add fortress type "small"
    250 fortressTypes["small"] = new Fortress("small");
    251 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "tower"];
    252 fortressTypes["small"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    253 // Add fortress type "medium"
    254 fortressTypes["medium"] = new Fortress("medium");
    255 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "tower"];
    256 fortressTypes["medium"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    257 // Add fortress type "normal"
    258 fortressTypes["normal"] = new Fortress("normal");
    259 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wall", "cornerIn", "wall", "tower"];
    260 fortressTypes["normal"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    261 // Add fortress type "large"
    262 fortressTypes["large"] = new Fortress("large");
    263 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"];
    264 fortressTypes["large"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    265 // Add fortress type "veryLarge"
    266 fortressTypes["veryLarge"] = new Fortress("veryLarge");
    267 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wall", "cornerIn", "wall", "tower"];
    268 fortressTypes["veryLarge"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    269 // Add fortress type "giant"
    270 fortressTypes["giant"] = new Fortress("giant");
    271 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"];
    272 fortressTypes["giant"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    273 
    274 // Setup some better looking semi default fortresses for "palisades" style
    275 var fortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"];
    276 for (var i = 0; i < fortressTypeKeys.length; i++)
     121/**
     122 * Setup some better looking semi default fortresses for "palisades" style
     123 */
     124for (let fortType of g_FortressTypeKeys)
    277125{
    278     var newKey = fortressTypeKeys[i] + "Palisades";
    279     var oldWall = fortressTypes[fortressTypeKeys[i]].wall;
    280     fortressTypes[newKey] = new Fortress(newKey);
     126    var newKey = fortType + "Palisades";
     127    var oldWall = g_FortressTypes[fortType].wall;
     128    g_FortressTypes[newKey] = new Fortress(newKey);
    281129    var fillTowersBetween = ["wallShort", "wall", "wallLong", "endLeft", "endRight", "cornerIn", "cornerOut"];
    282     for (var j = 0; j < oldWall.length; j++)
     130    for (var j = 0; j < oldWall.length; ++j)
    283131    {
    284         fortressTypes[newKey].wall.push(oldWall[j]); // Only works if the first element is not in fillTowersBetween (e.g. entry or gate like it should be)
     132        g_FortressTypes[newKey].wall.push(oldWall[j]); // Only works if the first element is not in fillTowersBetween (e.g. entry or gate like it should be)
    285133        if (j+1 < oldWall.length)
    286134            if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means "exists" here
    287                 fortressTypes[newKey].wall.push("tower");
     135                g_FortressTypes[newKey].wall.push("tower");
    288136    }
    289137}
    290138
    291 // Setup some balanced (to civ type fortresses) semi default fortresses for "palisades" style
    292 // TODO
     139/**
     140 * Define some helper functions
     141 */
    293142
    294 // Add some "fortress types" for roads (will only work with style "road")
    295 // ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"];
    296 var wall = ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"];
    297 fortressTypes["road01"] = new Fortress("road01", wall);
    298 var wall = ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"];
    299 fortressTypes["road02"] = new Fortress("road02", wall);
    300 var wall = ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"];
    301 fortressTypes["road03"] = new Fortress("road03", wall);
    302 var wall = ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short",
    303     "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"];
    304 fortressTypes["road04"] = new Fortress("road04", wall);
    305 var wall = ["start", "tLeft", "short", "xRight",
    306     "curveLeft", "xRight", "tRight", "cornerLeft", "tRight",
    307     "curveLeft", "short", "tRight", "cornerLeft", "xRight",
    308     "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"];
    309 fortressTypes["road05"] = new Fortress("road05", wall);
     143/**
     144 * Get a wall element of a style.
     145 *
     146 * Valid elements:
     147 *   long, medium, short, start, end, cornerIn, cornerOut, tower, fort, gate
     148 *
     149 * Kept for backwards compatibility:
     150 *   wallLong, wallMedium, wall, wallShort, endLeft, endRight, entry, entryTower, entryFort
     151 *
     152 * If an element of the form `gap{x}` is requested, where `{x}` is a number,
     153 * then a non-blocking gap of `x` length is returned.
     154 *
     155 * If an element of the form `turn{x}` is requested where `{x}` is either
     156 * `out` or `in` (case in-sensitive), then a 90 degree (PI/2 radians) bend
     157 * with zero length is returned in the specified direction.
     158 *
     159 * You can specify a normal structure (ie. `house`, `apadana` `barracks`)
     160 * and the function will attempt to return the appropriate civ's building
     161 * of that type with appropriate indentation away from the wall.
     162 * @todo do something about the arbitrary-ness of the indent.
     163 *
     164 * If after all that, the function still can't work out what's requested,
     165 * it returns a wall tower.
     166 *
     167 * @param style The style from which this element should come from
     168 * @param element The element to fetch
     169 * @return The wall element requested. Or a tower element.
     170 */
     171function getWallElement(style="athen_stone", element)
     172{
     173    if (g_WallStyleList.indexOf(style) < 0)
     174    {
     175        warn("getWallElement: Style '"+style+"' not recognised. (Falling back to '" + FALLBACK_CIV + "_stone'.)");
     176        style = FALLBACK_CIV + "_stone";
     177    }
     178    if (g_WallStyles[style][element])
     179        return g_WallStyles[style][element];
    310180
     181    // Attempt to derive any unknown elements.
     182    // Defaults to a wall tower piece
     183    var wallset = g_WallStyles[style];
     184    var civ = style.split("_")[0];
     185    var ret = clone(wallset.tower);
    311186
    312 ///////////////////////////////
    313 // Define some helper functions
    314 ///////////////////////////////
     187    // We use clone() so we don't change the attributes of the object we're referencing
     188    switch (element)
     189    {
    315190
    316 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    317 //  getWallAlignment
    318 //
    319 //  Returns a list of objects containing all information to place all the wall elements entities with placeObject (but the player ID)
    320 //  Placing the first wall element at startX/startY placed with an angle given by orientation
    321 //  An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement
    322 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    323 function getWallAlignment(startX, startY, wall, style, orientation)
     191    case "cornerIn":
     192        if (wallset.quarterCurve)
     193            ret = clone(wallset.quarterCurve);
     194        else
     195        {
     196            ret.angle += PI/4
     197            ret.indent = ret.length * 0.25;
     198            ret.length = 0;
     199        }
     200        ret.bend = PI/2;
     201        break;
     202
     203    case "cornerOut":
     204        if (wallset.quarterCurve)
     205        {
     206            ret = clone(wallset.quarterCurve);
     207            ret.angle += PI/2;
     208            ret.indent -= ret.indent*2;
     209        }
     210        else
     211        {
     212            ret.angle -= PI/4;
     213            ret.length *= 0.71;
     214        }
     215        ret.bend = -PI/2;
     216        break;
     217
     218    case "wallShort":
     219        warn("getWallElement: Deprecated use of 'wallShort' (please use 'short')");
     220        ret = clone(wallset.short);
     221        break;
     222
     223    case "wallMedium":
     224    case "wall":
     225        warn("getWallElement: Deprecated use of '"+element+"' (please use 'medium')");
     226        ret = clone(wallset.medium);
     227        break;
     228
     229    case "wallLong":
     230        warn("getWallElement: Deprecated use of 'wallLong' (please use 'long')");
     231        ret = clone(wallset.long);
     232        break;
     233
     234    case "entry":
     235        ret.entPath = undefined;
     236        ret.length = clone(g_WallStyles[style].gate.length);
     237        break;
     238
     239    case "entryTower":
     240        ret.entPath = (g_CivList.indexOf(civ) > -1) ? "structures/"+civ+"_defense_tower" : "other/palisades_rocks_watchtower";
     241        ret.indent = ret.length * -3;
     242        ret.length = clone(g_WallStyles[style].gate.length);
     243        break;
     244
     245    case "entryFort":
     246        ret = clone(g_WallStyles[style].fort);
     247        ret.angle -= PI;
     248        ret.length *= 1.5;
     249        ret.indent = ret.length;
     250        break;
     251
     252    case "endLeft":
     253        warn("getWallElement: Deprecated use of 'endLeft' (please use 'start')");
     254    case "start":
     255        if (wallset.end)
     256        {
     257            ret = clone(wallset.end);
     258            ret.angle += PI;
     259        }
     260        break;
     261
     262    case "endRight":
     263        warn("getWallElement: Deprecated use of 'endRight' (please use 'end')");
     264    case "end":
     265        if (wallset.end)
     266            ret = clone(wallset.end);
     267        break;
     268
     269    default:
     270        if (g_CivList.indexOf(civ) == -1)
     271            civ = FALLBACK_CIV;
     272        // Is it a structure?
     273        var entPath = "structures/"+civ+"_"+element;
     274        if (RMS.TemplateExists(entPath))
     275        {
     276            if (["outpost", "defense_tower"].indexOf(element) > -1)
     277                ret.indent = ret.length * -3;
     278            else
     279                ret.indent = ret.length * 3.5;
     280            ret.entPath = entPath;
     281            ret.length = 0;
     282        }
     283        else if (element.slice(0, 3) === "gap") // A gap?
     284        {
     285            ret.entPath = undefined;
     286            ret.angle = 0;
     287            ret.length = +element.slice(3);
     288        }
     289        else if (element.slice(0, 4) === "turn") // A bend?
     290        {
     291            let dir = element.slice(4).toLowerCase();
     292            if (dir === "out" || dir === "in")
     293            {
     294                ret.entPath = undefined;
     295                ret.angle = PI/2;
     296                ret.length = 0;
     297                if (dir === "out")
     298                    ret.angle -= ret.angle;
     299            }
     300            else
     301                warn("Unrecognised turn direction given: '"+dir+"' ("+ style+").");
     302        }
     303        else // Or... I give up.
     304            warn("Unrecognised wall element: '"+element+"' ("+ style+"). Defaulting to 'tower'.");
     305    }
     306
     307    // Cache to save having to calculate this element again
     308    g_WallStyles[style][element] = ret;
     309
     310    return ret;
     311}
     312
     313/**
     314 * Set a wall element of a style.
     315 *
     316 * @param style The style to which this element belongs
     317 * @param element The element to add
     318 * @param path The template path to read values from
     319 */
     320function setWallElement(style, element, path)
    324321{
    325     // Graciously handle arguments
    326     if (wall === undefined)
    327         wall = [];
    328     if (!wallStyles.hasOwnProperty(style))
    329     {
    330         warn("Function getWallAlignment: Unknown style: " + style + ' (falling back to "athen")');
    331         style = "athen";
    332     }
    333     orientation = (orientation || 0);
    334    
     322    var template = RMS.GetTemplate(path);
     323    template = GetTemplateDataHelper(template);
     324
     325    if (!g_WallStyles[style])
     326        g_WallStyles[style] = {};
     327
     328    var length = (template.wallPiece) ? template.wallPiece.length : template.obstruction.shape.width;
     329    g_WallStyles[style][element] = {
     330        "entPath": path,
     331        "angle": (template.wallPiece) ? template.wallPiece.angle : PI,
     332        "length": length / CELL_SIZE,
     333        "indent": (template.wallPiece) ? template.wallPiece.indent / CELL_SIZE : 0,
     334        "bend": (template.wallPiece) ? template.wallPiece.bend : 0
     335    };
     336}
     337
     338/**
     339 *  getWallAlignment
     340 *
     341 *  Returns a list of objects containing all information to place all the wall elements entities with placeObject (but the player ID)
     342 *  Placing the first wall element at startX/startY placed with an angle given by orientation
     343 *  An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement
     344 */
     345function getWallAlignment(startX, startY, wall=[], style="athen_stone", orientation=0)
     346{
    335347    var alignment = [];
    336348    var wallX = startX;
    337349    var wallY = startY;
    338     for (var i = 0; i < wall.length; i++)
     350
     351    for (var i = 0; i < wall.length; ++i)
    339352    {
    340         var element = wallStyles[style][wall[i]];
     353        var element = getWallElement(style, wall[i]);
    341354        if (element === undefined && i == 0)
    342             warn("No valid wall element: " + wall[i]);
     355        {
     356            warn("Not a valid wall element: style = " + style + ", wall[" +i+ "] = " +wall[i]+ "; .entPath = " +element.entPath+ ", .length = " +element.length+ ", .angle = " +element.angle+ ", .indent = " +element.indent+ ", .bend = " +element.bend);
     357            continue;
     358        }
     359
    343360        // Indentation
    344361        var placeX = wallX - element.indent * cos(orientation);
    345362        var placeY = wallY - element.indent * sin(orientation);
     363
    346364        // Add wall elements entity placement arguments to the alignment
    347         alignment.push({"x": placeX, "y": placeY, "entity": element.entity, "angle":orientation + element.angle});
     365        alignment.push({"x": placeX, "y": placeY, "entPath": element.entPath, "angle":orientation + element.angle});
     366
    348367        // Preset vars for the next wall element
    349368        if (i+1 < wall.length)
    350369        {
    351             orientation += element.bending;
    352             var nextElement = wallStyles[style][wall[i+1]];
     370            orientation += element.bend;
     371            var nextElement = getWallElement(style, wall[i+1]);
    353372            if (nextElement === undefined)
    354                 warn("No valid wall element: " + wall[i+1]);
    355             var distance = (element.width + nextElement.width)/2;
     373            {
     374                warn("Not a valid wall element: style = " + style + ", wall[" +(i+1)+ "] = " +wall[i+1]+ "; .entPath = " +nextElement.entPath+ ", .length = " +nextElement.length+ ", .angle = " +nextElement.angle+ ", .indent = " +nextElement.indent+ ", .bend = " +nextElement.bend);
     375                continue;
     376            }
     377           
     378            var distance = (element.length + nextElement.length)/2 - getOverlap(style);
    356379            // Corrections for elements with indent AND bending
    357380            var indent = element.indent;
    358             var bending = element.bending;
    359             if (bending !== 0 && indent !== 0)
     381            var bend = element.bend;
     382            if (bend !== 0 && indent !== 0)
    360383            {
    361384                // Indent correction to adjust distance
    362                 distance += indent*sin(bending);
     385                distance += indent*sin(bend);
    363386                // Indent correction to normalize indentation
    364387                wallX += indent * cos(orientation);
    365388                wallY += indent * sin(orientation);
    366389            }
     390           
    367391            // Set the next coordinates of the next element in the wall without indentation adjustment
    368392            wallX -= distance * sin(orientation);
    369393            wallY += distance * cos(orientation);
     
    372396    return alignment;
    373397}
    374398
    375 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    376 //  getCenterToFirstElement
    377 //
    378 //  Center calculation works like getting the center of mass assuming all wall elements have the same "weight"
    379 //
    380 //  It returns the vector from the center to the first wall element
    381 //  Used to get centerToFirstElement of fortresses by default
    382 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     399/**
     400 *  getCenterToFirstElement
     401 *
     402 *  Center calculation works like getting the center of mass assuming all wall elements have the same "weight"
     403 *
     404 *  It returns the vector from the center to the first wall element
     405 *  Used to get centerToFirstElement of fortresses by default
     406 */
    383407function getCenterToFirstElement(alignment)
    384408{
    385409    var centerToFirstElement = {"x": 0, "y": 0};
    386     for (var i = 0; i < alignment.length; i++)
     410    for (var i = 0; i < alignment.length; ++i)
    387411    {
    388412        centerToFirstElement.x -= alignment[i].x/alignment.length;
    389413        centerToFirstElement.y -= alignment[i].y/alignment.length;
     
    391415    return centerToFirstElement;
    392416}
    393417
    394 //////////////////////////////////////////////////////////////////
    395 //  getWallLength
    396 //
    397 //  NOTE: Does not support bending wall elements like corners!
    398 //  e.g. used by placeIrregularPolygonalWall
    399 //////////////////////////////////////////////////////////////////
    400 function getWallLength(wall, style)
     418/**
     419 *  getWallLength
     420 *
     421 *  NOTE: Does not support bending wall elements like corners!
     422 */
     423function getWallLength(style, wall=[])
    401424{
    402425    // Graciously handle arguments
    403     if (wall === undefined)
    404         wall = [];
    405     if (!wallStyles.hasOwnProperty(style))
     426    if (g_WallStyleList.indexOf(style) < 0)
    406427    {
    407         warn("Function getWallLength: Unknown style: " + style + ' (falling back to "athen")');
    408         style = "athen";
     428        warn("getWallLength: Unknown style: '" + style + "'. (Falling back to '" + FALLBACK_CIV + "_stone').");
     429        style = FALLBACK_CIV +"_stone";
    409430    }
    410    
     431
    411432    var length = 0;
    412     for (var i = 0; i < wall.length; i++)
    413     {
    414         length += wallStyles[style][wall[i]].width;
    415     }
     433    var overlap = getOverlap(style);
     434    for (let element of wall)
     435        length += getWallElement(style, element).length - overlap;
     436
    416437    return length;
    417438}
    418439
     440function getOverlap(style)
     441{
     442    if (!style || g_WallStyleList.indexOf(style) == -1)
     443        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
     444    return g_WallStyles[style]["@overlap"];
     445}
    419446
    420 /////////////////////////////////////////////
    421 // Define the different wall placer functions
    422 /////////////////////////////////////////////
    423447
    424 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    425 //  placeWall
    426 //
    427 //  Places a wall with wall elements attached to another like determined by WallElement properties.
    428 //
    429 //  startX, startY  Where the first wall element should be placed
    430 //  wall            Array of wall element type strings. Example: ["endLeft", "wallLong", "tower", "wallLong", "endRight"]
    431 //  style           Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    432 //  playerId        Optional. Number of the player the wall will be placed for. Default is 0 (gaia)
    433 //  orientation     Optional. Angle the first wall element is placed. Default is 0
    434 //                  0 means "outside" or "front" of the wall is right (positive X) like placeObject
    435 //                  It will then be build towards top/positive Y (if no bending wall elements like corners are used)
    436 //                  Raising orientation means the wall is rotated counter-clockwise like placeObject
    437 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    438 function placeWall(startX, startY, wall, style, playerId, orientation)
     448/**
     449 * Define the different wall placer functions
     450 */
     451
     452/**
     453 *  placeWall
     454 *
     455 *  Places a wall with wall elements attached to another like determined by WallElement properties.
     456 *
     457 *  startX, startY  Where the first wall element should be placed
     458 *  wall            Array of wall element types. Example: ["start", "long", "tower", "long", "end"]
     459 *  style           Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
     460 *  playerId        Optional. Number of the player the wall will be placed for. Default is 0 (gaia)
     461 *  orientation     Optional. Angle the first wall element is placed. Default is 0
     462 *                  0 means "outside" or "front" of the wall is right (positive X) like placeObject
     463 *                  It will then be build towards top/positive Y (if no bending wall elements like corners are used)
     464 *                  Raising orientation means the wall is rotated counter-clockwise like placeObject
     465 */
     466function placeWall(startX=0, startY=0, wall=[], style, playerId=0, orientation=0)
    439467{
    440     // Graciously handle arguments
    441     if (wall === undefined)
    442         wall = [];
    443     playerId = (playerId || 0);
    444     if (!wallStyles.hasOwnProperty(style))
    445     {
    446         if (playerId == 0)
    447             style = (style || "palisades");
    448         else
    449             style = (getCivCode(playerId-1));
    450     }
    451     orientation = (orientation || 0);
     468    if (!style || g_WallStyleList.indexOf(style) == -1)
     469        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    452470   
    453471    // Get wall alignment
    454472    var AM = getWallAlignment(startX, startY, wall, style, orientation);
     473   
    455474    // Place the wall
    456     for (var iWall = 0; iWall < wall.length; iWall++)
     475    for (var iWall = 0; iWall < wall.length; ++iWall)
    457476    {
    458         var entity = AM[iWall].entity;
    459         if (entity !== undefined)
    460             placeObject(AM[iWall].x, AM[iWall].y, entity, playerId, AM[iWall].angle);
     477        var entPath = AM[iWall].entPath;
     478        if (entPath !== undefined)
     479            placeObject(AM[iWall].x, AM[iWall].y, entPath, playerId, AM[iWall].angle);
    461480    }
    462481}
    463482
    464 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    465 //  placeCustomFortress
    466 //
    467 //  Place a fortress (mainly a closed wall build like placeWall) centered at centerX/centerY
    468 //  The fortress wall should always start with the main entrance (like "entry" or "gate") to get the orientation right (like placeObject)
    469 //
    470 //  fortress       An instance of Fortress with a wall defined
    471 //  style          Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    472 //  playerId       Optional. Number of the player the wall will be placed for. Default is 0 (gaia)
    473 //  orientation    Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0
    474 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    475 function placeCustomFortress(centerX, centerY, fortress, style, playerId, orientation)
     483/**
     484 *  placeCustomFortress
     485 *
     486 *  Place a fortress (mainly a closed wall build like placeWall) centered at centerX/centerY
     487 *  The fortress wall should always start with the main entrance (like "entry" or "gate") to get the orientation right (like placeObject)
     488 *
     489 *  fortress       An instance of Fortress with a wall defined
     490 *  style          Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
     491 *  playerId       Optional. Number of the player the wall will be placed for. Default is 0 (gaia)
     492 *  orientation    Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0
     493 */
     494function placeCustomFortress(centerX, centerY, fortress, style, playerId=0, orientation=0)
    476495{
    477496    // Graciously handle arguments
    478     fortress = (fortress || fortressTypes["medium"]);
    479     playerId = (playerId || 0);
    480     if (!wallStyles.hasOwnProperty(style))
    481     {
    482         if (playerId == 0)
    483             style = (style || "palisades");
    484         else
    485             style = (getCivCode(playerId-1));
    486     }
    487     orientation = (orientation || 0);
     497    fortress = fortress || g_FortressTypes["medium"];
     498    if (!style || g_WallStyleList.indexOf(style) == -1)
     499        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    488500   
    489501    // Calculate center if fortress.centerToFirstElement is undefined (default)
    490502    var centerToFirstElement = fortress.centerToFirstElement;
     
    496508    placeWall(startX, startY, fortress.wall, style, playerId, orientation)
    497509}
    498510
    499 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    500 //  placeFortress
    501 //
    502 //  Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress
    503 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    504 function placeFortress(centerX, centerY, type, style, playerId, orientation)
     511/**
     512 *  placeFortress
     513 *
     514 *  Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress
     515 */
     516function placeFortress(centerX, centerY, type="medium", style, playerId=0, orientation=0)
    505517{
    506518    // Graciously handle arguments
    507     type = (type || "medium");
    508     playerId = (playerId || 0);
    509     if (!wallStyles.hasOwnProperty(style))
    510     {
    511         if (playerId == 0)
    512             style = (style || "palisades");
    513         else
    514             style = (getCivCode(playerId-1));
    515     }
    516     orientation = (orientation || 0);
     519    if (!style || g_WallStyleList.indexOf(style) == -1)
     520        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    517521   
    518522    // Call placeCustomFortress with the given arguments
    519     placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation);
     523    placeCustomFortress(centerX, centerY, g_FortressTypes[type], style, playerId, orientation);
    520524}
    521525
    522 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    523 //  placeLinearWall
    524 //
    525 //  Places a straight wall from a given coordinate to an other repeatedly using the wall parts.
    526 //
    527 //  startX/startY    Coordinate of the approximate beginning of the wall (Not the place of the first wall element)
    528 //  targetX/targetY  Coordinate of the approximate ending of the wall (Not the place of the last wall element)
    529 //  wallPart         Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"]
    530 //  style            Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    531 //  playerId         Optional. Integer number of the player. Default is 0 (gaia)
    532 //  endWithFirst     Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true
    533 //
    534 //  TODO: Maybe add angle offset for more generic looking?
    535 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    536 function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId, endWithFirst)
     526/**
     527 *  placeLinearWall
     528 *
     529 *  Places a straight wall from a given coordinate to an other repeatedly using the wall parts.
     530 *
     531 *  startX/startY    Coordinate of the approximate beginning of the wall (Not the place of the first wall element)
     532 *  targetX/targetY  Coordinate of the approximate ending of the wall (Not the place of the last wall element)
     533 *  wallPart         Optional. An array of NON-BENDING wall element types. Default is ["tower", "wallLong"]
     534 *  style            Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
     535 *  playerId         Optional. Integer number of the player. Default is 0 (gaia)
     536 *  endWithFirst     Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true
     537 *
     538 *  TODO: Maybe add angle offset for more generic looking?
     539 */
     540function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId=0, endWithFirst=true)
    537541{
    538542    // Setup optional arguments to the default
    539     wallPart = (wallPart || ["tower", "wallLong"]);
    540     playerId = (playerId || 0);
    541     if (!wallStyles.hasOwnProperty(style))
    542     {
    543         if (playerId == 0)
    544             style = (style || "palisades");
    545         else
    546             style = (getCivCode(playerId-1));
    547     }
    548     endWithFirst = typeof endWithFirst == "undefined" ? true : endWithFirst;
     543    wallPart = wallPart || ["tower", "long"];
     544    if (!style || g_WallStyleList.indexOf(style) == -1)
     545        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    549546   
    550547    // Check arguments
    551     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    552     {
    553         var bending = wallStyles[style][wallPart[elementIndex]].bending;
    554         if (bending != 0)
    555             warn("Bending is not supported by placeLinearWall but a bending wall element is used: " + wallPart[elementIndex] + " -> wallStyles[style][wallPart[elementIndex]].entity");
    556     }
     548    for (let element of wallPart)
     549        if (getWallElement(style, element).bend != 0)
     550            warn("Bending is not supported by placeLinearWall but the following bending wall element was used: " + element);
     551
    557552    // Setup number of wall parts
    558553    var totalLength = getDistance(startX, startY, targetX, targetY);
    559     var wallPartLength = 0;
    560     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    561         wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
     554    var wallPartLength = getWallLength(style, wallPart);
    562555    var numParts = 0;
    563556    if (endWithFirst == true)
    564         numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);
     557        numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength);
    565558    else
    566559        numParts = ceil(totalLength / wallPartLength);
     560
    567561    // Setup scale factor
    568562    var scaleFactor = 1;
    569563    if (endWithFirst == true)
    570         scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);
     564        scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length);
    571565    else
    572566        scaleFactor = totalLength / (numParts * wallPartLength);
     567
    573568    // Setup angle
    574569    var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed...
    575570    var placeAngle = wallAngle - PI/2;
    576571    // Place wall entities
    577572    var x = startX;
    578573    var y = startY;
    579     for (var partIndex = 0; partIndex < numParts; partIndex++)
     574    for (var partIndex = 0; partIndex < numParts; ++partIndex)
    580575    {
    581         for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
     576        for (var elementIndex = 0; elementIndex < wallPart.length; ++elementIndex)
    582577        {
    583             var wallEle = wallStyles[style][wallPart[elementIndex]];
    584             // Width correction
    585             x += scaleFactor * wallEle.width/2 * cos(wallAngle);
    586             y += scaleFactor * wallEle.width/2 * sin(wallAngle);
     578            let wallEle = getWallElement(style, wallPart[elementIndex]);
     579            let wallLength = (wallEle.length - getOverlap(style)) / 2;
     580            let distX = scaleFactor * wallLength * cos(wallAngle);
     581            let distY = scaleFactor * wallLength * sin(wallAngle);
     582            // Length correction
     583            x += distX;
     584            y += distY;
    587585            // Indent correction
    588             var placeX = x - wallEle.indent * sin(wallAngle);
    589             var placeY = y + wallEle.indent * cos(wallAngle);
     586            let placeX = x - wallEle.indent * sin(wallAngle);
     587            let placeY = y + wallEle.indent * cos(wallAngle);
    590588            // Placement
    591             var entity = wallEle.entity;
    592             if (entity !== undefined)
    593                 placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle);
    594             x += scaleFactor * wallEle.width/2 * cos(wallAngle);
    595             y += scaleFactor * wallEle.width/2 * sin(wallAngle);
     589            let entPath = wallEle.entPath;
     590            if (entPath !== undefined)
     591                placeObject(placeX, placeY, entPath, playerId, placeAngle + wallEle.angle);
     592            // Prep for next object
     593            x += distX;
     594            y += distY;
    596595        }
    597596    }
    598597    if (endWithFirst == true)
    599598    {
    600         var wallEle = wallStyles[style][wallPart[0]];
    601         x += scaleFactor * wallEle.width/2 * cos(wallAngle);
    602         y += scaleFactor * wallEle.width/2 * sin(wallAngle);
    603         var entity = wallEle.entity;
    604         if (entity !== undefined)
    605             placeObject(x, y, entity, playerId, placeAngle + wallEle.angle);
     599        var wallEle = getWallElement(style, wallPart[0]);
     600        let wallLength = (wallEle.length - getOverlap(style)) / 2;
     601        x += scaleFactor * wallLength * cos(wallAngle);
     602        y += scaleFactor * wallLength * sin(wallAngle);
     603        var entPath = wallEle.entPath;
     604        if (entPath !== undefined)
     605            placeObject(x, y, entPath, playerId, placeAngle + wallEle.angle);
    606606    }
    607607}
    608608
    609 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    610 //  placeCircularWall
    611 //
    612 //  Place a circular wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius
    613 //  The wall can be opened forming more an arc than a circle if maxAngle < 2*PI
    614 //  The orientation then determines where this open part faces (0 means right like unrotated building's drop-points)
    615 //
    616 //  centerX/Y     Coordinates of the circle's center
    617 //  radius        How wide the circle should be (approximate, especially if maxBendOff != 0)
    618 //  wallPart      Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"]
    619 //  style         Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    620 //  playerId      Optional. Integer number of the player. Default is 0 (gaia)
    621 //  orientation   Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0
    622 //  maxAngle      Optional. How far the wall should circumvent the center. Default is 2*PI (full circle)
    623 //  endWithFirst  Optional. Boolean. If true the 1st wall element in the wallPart array will finalize the wall. Default is false for full circles, else true
    624 //  maxBendOff    Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle)
    625 //
    626 //  NOTE: Don't use wall elements with bending like corners!
    627 //  TODO: Perhaps add eccentricity and maxBendOff functionality (untill now an unused argument)
    628 //  TODO: Perhaps add functionality for spirals
    629 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    630 function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff)
     609/**
     610 *  placeCircularWall
     611 *
     612 *  Place a circular wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius
     613 *  The wall can be opened forming more an arc than a circle if maxAngle < 2*PI
     614 *  The orientation then determines where this open part faces (0 means right like unrotated building's drop-points)
     615 *
     616 *  centerX/Y     Coordinates of the circle's center
     617 *  radius        How wide the circle should be (approximate, especially if maxBendOff != 0)
     618 *  wallPart      Optional. An array of NON-BENDING wall element types. Default is ["tower", "wallLong"]
     619 *  style         Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
     620 *  playerId      Optional. Integer number of the player. Default is 0 (gaia)
     621 *  orientation   Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0
     622 *  maxAngle      Optional. How far the wall should circumvent the center. Default is 2*PI (full circle)
     623 *  endWithFirst  Optional. Boolean. If true the 1st wall element in the wallPart array will finalize the wall. Default is false for full circles, else true
     624 *  maxBendOff    Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle)
     625 *
     626 *  NOTE: Don't use wall elements with bending like corners!
     627 *  TODO: Perhaps add eccentricity
     628 *  TODO: Check if maxBendOff parameter works in all cases
     629 *  TODO: Perhaps add functionality for spirals
     630 */
     631function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId=0, orientation=0, maxAngle=TWO_PI, endWithFirst, maxBendOff=0)
    631632{
    632633    // Setup optional arguments to the default
    633     wallPart = (wallPart || ["tower", "wallLong"]);
    634     playerId = (playerId || 0);
    635     if (!wallStyles.hasOwnProperty(style))
    636     {
    637         if (playerId == 0)
    638             style = (style || "palisades");
    639         else
    640             style = (getCivCode(playerId-1));
    641     }
    642     orientation = (orientation || 0);
    643     maxAngle = (maxAngle || 2*PI);
     634    wallPart = wallPart || ["tower", "long"];
     635    if (!style || g_WallStyleList.indexOf(style) == -1)
     636        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    644637    if (endWithFirst === undefined)
    645638    {
    646         if (maxAngle >= 2*PI - 0.001) // Can this be done better?
     639        if (maxAngle >= TWO_PI - 0.001) // Can this be done better?
    647640            endWithFirst = false;
    648641        else
    649642            endWithFirst = true;
    650643    }
    651     maxBendOff = (maxBendOff || 0);
    652644   
    653645    // Check arguments
    654646    if (maxBendOff > PI/2 || maxBendOff < 0)
    655         warn("placeCircularWall maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff);
    656     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    657     {
    658         var bending = wallStyles[style][wallPart[elementIndex]].bending;
    659         if (bending != 0)
    660             warn("Bending is not supported by placeCircularWall but a bending wall element is used: " + wallPart[elementIndex]);
    661     }
     647        warn("placeCircularWall maxBendOff should satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff);
     648    for (let element of wallPart)
     649        if (getWallElement(style, element).bend != 0)
     650            warn("Bending is not supported by placeCircularWall but the following bending wall element was used: " + element);
     651
    662652    // Setup number of wall parts
    663653    var totalLength = maxAngle * radius;
    664     var wallPartLength = 0;
    665     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    666         wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
     654    var wallPartLength = getWallLength(style, wallPart);
    667655    var numParts = 0;
    668656    if (endWithFirst == true)
    669657    {
    670         numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);
     658        numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength);
    671659    }
    672660    else
    673661    {
     
    676664    // Setup scale factor
    677665    var scaleFactor = 1;
    678666    if (endWithFirst == true)
    679         scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);
     667        scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length);
    680668    else
    681669        scaleFactor = totalLength / (numParts * wallPartLength);
    682670    // Place wall entities
    683671    var actualAngle = orientation + (2*PI - maxAngle) / 2;
    684672    var x = centerX + radius*cos(actualAngle);
    685673    var y = centerY + radius*sin(actualAngle);
    686     for (var partIndex = 0; partIndex < numParts; partIndex++)
     674    for (let partIndex = 0; partIndex < numParts; ++partIndex)
    687675    {
    688         for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
     676        for (let wallEle of wallPart)
    689677        {
    690             var wallEle = wallStyles[style][wallPart[elementIndex]];
     678            wallEle = getWallElement(style, wallEle);
    691679            // Width correction
    692             var addAngle = scaleFactor * wallEle.width / radius;
    693             var targetX = centerX + radius * cos(actualAngle + addAngle);
    694             var targetY = centerY + radius * sin(actualAngle + addAngle);
    695             var placeX = x + (targetX - x)/2;
    696             var placeY = y + (targetY - y)/2;
    697             var placeAngle = actualAngle + addAngle/2;
     680            let addAngle = scaleFactor * (wallEle.length - getOverlap(style)) / radius;
     681            let targetX = centerX + radius * cos(actualAngle + addAngle);
     682            let targetY = centerY + radius * sin(actualAngle + addAngle);
     683            let placeX = x + (targetX - x)/2;
     684            let placeY = y + (targetY - y)/2;
     685            let placeAngle = actualAngle + addAngle/2;
    698686            // Indent correction
    699687            placeX -= wallEle.indent * cos(placeAngle);
    700688            placeY -= wallEle.indent * sin(placeAngle);
    701689            // Placement
    702             var entity = wallEle.entity;
    703             if (entity !== undefined)
    704                 placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle);
     690            var entPath = wallEle.entPath;
     691            if (entPath !== undefined)
     692                placeObject(placeX, placeY, entPath, playerId, placeAngle + wallEle.angle);
    705693            // Prepare for the next wall element
    706694            actualAngle += addAngle;
    707695            x = centerX + radius*cos(actualAngle);
     
    710698    }
    711699    if (endWithFirst == true)
    712700    {
    713         var wallEle = wallStyles[style][wallPart[0]];
    714         var addAngle = scaleFactor * wallEle.width / radius;
     701        var wallEle = getWallElement(style, wallPart[0]);
     702        var addAngle = scaleFactor * wallEle.length / radius;
    715703        var targetX = centerX + radius * cos(actualAngle + addAngle);
    716704        var targetY = centerY + radius * sin(actualAngle + addAngle);
    717705        var placeX = x + (targetX - x)/2;
    718706        var placeY = y + (targetY - y)/2;
    719707        var placeAngle = actualAngle + addAngle/2;
    720         placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle);
     708        placeObject(placeX, placeY, wallEle.entPath, playerId, placeAngle + wallEle.angle);
    721709    }
    722710}
    723711
    724 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    725 //  placePolygonalWall
    726 //
    727 //  Place a polygonal wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius
    728 //
    729 //  centerX/Y          Coordinates of the polygon's center
    730 //  radius             How wide the circle should be in which the polygon fits
    731 //  wallPart           Optional. An array of NON-BENDING wall element type strings. Default is ["wallLong", "tower"]
    732 //  cornerWallElement  Optional. Wall element to be placed at the polygon's corners. Default is "tower"
    733 //  style              Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    734 //  playerId           Optional. Integer number of the player. Default is 0 (gaia)
    735 //  orientation        Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)
    736 //  numCorners         Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory)
    737 //  skipFirstWall      Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true
    738 //
    739 //  NOTE: Don't use wall elements with bending like corners!
    740 //  TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement
    741 //  TODO: Check some arguments
    742 //  TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0
    743 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    744 function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall)
     712/**
     713 *  placePolygonalWall
     714 *
     715 *  Place a polygonal wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius
     716 *
     717 *  centerX/Y          Coordinates of the polygon's center
     718 *  radius             How wide the circle should be in which the polygon fits
     719 *  wallPart           Optional. An array of NON-BENDING wall element types. Default is ["wallLong", "tower"]
     720 *  cornerWallElement  Optional. Wall element to be placed at the polygon's corners. Default is "tower"
     721 *  style              Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
     722 *  playerId           Optional. Integer number of the player. Default is 0 (gaia)
     723 *  orientation        Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)
     724 *  numCorners         Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory)
     725 *  skipFirstWall      Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true
     726 *
     727 *  NOTE: Don't use wall elements with bending like corners!
     728 *  TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement
     729 *  TODO: Check some arguments
     730 *  TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0
     731 */
     732function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId=0, orientation=0, numCorners=8, skipFirstWall=true)
    745733{
    746734    // Setup optional arguments to the default
    747     wallPart = (wallPart || ["wallLong", "tower"]);
    748     cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well...
    749     playerId = (playerId || 0);
    750     if (!wallStyles.hasOwnProperty(style))
    751     {
    752         if (playerId == 0)
    753             style = (style || "palisades");
    754         else
    755             style = (getCivCode(playerId-1));
    756     }
    757     orientation = (orientation || 0);
    758     numCorners = (numCorners || 8);
    759     skipFirstWall = (skipFirstWall || true);
    760    
     735    wallPart = wallPart || ["long", "tower"];
     736    cornerWallElement = cornerWallElement || "tower"; // Don't use wide elements for this. Not supported well...
     737    if (!style || g_WallStyleList.indexOf(style) == -1)
     738        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
     739
    761740    // Setup angles
    762     var angleAdd = 2*PI/numCorners;
     741    var angleAdd = TWO_PI/numCorners;
    763742    var angleStart = orientation - angleAdd/2;
     743
    764744    // Setup corners
    765745    var corners = [];
    766     for (var i = 0; i < numCorners; i++)
     746    for (let i = 0; i < numCorners; ++i)
    767747        corners.push([centerX + radius*cos(angleStart + i*angleAdd), centerY + radius*sin(angleStart + i*angleAdd)]);
     748
    768749    // Place Corners and walls
    769     for (var i = 0; i < numCorners; i++)
     750    for (let i = 0; i < numCorners; ++i)
    770751    {
    771         var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
    772         placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);
     752        let angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
     753        placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner);
    773754        if (!(skipFirstWall && i == 0))
    774755        {
     756            let cornerLength = getWallElement(style, cornerWallElement).length / 2;
     757            let cornerAngle = angleToCorner + angleAdd / 2;
     758            let cornerX = cornerLength * sin(cornerAngle);
     759            let cornerY = cornerLength * cos(cornerAngle);
    775760            placeLinearWall(
    776761                // Adjustment to the corner element width (approximately)
    777                 corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // startX
    778                 corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // startY
    779                 corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // targetX
    780                 corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // targetY
     762                corners[i][0] + cornerX, // startX
     763                corners[i][1] - cornerY, // startY
     764                corners[(i+1)%numCorners][0] - cornerX, // targetX
     765                corners[(i+1)%numCorners][1] + cornerY, // targetY
    781766                wallPart, style, playerId);
    782767        }
    783768    }
    784769}
    785770
    786 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    787 //  placeIrregularPolygonalWall
    788 //
    789 //  Place an irregular polygonal wall of some wall parts to choose from around centerX/centerY with the given radius
    790 //
    791 //  centerX/Y            Coordinates of the polygon's center
    792 //  radius               How wide the circle should be in which the polygon fits
    793 //  cornerWallElement    Optional. Wall element to be placed at the polygon's corners. Default is "tower"
    794 //  style                Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    795 //  playerId             Optional. Integer number of the player. Default is 0 (gaia)
    796 //  orientation          Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)
    797 //  numCorners           Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory)
    798 //  irregularity         Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5
    799 //  skipFirstWall        Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true
    800 //  wallPartsAssortment  Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^
    801 //
    802 //  NOTE: wallPartsAssortment is put to the end because it's hardest to set
    803 //  NOTE: Don't use wall elements with bending like corners!
    804 //  TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement
    805 //  TODO: Check some arguments
    806 //  TODO: Perhaps add eccentricity
    807 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    808 function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment)
     771/**
     772 *  placeIrregularPolygonalWall
     773 *
     774 *  Place an irregular polygonal wall of some wall parts to choose from around centerX/centerY with the given radius
     775 *
     776 *  centerX/Y            Coordinates of the polygon's center
     777 *  radius               How wide the circle should be in which the polygon fits
     778 *  cornerWallElement    Optional. Wall element to be placed at the polygon's corners. Default is "tower"
     779 *  style                Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
     780 *  playerId             Optional. Integer number of the player. Default is 0 (gaia)
     781 *  orientation          Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)
     782 *  numCorners           Optional. How many corners the polygon will have. Default is randomly chosen from 'tween 5 & 7 inclusive
     783 *  irregularity         Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5
     784 *  skipFirstWall        Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is false
     785 *  wallPartsAssortment  Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^
     786 *
     787 *  NOTE: wallPartsAssortment is put to the end because it's hardest to set
     788 *  NOTE: Don't use wall elements with bending like corners!
     789 *  TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement
     790 *  TODO: Check some arguments
     791 *  TODO: Perhaps add eccentricity
     792 */
     793function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement="tower", style, playerId=0, orientation=0, numCorners, irregularity=0.5, skipFirstWall=false, wallPartsAssortment)
    809794{
    810795    // Setup optional arguments
    811     playerId = (playerId || 0);
    812     if (!wallStyles.hasOwnProperty(style))
    813     {
    814         if (playerId == 0)
    815             style = (style || "palisades");
    816         else
    817             style = (getCivCode(playerId-1));
    818     }
    819    
     796    if (!style || g_WallStyleList.indexOf(style) == -1)
     797        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
     798    numCorners = (numCorners || randInt(5, 7));
     799
    820800    // Generating a generic wall part assortment with each wall part including 1 gate lengthened by walls and towers
    821801    // NOTE: It might be a good idea to write an own function for that...
    822     var defaultWallPartsAssortment = [["wallShort"], ["wall"], ["wallLong"], ["gate", "tower", "wallShort"]];
     802    var defaultWallPartsAssortment = [["short"], ["medium"], ["long"], ["gate", "tower", "short"]];
    823803    var centeredWallPart = ["gate"];
    824     var extandingWallPartAssortment = [["tower", "wallLong"], ["tower", "wall"]];
     804    var extandingWallPartAssortment = [["tower", "long"], ["tower", "medium"]];
    825805    defaultWallPartsAssortment.push(centeredWallPart);
    826     for (var i = 0; i < extandingWallPartAssortment.length; i++)
     806    for (var i = 0; i < extandingWallPartAssortment.length; ++i)
    827807    {
    828808        var wallPart = centeredWallPart;
    829         for (var j = 0; j < radius; j++)
     809        for (var j = 0; j < radius; ++j)
    830810        {
    831811            if (j%2 == 0)
    832812                wallPart = wallPart.concat(extandingWallPartAssortment[i]);
     
    841821    }
    842822    // Setup optional arguments to the default
    843823    wallPartsAssortment = (wallPartsAssortment || defaultWallPartsAssortment);
    844     cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well...
    845     style = (style || "palisades");
    846     playerId = (playerId || 0);
    847     orientation = (orientation || 0);
    848     numCorners = (numCorners || randInt(5, 7));
    849     irregularity = (irregularity || 0.5);
    850     skipFirstWall = (skipFirstWall || false);
     824
    851825    // Setup angles
    852     var angleToCover = 2*PI;
     826    var angleToCover = TWO_PI;
    853827    var angleAddList = [];
    854     for (var i = 0; i < numCorners; i++)
     828    for (var i = 0; i < numCorners; ++i)
    855829    {
    856830        // Randomize covered angles. Variety scales down with raising angle though...
    857831        angleAddList.push(angleToCover/(numCorners-i) * (1 + randFloat(-irregularity, irregularity)));
     
    860834    // Setup corners
    861835    var corners = [];
    862836    var angleActual = orientation - angleAddList[0]/2;
    863     for (var i = 0; i < numCorners; i++)
     837    for (var i = 0; i < numCorners; ++i)
    864838    {
    865839        corners.push([centerX + radius*cos(angleActual), centerY + radius*sin(angleActual)]);
    866840        if (i < numCorners - 1)
     
    869843    // Setup best wall parts for the different walls (a bit confusing naming...)
    870844    var wallPartLengths = [];
    871845    var maxWallPartLength = 0;
    872     for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)
     846    for (let wallPart of wallPartsAssortment)
    873847    {
    874         var length = wallPartLengths[partIndex];
    875         wallPartLengths.push(getWallLength(wallPartsAssortment[partIndex], style));
     848        var length = getWallLength(style, wallPart);
     849        wallPartLengths.push(length);
    876850        if (length > maxWallPartLength)
    877851            maxWallPartLength = length;
    878852    }
     853   
    879854    var wallPartList = []; // This is the list of the wall parts to use for the walls between the corners, not to confuse with wallPartsAssortment!
    880     for (var i = 0; i < numCorners; i++)
     855    for (var i = 0; i < numCorners; ++i)
    881856    {
    882         var bestWallPart = []; // This is a simpel wall part not a wallPartsAssortment!
    883         var bestWallLength = 99999999;
     857        var bestWallPart = []; // This is a simple wall part not a wallPartsAssortment!
     858        var bestWallLength = Number.MAX_VALUE;
    884859        // NOTE: This is not exactly like the length the wall will be in the end. Has to be tweaked...
    885860        var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]);
    886861        var numWallParts = ceil(wallLength/maxWallPartLength);
    887         for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)
     862        for (var partIndex = 0; partIndex < wallPartsAssortment.length; ++partIndex)
    888863        {
    889864            var linearWallLength = numWallParts*wallPartLengths[partIndex];
    890865            if (linearWallLength < bestWallLength && linearWallLength > wallLength)
     
    895870        }
    896871        wallPartList.push(bestWallPart);
    897872    }
     873
    898874    // Place Corners and walls
    899     for (var i = 0; i < numCorners; i++)
     875    for (var i = 0; i < numCorners; ++i)
    900876    {
    901877        var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
    902         placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);
     878        placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner);
    903879        if (!(skipFirstWall && i == 0))
    904880        {
     881            let cornerLength = getWallElement(style, cornerWallElement).length / 2;
    905882            placeLinearWall(
    906883                // Adjustment to the corner element width (approximately)
    907                 corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[i]/2), // startX
    908                 corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[i]/2), // startY
    909                 corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX
    910                 corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY
     884                corners[i][0] + cornerLength * sin(angleToCorner + angleAddList[i]/2), // startX
     885                corners[i][1] - cornerLength * cos(angleToCorner + angleAddList[i]/2), // startY
     886                corners[(i+1)%numCorners][0] - cornerLength * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX
     887                corners[(i+1)%numCorners][1] + cornerLength * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY
    911888                wallPartList[i], style, playerId, false);
    912889        }
    913890    }
    914891}
    915892
    916 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    917 //  placeGenericFortress
    918 //
    919 //  Places a generic fortress with towers at the edges connected with long walls and gates (entries until gates work)
    920 //  This is the default Iberian civ bonus starting wall
    921 //
    922 //  centerX/Y      The approximate center coordinates of the fortress
    923 //  radius         The approximate radius of the wall to be placed
    924 //  playerId       Optional. Integer number of the player. Default is 0 (gaia)
    925 //  style          Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    926 //  irregularity   Optional. Float between 0 (circle) and 1 (very spiky), default is 1/2
    927 //  gateOccurence  Optional. Integer number, every n-th walls will be a gate instead. Default is 3
    928 //  maxTrys        Optional. How often the function tries to find a better fitting shape at max. Default is 100
    929 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    930 function placeGenericFortress(centerX, centerY, radius, playerId, style, irregularity, gateOccurence, maxTrys)
     893/**
     894 *  placeGenericFortress
     895 *
     896 *  Places a generic fortress with towers at the edges connected with long walls and gates (entries until gates work)
     897 *  This is the default Iberian civ bonus starting wall
     898 *
     899 *  centerX/Y      The approximate center coordinates of the fortress
     900 *  radius         Optional. The approximate radius of the wall to be placed. Default is 20
     901 *  playerId       Optional. Integer number of the player. Default is 0 (gaia)
     902 *  style          Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
     903 *  irregularity   Optional. Float between 0 (circle) and 1 (very spiky), default is 0.5
     904 *  gateOccurence  Optional. Integer number, every n-th walls will be a gate instead. Default is 3
     905 *  maxTrys        Optional. How often the function tries to find a better fitting shape at max. Default is 100
     906 */
     907function placeGenericFortress(centerX, centerY, radius=20, playerId=0, style, irregularity=0.5, gateOccurence=3, maxTrys=100)
    931908{
    932909    // Setup optional arguments
    933     radius = (radius || 20);
    934     playerId = (playerId || 0);
    935     if (!wallStyles.hasOwnProperty(style))
    936     {
    937         if (playerId == 0)
    938             style = (style || "palisades");
    939         else
    940             style = (getCivCode(playerId-1));
    941     }
    942     irregularity = (irregularity || 1/2);
    943     gateOccurence = (gateOccurence || 3);
    944     maxTrys = (maxTrys || 100);
     910    if (!style || g_WallStyleList.indexOf(style) == -1)
     911        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    945912   
    946913    // Setup some vars
    947914    var startAngle = randFloat(0, 2*PI);
    948915    var actualOffX = radius*cos(startAngle);
    949916    var actualOffY = radius*sin(startAngle);
    950917    var actualAngle = startAngle;
    951     var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width;
     918    var pointDistance = getWallLength(style, ["long", "tower"]);
    952919    // Searching for a well fitting point derivation
    953920    var tries = 0;
    954921    var bestPointDerivation = undefined;
    955922    var minOverlap = 1000;
    956923    var overlap = undefined;
    957     while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10)
     924    while (tries < maxTrys && minOverlap > getOverlap(style))
    958925    {
    959926        var pointDerivation = [];
    960927        var distanceToTarget = 1000;
     
    963930        {
    964931            var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance);
    965932            var tmpAngle = getAngle(actualOffX, actualOffY,
    966                 (radius + indent)*cos(actualAngle + (pointDistance / radius)),
    967                 (radius + indent)*sin(actualAngle + (pointDistance / radius)));
     933                (radius + indent)*cos(actualAngle + pointDistance / radius),
     934                (radius + indent)*sin(actualAngle + pointDistance / radius));
    968935            actualOffX += pointDistance*cos(tmpAngle);
    969936            actualOffY += pointDistance*sin(tmpAngle);
    970937            actualAngle = getAngle(0, 0, actualOffX, actualOffY);
     
    982949                }
    983950            }
    984951        }
    985         tries++;
     952        ++tries;
    986953    }
    987954    log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries");
    988955    // Place wall
    989     for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++)
     956    for (var pointIndex = 0; pointIndex < bestPointDerivation.length; ++pointIndex)
    990957    {
    991958        var startX = centerX + bestPointDerivation[pointIndex][0];
    992959        var startY = centerY + bestPointDerivation[pointIndex][1];
    993960        var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0];
    994961        var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1];
    995962        var angle = getAngle(startX, startY, targetX, targetY);
    996         var wallElement = "wallLong";
     963        var wallElement = "long";
    997964        if ((pointIndex + 1) % gateOccurence == 0)
    998965            wallElement = "gate";
    999         var entity = wallStyles[style][wallElement].entity;
    1000         if (entity)
     966
     967        var entPath = getWallElement(style, wallElement).entPath;
     968        if (entPath)
    1001969        {
    1002970            placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX
    1003971                startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY
    1004                 entity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle);
     972                entPath, playerId, angle - PI/2 + getWallElement(style, wallElement).angle);
    1005973        }
    1006974        // Place tower
    1007975        var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0];
    1008976        var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1];
    1009977        var angle = getAngle(startX, startY, targetX, targetY);
    1010         placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style]["tower"].entity, playerId, angle - PI/2 + wallStyles[style]["tower"].angle);
     978
     979        var tower = getWallElement(style, "tower");
     980        placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], tower.entPath, playerId, angle - PI/2 + tower.angle);
    1011981    }
    1012982}
  • binaries/data/mods/public/maps/random/schwarzwald.js

     
    1 // Created by Niek ten Brinke (aka niektb)
    2 // Based on FeXoR's Daimond Square Algorithm for heightmap generation and several official random maps
     1/**
     2 * Created by Niek ten Brinke (aka niektb)
     3 * Based on FeXoR's Daimond Square Algorithm for heightmap generation and several official random maps
     4 */
    35
    46'use strict';
    57
    68RMS.LoadLibrary('rmgen');
    79
    8 // initialize map
     10/**
     11 * initialize map
     12 */
    913
    1014log('Initializing map...');
    1115
    1216InitMap();
    1317
    1418
    15 ////////////////
    16 //
    17 //  Initializing
    18 //
    19 ////////////////
     19/**
     20 *  Initializing
     21 */
    2022
    21 //sky
     23/**
     24 *sky
     25 */
    2226setSkySet("fog");
    2327setFogFactor(0.35);
    2428setFogThickness(0.19);
    25 
    26 // water
     29/**
     30 * water
     31 */
    2732setWaterColor(0.501961, 0.501961, 0.501961);
    2833setWaterTint(0.25098, 0.501961, 0.501961);
    2934setWaterWaviness(0.5);
    3035setWaterType("clap");
    3136setWaterMurkiness(0.75);
    32 
    33 // post processing
     37/**
     38 * post processing
     39 */
    3440setPPSaturation(0.37);
    3541setPPContrast(0.4);
    3642setPPBrightness(0.4);
    3743setPPEffect("hdr");
    3844setPPBloom(0.4);
    39 
    40 // Setup tile classes
     45/**
     46 * Setup tile classes
     47 */
    4148var clPlayer = createTileClass();
    4249var clPath = createTileClass();
    4350var clHill = createTileClass();
     
    4754var clFood = createTileClass();
    4855var clBaseResource = createTileClass();
    4956var clOpen = createTileClass();
    50 
    51 // Setup Templates
     57/**
     58 * Setup Templates
     59 */
    5260var templateStone = 'gaia/geology_stone_alpine_a';
    5361var templateStoneMine = 'gaia/geology_stonemine_alpine_quarry';
    5462var templateMetal = 'actor|geology/stone_granite_med.xml';
     
    6472var aReeds = 'actor|props/flora/reeds_pond_lush_b.xml';
    6573var oFish = "gaia/fauna_fish";
    6674
    67 
    68 // Setup terrain
     75/**
     76 * Setup terrain
     77 */
    6978var terrainWood = ['alpine_forrestfloor|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine'];
    7079var terrainWoodBorder = ['new_alpine_grass_mossy|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine',
    7180    'temp_grass_long|gaia/flora_bush_temperate', 'temp_grass_clovers|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes',
     
    108117
    109118const BUILDING_ANGlE = -PI/4;
    110119
    111 // Setup map
     120/**
     121 * Setup map
     122 */
    112123var mapSize = getMapSize();
    113124var mapRadius = mapSize/2;
    114125var playableMapRadius = mapRadius - 5;
    115126var mapCenterX = mapRadius;
    116127var mapCenterZ = mapRadius;
    117128
    118 // Setup players and bases
     129/**
     130 * Setup players and bases
     131 */
    119132var numPlayers = getNumPlayers();
    120133var baseRadius = 15;
    121134var minPlayerRadius = min(mapRadius-1.5*baseRadius, 5*mapRadius/8);
     
    128141var playerAngleAddAvrg = 2*PI / numPlayers;
    129142var playerAngleMaxOff = playerAngleAddAvrg/4;
    130143
    131 // Setup paths
     144/**
     145 * Setup paths
     146 */
    132147var pathSucsessRadius = baseRadius/2;
    133148var pathAngleOff = PI/2;
    134 var pathWidth = 10; // This is not really the path's thickness in tiles but the number of tiles in the clumbs of the path
     149var pathWidth = 10; // This is not really the path's thickness in tiles but the number of tiles in the clumps of the path
    135150
    136 // Setup additional resources
     151/**
     152 * Setup additional resources
     153 */
    137154var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8;
    138155//var resourcePerPlayer = [templateStone, templateMetalMine];
    139156
    140 // Setup woods
    141 // For large maps there are memory errors with too many trees.  A density of 256*192/mapArea works with 0 players.
    142 // Around each player there is an area without trees so with more players the max density can increase a bit.
     157/**
     158 * Setup woods
     159 * For large maps there are memory errors with too many trees.  A density of 256*192/mapArea works with 0 players.
     160 * Around each player there is an area without trees so with more players the max density can increase a bit.
     161 */
    143162var maxTreeDensity = min(256 * (192 + 8 * numPlayers) / (mapSize * mapSize), 1); // Has to be tweeked but works ok
    144163var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood
    145164
    146165
    147 ////////////////
    148 //
    149 //  Some general functions
    150 //
    151 ////////////////
    152 
     166/**
     167 * Some general functions
     168 */
    153169function HeightPlacer(lowerBound, upperBound) {
    154170    this.lowerBound = lowerBound;
    155171    this.upperBound = upperBound;
     
    159175    constraint = (constraint || new NullConstraint());
    160176   
    161177    var ret = [];
    162     for (var x = 0; x < g_Map.size; x++) {
    163         for (var y = 0; y < g_Map.size; y++) {
     178    for (var x = 0; x < g_Map.size; ++x) {
     179        for (var y = 0; y < g_Map.size; ++y) {
    164180            if (g_Map.height[x][y] >= this.lowerBound && g_Map.height[x][y] <= this.upperBound && constraint.allows(x, y)) {
    165181                ret.push(new PointXZ(x, y));
    166182            }
     
    169185    return ret;
    170186};
    171187
    172 /*
    173 Takes an array of 2D points (arrays of length 2)
    174 Returns the order to go through the points for the shortest closed path (array of indices)
    175 */
     188/**
     189 * Takes an array of 2D points (arrays of length 2)
     190 * Returns the order to go through the points for the shortest closed path (array of indices)
     191 */
    176192function getOrderOfPointsForShortestClosePath(points)
    177193{
    178194    var order = [];
    179195    var distances = [];
    180196    if (points.length <= 3)
    181197    {
    182         for (var i = 0; i < points.length; i++)
     198        for (var i = 0; i < points.length; ++i)
    183199            order.push(i);
    184200       
    185201        return order;
     
    187203   
    188204    // Just add the first 3 points
    189205    var pointsToAdd = deepcopy(points);
    190     for (var i = 0; i < min(points.length, 3); i++)
     206    for (var i = 0; i < min(points.length, 3); i)
    191207    {
    192208        order.push(i);
    193209        pointsToAdd.shift(i);
     
    198214   
    199215    // Add remaining points so the path lengthens the least
    200216    var numPointsToAdd = pointsToAdd.length;
    201     for (var i = 0; i < numPointsToAdd; i++)
     217    for (var i = 0; i < numPointsToAdd; ++i)
    202218    {
    203219        var indexToAddTo = undefined;
    204220        var minEnlengthen = Infinity;
    205221        var minDist1 = 0;
    206222        var minDist2 = 0;
    207         for (var k = 0; k < order.length; k++)
     223        for (var k = 0; k < order.length; ++k)
    208224        {
    209225            var dist1 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[k]][0], points[order[k]][1]);
    210226            var dist2 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[(k + 1) % order.length]][0], points[order[(k + 1) % order.length]][1]);
     
    226242}
    227243
    228244
    229 ////////////////
    230 //
    231 //  Heightmap functionality
    232 //
    233 ////////////////
     245/**
     246 *  Heightmap functionality
     247 */
    234248
    235 // Some heightmap constants
    236 const MIN_HEIGHT = - SEA_LEVEL; // -20
    237 const MAX_HEIGHT = 0xFFFF/HEIGHT_UNITS_PER_METRE - SEA_LEVEL; // A bit smaller than 90
    238 
    239 // Get the diferrence between minimum and maxumum height
     249/**
     250 * Get the diferrence between minimum and maxumum height
     251 */
    240252function getMinAndMaxHeight(reliefmap)
    241253{
    242254    var height = {};
    243255    height.min = Infinity;
    244256    height.max = - Infinity;
    245     for (var x = 0; x < reliefmap.length; x++)
     257    for (var x = 0; x < reliefmap.length; ++x)
    246258    {
    247         for (var y = 0; y < reliefmap[x].length; y++)
     259        for (var y = 0; y < reliefmap[x].length; ++y)
    248260        {
    249261            if (reliefmap[x][y] < height.min)
    250262                height.min = reliefmap[x][y];
     
    264276    var oldHeightRange = getMinAndMaxHeight(heightmap);
    265277    var max_x = heightmap.length;
    266278    var max_y = heightmap[0].length;
    267     for (var x = 0; x < max_x; x++)
    268         for (var y = 0; y < max_y; y++)
     279    for (var x = 0; x < max_x; ++x)
     280        for (var y = 0; y < max_y; ++y)
    269281            heightmap[x][y] = minHeight + (heightmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight);
    270282}
    271283
    272 /*
    273 getStartLocationsByHeightmap
    274 Takes
    275     hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
    276     heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
    277     maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
    278     minDistToBorder Optional, default is 20, an integer, how far start locations have to be
    279     numberOfPlayers Optional, default is getNumPlayers, an integer, how many start locations should be placed
    280 Returns
    281     An array of 2D points (arrays of length 2)
    282 */
     284/**
     285 * getStartLocationsByHeightmap
     286 * Takes
     287 *  hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
     288 *  heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
     289 *  maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
     290 *  minDistToBorder Optional, default is 20, an integer, how far start locations have to be
     291 *  numberOfPlayers Optional, default is getNumPlayers, an integer, how many start locations should be placed
     292 * Returns
     293 *  An array of 2D points (arrays of length 2)
     294 */
    283295function getStartLocationsByHeightmap(hightRange, maxTries, minDistToBorder, numberOfPlayers, heightmap)
    284296{
    285297    maxTries = (maxTries || 1000);
     
    288300    heightmap = (heightmap || g_Map.height);
    289301   
    290302    var validStartLocTiles = [];
    291     for (var x = minDistToBorder; x < heightmap.length - minDistToBorder; x++)
    292         for (var y = minDistToBorder; y < heightmap[0].length - minDistToBorder; y++)
     303    for (var x = minDistToBorder; x < heightmap.length - minDistToBorder; ++x)
     304        for (var y = minDistToBorder; y < heightmap[0].length - minDistToBorder; ++y)
    293305            if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight
    294306                validStartLocTiles.push([x, y]);
    295307   
    296308    var maxMinDist = 0;
    297     for (var tries = 0; tries < maxTries; tries++)
     309    for (var tries = 0; tries < maxTries; ++tries)
    298310    {
    299311        var startLoc = [];
    300312        var minDist = heightmap.length;
    301         for (var p = 0; p < numberOfPlayers; p++)
     313        for (var p = 0; p < numberOfPlayers; ++p)
    302314            startLoc.push(validStartLocTiles[randInt(validStartLocTiles.length)]);
    303         for (var p1 = 0; p1 < numberOfPlayers - 1; p1++)
     315        for (var p1 = 0; p1 < numberOfPlayers - 1; ++p1)
    304316        {
    305             for (var p2 = p1 + 1; p2 < numberOfPlayers; p2++)
     317            for (var p2 = p1 + 1; p2 < numberOfPlayers; ++p2)
    306318            {
    307319                var dist = getDistance(startLoc[p1][0], startLoc[p1][1], startLoc[p2][0], startLoc[p2][1]);
    308320                if (dist < minDist)
     
    319331    return finalStartLoc;
    320332}
    321333
    322 /*
    323 derivateEntitiesByHeight
    324 Takes
    325     hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
    326     startLoc        An array of 2D points (arrays of length 2)
    327     heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
    328     entityList      Array of entities/actors (strings to be placed with placeObject())
    329     maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
    330     minDistance     Optional, default is 30, an integer, how far start locations have to be away from start locations and the map border
    331 Returns
    332     An array of 2D points (arrays of length 2)
    333 */
     334/**
     335 *derivateEntitiesByHeight
     336 *Takes
     337 *  hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
     338 *  startLoc        An array of 2D points (arrays of length 2)
     339 *  heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
     340 *  entityList      Array of entities/actors (strings to be placed with placeObject())
     341 *  maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
     342 *  minDistance     Optional, default is 30, an integer, how far start locations have to be away from start locations and the map border
     343 *Returns
     344 *  An array of 2D points (arrays of length 2)
     345 */
    334346function derivateEntitiesByHeight(hightRange, startLoc, entityList, maxTries, minDistance, heightmap)
    335347{
    336348    entityList = (entityList || [templateMetalMine, templateStoneMine]);
     
    340352   
    341353    var placements = deepcopy(startLoc);
    342354    var validTiles = [];
    343     for (var x = minDistance; x < heightmap.length - minDistance; x++)
    344         for (var y = minDistance; y < heightmap[0].length - minDistance; y++)
     355    for (var x = minDistance; x < heightmap.length - minDistance; ++x)
     356        for (var y = minDistance; y < heightmap[0].length - minDistance; ++y)
    345357            if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight
    346358                validTiles.push([x, y]);
    347359   
    348360    if (!validTiles.length)
    349361        return;
    350362   
    351     for (var tries = 0; tries < maxTries; tries++)
     363    for (var tries = 0; tries < maxTries; ++tries)
    352364    {
    353365        var tile = validTiles[randInt(validTiles.length)];
    354366        var isValid = true;
    355         for (var p = 0; p < placements.length; p++)
     367        for (var p = 0; p < placements.length; ++p)
    356368        {
    357369            if (getDistance(placements[p][0], placements[p][1], tile[0], tile[1]) < minDistance)
    358370            {
     
    370382}
    371383
    372384
    373 ////////////////
    374 //
    375 //  Base terrain generation functionality
    376 //
    377 ////////////////
     385/**
     386 *  Base terrain generation functionality
     387 */
    378388
    379389function setBaseTerrainDiamondSquare(minHeight, maxHeight, smoothness, initialHeightmap, heightmap)
    380390{
     
    395405        var newHeightmap = [];
    396406        var oldWidth = initialHeightmap.length;
    397407        // Square
    398         for (var x = 0; x < 2 * oldWidth - 1; x++)
     408        for (var x = 0; x < 2 * oldWidth - 1; ++x)
    399409        {
    400410            newHeightmap.push([]);
    401             for (var y = 0; y < 2 * oldWidth - 1; y++)
     411            for (var y = 0; y < 2 * oldWidth - 1; ++y)
    402412            {
    403413                if (x % 2 === 0 && y % 2 === 0) // Old tile
    404414                    newHeightmap[x].push(initialHeightmap[x/2][y/2]);
     
    412422            }
    413423        }
    414424        // Diamond
    415         for (var x = 0; x < 2 * oldWidth - 1; x++)
     425        for (var x = 0; x < 2 * oldWidth - 1; ++x)
    416426        {
    417             for (var y = 0; y < 2 * oldWidth - 1; y++)
     427            for (var y = 0; y < 2 * oldWidth - 1; ++y)
    418428            {
    419429                if (newHeightmap[x][y] === undefined)
    420430                {
     
    452462   
    453463    // Cut initialHeightmap to fit target width
    454464    var shift = [floor((newHeightmap.length - heightmap.length) / 2), floor((newHeightmap[0].length - heightmap[0].length) / 2)];
    455     for (var x = 0; x < heightmap.length; x++)
    456         for (var y = 0; y < heightmap[0].length; y++)
     465    for (var x = 0; x < heightmap.length; ++x)
     466        for (var y = 0; y < heightmap[0].length; ++y)
    457467            heightmap[x][y] = newHeightmap[x][y];
    458468}
    459469
    460470
    461 ////////////////
    462 //
    463 //  Terrain erosion functionality
    464 //
    465 ////////////////
    466 
     471/**
     472 *  Terrain erosion functionality
     473 */
    467474function decayErrodeHeightmap(strength, heightmap)
    468475{
    469476    strength = (strength || 0.9); // 0 to 1
     
    474481    var map = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]; // smoother
    475482    var max_x = heightmap.length;
    476483    var max_y = heightmap[0].length;
    477     for (var x = 0; x < max_x; x++)
    478         for (var y = 0; y < max_y; y++)
    479             for (var i = 0; i < map.length; i++)
     484    for (var x = 0; x < max_x; ++x)
     485        for (var y = 0; y < max_y; ++y)
     486            for (var i = 0; i < map.length; ++i)
    480487                heightmap[x][y] += strength / map.length * (referenceHeightmap[(x + map[i][0] + max_x) % max_x][(y + map[i][1] + max_y) % max_y] - referenceHeightmap[x][y]); // Not entirely sure if scaling with map.length is perfect but tested values seam to indicate it is
    481488}
    482489
     
    490497    heightmap = (heightmap || g_Map.height);
    491498   
    492499    var heightmapWin = [];
    493     for (var wx = 0; wx < 2 * dx + 1; wx++)
     500    for (var wx = 0; wx < 2 * dx + 1; ++wx)
    494501    {
    495502        heightmapWin.push([]);
    496         for (var wy = 0; wy < 2 * dy + 1; wy++)
     503        for (var wy = 0; wy < 2 * dy + 1; ++wy)
    497504        {
    498505            var actualX = x - dx + wx;
    499506            var actualY = y - dy + wy;
     
    503510                heightmapWin[wx].push(targetHeight);
    504511        }
    505512    }
    506     for (var wx = 0; wx < 2 * dx + 1; wx++)
     513    for (var wx = 0; wx < 2 * dx + 1; ++wx)
    507514    {
    508         for (var wy = 0; wy < 2 * dy + 1; wy++)
     515        for (var wy = 0; wy < 2 * dy + 1; ++wy)
    509516        {
    510517            var actualX = x - dx + wx;
    511518            var actualY = y - dy + wy;
     
    522529}
    523530
    524531
    525 ////////////////
    526 //
    527 //  Actually do stuff
    528 //
    529 ////////////////
     532/**
     533 *  Actually do stuff
     534 */
    530535
    531 ////////////////
    532 // Set height limits and water level by map size
    533 ////////////////
     536/**
     537 * Set height limits and water level by map size
     538 */
    534539
    535 // Set target min and max height depending on map size to make average steepness about the same on all map sizes
     540/**
     541 * Set target min and max height depending on map size to make average steepness about the same on all map sizes
     542 */
    536543var heightRange = {'min': MIN_HEIGHT * (g_Map.size + 512) / 8192, 'max': MAX_HEIGHT * (g_Map.size + 512) / 8192, 'avg': (MIN_HEIGHT * (g_Map.size + 512) +MAX_HEIGHT * (g_Map.size + 512))/16384};
    537544
    538 // Set average water coverage
     545/**
     546 * Set average water coverage
     547 */
    539548var averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values
    540549var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min);
    541550var waterHeightAdjusted = waterHeight + MIN_HEIGHT;
    542551setWaterHeight(waterHeight);
    543552
    544 ////////////////
    545 // Generate base terrain
    546 ////////////////
     553/**
     554 * Generate base terrain
     555 */
    547556
    548 // Setting a 3x3 Grid as initial heightmap
     557/**
     558 * Setting a 3x3 Grid as initial heightmap
     559 */
    549560var initialReliefmap = [[heightRange.max, heightRange.max, heightRange.max], [heightRange.max, heightRange.min, heightRange.max], [heightRange.max, heightRange.max, heightRange.max]];
    550561
    551562setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, 0.5, initialReliefmap, g_Map.height);
    552 // Apply simple erosion
    553 for (var i = 0; i < 5; i++)
     563/**
     564 * Apply simple erosion
     565 */
     566for (var i = 0; i < 5; ++i)
    554567    decayErrodeHeightmap(0.5);
    555568rescaleHeightmap(heightRange.min, heightRange.max);
    556569
    557570RMS.SetProgress(50);
    558571
    559 //////////
    560 // Setup height limit
    561 //////////
     572/**
     573 * Setup height limit
     574 */
    562575
    563 // Height presets
     576/**
     577 * Height presets
     578 */
    564579var heighLimits = [
    565580    heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water
    566581    heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), // 1 Medium Water
     
    574589    waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border
    575590    waterHeightAdjusted + (heightRange.max - waterHeightAdjusted)]; // 10 Hilltop
    576591
    577 //////////
    578 // Place start locations and apply terrain texture and decorative props
    579 //////////
     592/**
     593 * Place start locations and apply terrain texture and decorative props
     594 */
    580595
    581 // Get start locations
     596/**
     597 * Get start locations
     598 */
    582599var startLocations = getStartLocationsByHeightmap({'min': heighLimits[4], 'max': heighLimits[5]});
    583600var playerHeight = (heighLimits[4] + heighLimits[5]) / 2;
    584601
    585 for (var i=0; i < numPlayers; i++)
     602for (var i=0; i < numPlayers; ++i)
    586603{
    587604    playerAngle[i] = (playerAngleStart + i*playerAngleAddAvrg + randFloat(0, playerAngleMaxOff))%(2*PI);
    588605    var x = round(mapCenterX + randFloat(minPlayerRadius, maxPlayerRadius)*cos(playerAngle[i]));
     
    604621    var distToSL = 15;
    605622    var resStartAngle = playerAngle[i] + PI;
    606623    var resAddAngle = 2*PI / startingResources.length;
    607     for (var rIndex = 0; rIndex < startingResources.length; rIndex++)
     624    for (var rIndex = 0; rIndex < startingResources.length; ++rIndex)
    608625    {
    609626        var angleOff = randFloat(-resAddAngle/2, resAddAngle/2);
    610627        var placeX = x + distToSL*cos(resStartAngle + rIndex*resAddAngle + angleOff);
     
    614631    }
    615632}
    616633
    617 // Add further stone and metal mines
     634/**
     635 * Add further stone and metal mines
     636 */
    618637derivateEntitiesByHeight({'min': heighLimits[3], 'max': ((heighLimits[4]+heighLimits[3])/2)}, startLocations);
    619638derivateEntitiesByHeight({'min': ((heighLimits[5]+heighLimits[6])/2), 'max': heighLimits[7]}, startLocations);
    620639
    621640RMS.SetProgress(50);
    622641
    623 //place water & open terrain textures and assign TileClasses
     642/**
     643 * place water & open terrain textures and assign TileClasses
     644 */
    624645log("Painting textures...");
    625646var placer = new HeightPlacer(heighLimits[2], (heighLimits[3]+heighLimits[2])/2);
    626647var painter = new LayeredPainter([terrainBase, terrainBaseBorder], [5]);
     
    634655
    635656RMS.SetProgress(60);
    636657
    637 // Place paths
     658/**
     659 * Place paths
     660 */
    638661log("Placing paths...");
    639662var doublePaths = true;
    640663if (numPlayers > 4)
     
    644667    var maxI = numPlayers+1;
    645668else
    646669    var maxI = numPlayers;
    647 for (var i = 0; i < maxI; i++)
     670for (var i = 0; i < maxI; ++i)
    648671{
    649672    if (doublePaths === true)
    650673        var minJ = 0;
    651674    else
    652675        var minJ = i+1;
    653     for (var j = minJ; j < numPlayers+1; j++)
     676    for (var j = minJ; j < numPlayers+1; ++j)
    654677    {
    655678        // Setup start and target coordinates
    656679        if (i < numPlayers)
     
    700723            }
    701724            if (getDistance(x, z, targetX, targetZ) < pathSucsessRadius)
    702725                targetReached = true;
    703             tries++;
     726            ++tries;
    704727
    705728        }
    706729    }
     
    708731
    709732RMS.SetProgress(75);
    710733
    711 //create general decoration
     734/**
     735 *create general decoration
     736 */
    712737log("Creating decoration...");
    713738createDecoration
    714739(
     
    730755
    731756RMS.SetProgress(80);
    732757
    733 //create fish
     758/**
     759 *create fish
     760 */
    734761log("Growing fish...");
    735762createFood
    736763(
     
    745772
    746773RMS.SetProgress(85);
    747774
    748 // create reeds
     775/**
     776 * create reeds
     777 */
    749778log("Planting reeds...");
    750779var types = [aReeds];   // some variation
    751780for (var i = 0; i < types.length; ++i)
     
    759788
    760789RMS.SetProgress(90);
    761790
    762 // place trees
     791/**
     792 * place trees
     793 */
    763794log("Planting trees...");
    764 for (var x = 0; x < mapSize; x++)
     795for (var x = 0; x < mapSize; ++x)
    765796{
    766     for (var z = 0;z < mapSize;z++)
     797    for (var z = 0; z < mapSize; ++z)
    767798    {
    768799        // Some variables
    769800        var radius = Math.pow(Math.pow(mapCenterX - x - 0.5, 2) + Math.pow(mapCenterZ - z - 0.5, 2), 1/2); // The 0.5 is a correction for the entities placed on the center of tiles
    770801        var minDistToSL = mapSize;
    771         for (var i=0; i < numPlayers; i++)
     802        for (var i=0; i < numPlayers; ++i)
    772803            minDistToSL = min(minDistToSL, getDistance(playerStartLocX[i], playerStartLocZ[i], x, z));
    773804        // Woods tile based
    774805        var tDensFactSL = max(min((minDistToSL - baseRadius) / baseRadius, 1), 0);
     
    793824
    794825RMS.SetProgress(100);
    795826
    796 // Export map data
     827/**
     828 * Export map data
     829 */
    797830ExportMap();
  • binaries/data/mods/public/maps/random/wall_demo.js

     
    11RMS.LoadLibrary("rmgen");
    22
    3 // initialize map
     3/**
     4 * initialize map
     5 */
    46log("Initializing map...");
    57InitMap();
    68
    7 
    8 // General map setup
     9/**
     10 * General map setup
     11 */
    912var mapSize = getMapSize();
    1013var mapCenterX = mapSize/2;
    1114var mapCenterY = mapSize/2;
    1215const BUILDING_ANlE = -PI/4;
    1316
    1417
    15 ////////////////////////////////////////
    16 // Demonstration code for wall placement
    17 ////////////////////////////////////////
     18/**
     19 * Demonstration code for wall placement
     20 *
     21 *
     22 *Some general notes to the arguments:
     23 *
     24 * First all the place functions take the coordinates needed to place the wall
     25 * X and Y coordinate are taken in seperate arguments like in placeObject
     26 * Their meaning differs for different placement methods but are mainly self explanatory
     27 * placeLinearWall takes 4 arguments here (2 coordinates) for startX, startY, targetX and targetY
     28 *
     29 * The next argument is always the 'wall' definition, an array of wall element type strings in most cases
     30 * That looks like ['endLeft', 'wall', 'tower', 'wall', 'endRight', 'entry', 'endLeft', 'wall', 'tower', 'wall', 'endRight']
     31 * For placeCircularWall and placeLinearWall only wall parts are needed like: ['tower', 'wall']
     32 * They will automatically end with the first wall element if that makes sense (e.g. the wall is not closed)
     33 * NOTE: They take further optional arguments to adjust this behaviour (See the wall_builder.js for that)
     34 * placeFortress just takes a fortress type string that includes the wall definition
     35 * The default fortress type strings are made for easy placement of predefined fortresses
     36 * They are chosen like map sizes: 'tiny', 'small', 'medium', 'normal', 'large', 'veryLarge' and 'giant'
     37 * NOTE: To place a custom fortress use placeCustomFortress instead
     38 * It takes an instance of the Fortress class instead of the default fortress type strings
     39 *
     40 * The next argument is always the wall style string
     41 * Wall styles are chosen by strings so the civ strings got by getCivCode() can be used
     42 * Other styles may be present as well but besides the civ styles only 'palisades' includes all wall element types (yet)
     43 *
     44 * The next argument is always the index of the player that owns the wall.
     45 * 0 is Gaia, 1 is Player 1 (default color blue), 2 is Player 2 (default color red), ...
     46 *
     47 * The next argument is an angle defining the orientation of the wall
     48 * placeLinearWall does not need an angle since it's defined by startX/Y and targetX/Y
     49 * Orientation works like the angle argument in placeObject
     50 * 0 is always right (towards positive X)
     51 * Raising the angle will rotate the wall counter-clockwise (mathmatical positive in default 2D)
     52 * PI/2 faces top (positive Y)
     53 * Orientation might be a little confusing for placeWall since it defines where the wall has its 'front' or 'outside' not the direction it will be build to.
     54 * It's because all other methods work like that and it's intuitive there
     55 * That means the walls outside by default (orientation = 0) faces positive X and (without bending wall elements) will be build towards positive Y
     56 *
     57 * Some other arguments are taken but all of them are optional and in most cases not needed
     58 * One example is maxAngle for placeCircularWall that defines how far the wall will circumvent the center. Default is 2*PI which makes a full circle
     59 */
    1860
    19 // Some general notes to the arguments:
    20 
    21 // First all the place functions take the coordinates needed to place the wall
    22 // X and Y coordinate are taken in seperate arguments like in placeObject
    23 // Their meaning differs for different placement methods but are mainly self explanatory
    24 // placeLinearWall takes 4 arguments here (2 coordinates) for startX, startY, targetX and targetY
    25 
    26 // The next argument is always the 'wall' definition, an array of wall element type strings in most cases
    27 // That looks like ['endLeft', 'wall', 'tower', 'wall', 'endRight', 'entry', 'endLeft', 'wall', 'tower', 'wall', 'endRight']
    28 // For placeCircularWall and placeLinearWall only wall parts are needed like: ['tower', 'wall']
    29 // They will automatically end with the first wall element if that makes sense (e.g. the wall is not closed)
    30 // NOTE: They take further optional arguments to adjust this behaviour (See the wall_builder.js for that)
    31 // placeFortress just takes a fortress type string that includes the wall definition
    32 // The default fortress type strings are made for easy placement of predefined fortresses
    33 // They are chosen like map sizes: 'tiny', 'small', 'medium', 'normal', 'large', 'veryLarge' and 'giant'
    34 // NOTE: To place a custom fortress use placeCustomFortress instead
    35 // It takes an instance of the Fortress class instead of the default fortress type strings
    36 
    37 // The next argument is always the wall style string
    38 // Wall styles are chosen by strings so the civ strings got by getCivCode() can be used
    39 // Other styles may be present as well but besides the civ styles only 'palisades' includes all wall element types (yet)
    40 
    41 // The next argument is always the index of the player that owns the wall.
    42 // 0 is Gaia, 1 is Player 1 (default color blue), 2 is Player 2 (default color red), ...
    43 
    44 // The next argument is an angle defining the orientation of the wall
    45 // placeLinearWall does not need an angle since it's defined by startX/Y and targetX/Y
    46 // Orientation works like the angle argument in placeObject
    47 // 0 is always right (towards positive X)
    48 // Raising the angle will rotate the wall counter-clockwise (mathmatical positive in default 2D)
    49 // PI/2 faces top (positive Y)
    50 // Orientation might be a little confusing for placeWall since it defines where the wall has its 'front' or 'outside' not the direction it will be build to.
    51 // It's because all other methods work like that and it's intuitive there
    52 // That means the walls outside by default (orientation = 0) faces positive X and (without bending wall elements) will be build towards positive Y
    53 
    54 // Some other arguments are taken but all of them are optional and in most cases not needed
    55 // One example is maxAngle for placeCircularWall that defines how far the wall will circumvent the center. Default is 2*PI which makes a full circle
    56 
    57 
    58 // General wall placement setup
     61/**
     62 * General wall placement setup
     63 */
    5964const distToMapBorder = 5;
    6065const distToOtherWalls = 10;
    6166var buildableMapSize = mapSize - 2 * distToMapBorder;
    6267var actualX = distToMapBorder;
    6368var actualY = distToMapBorder;
    64 // Wall styles are chosen by strings so the civ strings got by getCivCode() can be used
    65 // Other styles may be present as well but besides the civ styles only 'palisades' includes all wall element types (yet)
    66 const wallStyleList = ["athen", "brit", "cart", "gaul", "iber", "mace", "maur", "pers", "ptol", "rome", "sele", "spart", "rome_siege", "palisades"];
     69var wallStyleList = g_WallStyleList;
    6770
    68 
    69 ////////////////////////////////////////
    70 // Custom wall placement (element based)
    71 ////////////////////////////////////////
    72 var wall = ['endLeft', 'wallLong', 'tower', 'wall', 'outpost', 'wall', 'cornerOut', 'wall', 'cornerIn', 'wall', 'house', 'endRight', 'entryTower', 'endLeft', 'wallShort', 'barracks', 'gate', 'tower', 'wall', 'wallFort', 'wall', 'endRight'];
    73 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
     71/**
     72 * Custom wall placement (element based)
     73 */
     74var 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'];
     75for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex)
    7476{
    7577    var startX = actualX + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the first wall element
    7678    var startY = actualY; // Y coordinate of the first wall element
    77     var style = wallStyleList[styleIndex]; // // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
    78     var orientation = styleIndex * PI/64; // Orientation of the first wall element. 0 means 'outside' or 'front' is right (positive X, like object placement)
     79    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
     80    var orientation = PI/16 * sin(styleIndex * PI/4); // Orientation of the first wall element. 0 means 'outside' or 'front' is right (positive X, like object placement in Atlas)
    7981    // That means the wall will be build towards top (positive Y) if no corners are used
    8082    var playerId = 0; // Owner of the wall (like in placeObject). 0 is Gaia, 1 is Player 1 (default color blue), ...
    81     placeWall(startX, startY, wall, style, playerId, orientation); // Actually placing the wall
     83    placeWall(startX, startY, wall, style, playerId, orientation); // Actually place the wall
    8284}
    8385actualX = distToMapBorder; // Reset actualX
    8486actualY += 80 + distToOtherWalls; // Increase actualY for next wall placement method
    8587
    86 //////////////////////////////////////////////////////////////
    87 // Default fortress placement (chosen by fortress type string)
    88 //////////////////////////////////////////////////////////////
     88
     89/**
     90 * Default fortress placement (chosen by fortress type string)
     91 */
    8992var fortressRadius = 15; // The space the fortresses take in average. Just for design of this map
    90 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
     93for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex)
    9194{
    9295    var centerX = actualX + fortressRadius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the fortress
    9396    var centerY = actualY + fortressRadius; // Y coordinate of the center of the fortress
     
    99102    placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress
    100103}
    101104actualX = distToMapBorder; // Reset actualX
    102 actualY += 2 * fortressRadius + 2 * distToOtherWalls; // Increase actualY for next wall placement method
     105actualY += 2 * fortressRadius + distToOtherWalls; // Increase actualY for next wall placement method
    103106
    104 //////////////////////////
    105 // Circular wall placement
    106 //////////////////////////
    107 // NOTE: Don't use bending wall elements like corners here!
     107/**
     108 * 'generic' fortress placement (iberian wall circuit code)
     109 */
    108110var radius = min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall circle
     111for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex)
     112{
     113    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the fortress
     114    var centerY = actualY + radius; // Y coordinate of the center of the fortress
     115    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
     116    var playerId = 0; // Owner of the wall. 0 is Gaia, 1 is Player 1 (default color blue), ...
     117    placeGenericFortress(centerX, centerY, radius, playerId, style); // Actually place the fortress
     118    placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress
     119}
     120actualX = distToMapBorder; // Reset actualX
     121actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
     122
     123/**
     124 * Circular wall placement
     125 *
     126 * NOTE: Don't use bending wall elements like corners here!
     127 */
     128var radius = min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall circle
    109129var centerY = actualY + radius; // Y coordinate of the center of the wall circle
    110130var orientation = 0; // Where the wall circle will be open if maxAngle < 2*PI, see below. Otherwise where the first wall element will be placed
    111 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
     131for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex)
    112132{
    113133    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle
    114134    var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
    115     var wallPart = ['tower', 'wall', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall']
     135    var wallPart = ['tower', 'medium', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall']
    116136    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
    117137    var maxAngle = PI/2 * (styleIndex%3 + 2); // How far the wall should circumvent the center
    118138    placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle); // Actually placing the wall
     
    122142actualX = distToMapBorder; // Reset actualX
    123143actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
    124144
    125 ///////////////////////////
    126 // Polygonal wall placement
    127 ///////////////////////////
    128 // NOTE: Don't use bending wall elements like corners here!
     145/**
     146 * Regular Polygonal wall placement
     147 *
     148 * NOTE: Don't use bending wall elements like corners here!
     149 */
    129150var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons
    130151var centerY = actualY + radius; // Y coordinate of the center of the wall polygon
    131152var orientation = 0; // Where the wall circle will be open if ???, see below. Otherwise where the first wall will be placed
    132 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
     153for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex)
    133154{
    134155    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle
    135156    var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
    136157    var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon
    137     var wallPart = ['wall', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall']
     158    var wallPart = ['medium', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall']
    138159    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
    139160    var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have
    140161    var skipFirstWall = true; // If the wall should be open towards orientation
     
    145166actualX = distToMapBorder; // Reset actualX
    146167actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
    147168
    148 ////////////////////////
    149 // Linear wall placement
    150 ////////////////////////
    151 // NOTE: Don't use bending wall elements like corners here!
     169/**
     170 * Irregular Polygonal wall placement
     171 *
     172 * NOTE: Don't use bending wall elements like corners here!
     173 */
     174var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons
     175var centerY = actualY + radius; // Y coordinate of the center of the wall polygon
     176var orientation = 0; // Where the wall circle will be open if ???, see below. Otherwise where the first wall will be placed
     177for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex)
     178{
     179    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle
     180    var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
     181    var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon
     182    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
     183    var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have
     184    var skipFirstWall = true; // If the wall should be open towards orientation
     185    placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, undefined, skipFirstWall);
     186    placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the wall circle
     187    orientation += PI/16; // Increasing orientation to see how rotation works (like for object placement)
     188}
     189actualX = distToMapBorder; // Reset actualX
     190actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
     191
     192/**
     193 * Linear wall placement
     194 *
     195 * NOTE: Don't use bending wall elements like corners here!
     196 */
    152197var maxWallLength = (mapSize - actualY - distToMapBorder - distToOtherWalls); // Just for this maps design. How long the longest wall will be
    153198var numWallsPerStyle = floor(buildableMapSize / distToOtherWalls / wallStyleList.length); // Just for this maps design. How many walls of the same style will be placed
    154 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
     199for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex)
    155200{
    156     for (var wallIndex = 0; wallIndex < numWallsPerStyle; wallIndex++)
     201    for (var wallIndex = 0; wallIndex < numWallsPerStyle; ++wallIndex)
    157202    {
    158         var startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * distToOtherWalls; // X coordinate the wall will start from
     203        var startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize/wallStyleList.length/numWallsPerStyle; // X coordinate the wall will start from
    159204        var startY = actualY; // Y coordinate the wall will start from
    160205        var endX = startX; // X coordinate the wall will end
    161206        var endY = actualY + (wallIndex + 1) * maxWallLength/numWallsPerStyle; // Y coordinate the wall will end
    162207        var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
    163         var wallPart = ['tower', 'wall']; // List of wall elements the wall will be build of
     208        var wallPart = ['tower', 'medium']; // List of wall elements the wall will be build of
    164209        var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
    165210        placeLinearWall(startX, startY, endX, endY, wallPart, style, playerId); // Actually placing the wall
    166211        // placeObject(startX, startY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall begins
    167212        // placeObject(endX, endY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall ends
    168213    }
    169214}
    170 actualX = distToMapBorder; // Reset actualX
    171 actualY += maxWallLength + distToOtherWalls; // Increase actualY for next wall placement method
    172215
    173 
    174 // Export map data
     216/**
     217 * Export map data
     218 */
    175219ExportMap();
  • binaries/data/mods/public/maps/random/wall_demo.json

     
    22    "settings" : {
    33        "Name" : "Wall Demo",
    44        "Script" : "wall_demo.js",
    5         "Description" : "A demonstration of wall placement methods/code in random maps. Very large map size is recommended.",
     5        "Description" : "A demonstration of wall placement methods/code in random maps. Giant map size is recommended!",
    66        "BaseTerrain" : ["grass1"],
    77        "BaseHeight" : 0,
    88        "Keywords": ["demo"],
    99        "CircularMap" : false,
     10        "RevealMap": true,
    1011        "XXXXXX" : "Optionally define other things here, like we would for a scenario"
    1112    }
    1213}
     14 No newline at end of file
  • binaries/data/mods/public/simulation/components/WallPiece.js

     
    66    "</a:example>" +
    77    "<element name='Length'>" +
    88        "<ref name='nonNegativeDecimal'/>" +
    9     "</element>";
     9    "</element>" +
     10    "<optional>" +
     11        "<element name='Orientation'>" +
     12            "<ref name='nonNegativeDecimal'/>" +
     13        "</element>" +
     14    "</optional>" +
     15    "<optional>" +
     16        "<element name='Indent'>" +
     17            "<data type='decimal'/>" +
     18        "</element>" +
     19    "</optional>" +
     20    "<optional>" +
     21        "<element name='Bend'>" +
     22            "<data type='decimal'/>" +
     23        "</element>" +
     24    "</optional>";
    1025
    1126
    1227WallPiece.prototype.Init = function()
  • binaries/data/mods/public/simulation/components/WallSet.js

     
    2121            "<element name='WallShort' a:help='Template name of the short wall segment'>" +
    2222                "<text/>" +
    2323            "</element>" +
     24            "<optional>" +
     25                "<element name='WallCurveQuarter'>" +
     26                    "<text/>" +
     27                "</element>" +
     28            "</optional>" +
     29            "<optional>" +
     30                "<element name='WallCurveEighth'>" +
     31                    "<text/>" +
     32                "</element>" +
     33            "</optional>" +
     34            "<optional>" +
     35                "<element name='WallEnd'>" +
     36                    "<text/>" +
     37                "</element>" +
     38            "</optional>" +
     39            "<optional>" +
     40                "<element name='Fort'>" +
     41                    "<text/>" +
     42                "</element>" +
     43            "</optional>" +
    2444        "</interleave>" +
    2545    "</element>" +
    2646    "<element name='MinTowerOverlap' a:help='Maximum fraction that wall segments are allowed to overlap towers, where 0 signifies no overlap and 1 full overlap'>" +
  • binaries/data/mods/public/simulation/data/civs/athen.json

     
    109109            "Special":"Train heroes and research technology pertaining to heroes."
    110110        }
    111111    ],
     112    "WallSets":
     113    [
     114        "other/wallset_palisade",
     115        "structures/athen_wallset_stone"
     116    ],
    112117    "StartEntities":
    113118    [
    114119        {
  • binaries/data/mods/public/simulation/data/civs/brit.json

     
    8787            "Special": ""
    8888        }
    8989    ],
     90    "WallSets":
     91    [
     92        "other/wallset_palisade",
     93        "structures/brit_wallset_stone"
     94    ],
    9095    "StartEntities":
    9196    [
    9297        {
  • binaries/data/mods/public/simulation/data/civs/cart.json

     
    112112            "Special":"Hire Iberian mercenaries."
    113113        }       
    114114    ],
     115    "WallSets":
     116    [
     117        "other/wallset_palisade",
     118        "structures/cart_wallset_stone"
     119    ],
    115120    "StartEntities":
    116121    [
    117122        {
  • binaries/data/mods/public/simulation/data/civs/gaul.json

     
    8787            "Special": ""
    8888        }
    8989    ],
     90    "WallSets":
     91    [
     92        "other/wallset_palisade",
     93        "structures/gaul_wallset_stone"
     94    ],
    9095    "StartEntities":
    9196    [
    9297        {
  • binaries/data/mods/public/simulation/data/civs/iber.json

     
    8585            "Special": "Defensive Aura - Gives all Iberian units and buildings within vision range of the monument a 10-15% attack boost. Build Limit: Only 5 may be built per map."
    8686        }
    8787    ],
     88    "WallSets":
     89    [
     90        "other/wallset_palisade",
     91        "structures/iber_wallset_stone"
     92       
     93    ],
    8894    "StartEntities":
    8995    [
    9096        {
  • binaries/data/mods/public/simulation/data/civs/mace.json

     
    114114            "Special":"Constructs and upgrades all Macedonian siege engines."
    115115        }
    116116    ],
     117    "WallSets":
     118    [
     119        "other/wallset_palisade",
     120        "structures/mace_wallset_stone"
     121       
     122    ],
    117123    "StartEntities":
    118124    [
    119125        {
  • binaries/data/mods/public/simulation/data/civs/maur.json

     
    9494            "Special":"Contentment: +10% Health and +10% resource gathering rates for all citizens and allied citizens within its range. Can be built anywhere except in enemy territory. Max Built: 10."
    9595        }
    9696    ],
     97    "WallSets":
     98    [
     99        "other/wallset_palisade",
     100        "structures/maur_wallset_stone"
     101       
     102    ],
    97103    "StartEntities":
    98104    [
    99105        {
  • binaries/data/mods/public/simulation/data/civs/pers.json

     
    104104            "Special": "Train heroes and Persian Immortals. Gives a slow trickle of all resources as 'Satrapy Tribute.'"
    105105        }
    106106    ],
     107    "WallSets":
     108    [
     109        "other/wallset_palisade",
     110        "structures/pers_wallset_stone"
     111       
     112    ],
    107113    "StartEntities":
    108114    [
    109115        {
  • binaries/data/mods/public/simulation/data/civs/ptol.json

     
    113113            "Special":"When built along the shoreline, removes shroud of darkness over all the water, revealing all the coast lines on the map. Limit: 1."
    114114        }
    115115    ],
     116    "WallSets":
     117    [
     118        "other/wallset_palisade",
     119        "structures/ptol_wallset_stone"
     120       
     121    ],
    116122    "StartEntities":
    117123    [
    118124        {
  • binaries/data/mods/public/simulation/data/civs/rome.json

     
    8989            "Special": "Can be built in neutral and enemy territory to strangle enemy towns."
    9090        }
    9191    ],
     92    "WallSets":
     93    [
     94        "structures/rome_wallset_stone",
     95        "structures/rome_wallset_siege"
     96       
     97    ],
    9298    "StartEntities":
    9399    [
    94100        {
  • binaries/data/mods/public/simulation/data/civs/sele.json

     
    114114            "Special":"This is the Seleucid expansion building, similar to Civic Centers for other factions. It is weaker and carries a smaller territory influence, but is cheaper and built faster."
    115115        }
    116116    ],
     117    "WallSets":
     118    [
     119        "other/wallset_palisade",
     120        "structures/sele_wallset_stone"
     121       
     122    ],
    117123    "StartEntities":
    118124    [
    119125        {
  • binaries/data/mods/public/simulation/data/civs/spart.json

     
    105105            "Special":"Train heroes and Spartiates and research technologies related to them."
    106106        }
    107107    ],
     108    "WallSets":
     109    [
     110        "other/wallset_palisade",
     111        "structures/spart_wallset_stone"
     112       
     113    ],
    108114    "StartEntities":
    109115    [
    110116        {
  • binaries/data/mods/public/simulation/templates/other/palisades_rocks_curve.xml

     
    2525  <VisualActor>
    2626    <Actor>props/special/palisade_rocks_curve.xml</Actor>
    2727  </VisualActor>
     28  <WallPiece>
     29    <Length>8.0</Length>
     30    <Orientation>0.75</Orientation>
     31    <Indent>2.8</Indent>
     32    <Bend>0.5</Bend>
     33  </WallPiece>
    2834</Entity>
  • binaries/data/mods/public/simulation/templates/other/palisades_rocks_end.xml

     
    2525  <VisualActor>
    2626    <Actor>props/special/palisade_rocks_end.xml</Actor>
    2727  </VisualActor>
     28  <WallPiece>
     29    <Length>0.8</Length>
     30    <Orientation>1.5</Orientation>
     31  </WallPiece>
    2832</Entity>
  • binaries/data/mods/public/simulation/templates/other/palisades_rocks_fort.xml

     
    88    <Icon>structures/palisade_fort.png</Icon>
    99    <Classes datatype="tokens">Palisade</Classes>
    1010  </Identity>
     11  <WallPiece>
     12    <Length>8.0</Length>
     13  </WallPiece>
    1114</Entity>
  • binaries/data/mods/public/simulation/templates/other/palisades_rocks_long.xml

     
    3939  </VisualActor>
    4040  <TerritoryInfluence disable=""/>
    4141  <WallPiece>
    42     <Length>11.0</Length>
     42    <Length>14.0</Length>
    4343  </WallPiece>
    4444</Entity>
  • binaries/data/mods/public/simulation/templates/other/palisades_rocks_medium.xml

     
    3838  </VisualActor>
    3939  <TerritoryInfluence disable=""/>
    4040  <WallPiece>
    41     <Length>8.0</Length>
     41    <Length>9.2</Length>
    4242  </WallPiece>
    4343</Entity>
  • binaries/data/mods/public/simulation/templates/other/palisades_rocks_short.xml

     
    3737    <FoundationActor>structures/fndn_1x1pal.xml</FoundationActor>
    3838  </VisualActor>
    3939  <WallPiece>
    40     <Length>4.0</Length>
     40    <Length>4.8</Length>
    4141  </WallPiece>
    4242</Entity>
  • binaries/data/mods/public/simulation/templates/other/wallset_palisade.xml

     
    1313    <Templates>
    1414      <Tower>other/palisades_rocks_tower</Tower>
    1515      <Gate>other/palisades_rocks_gate</Gate>
     16      <Fort>other/palisades_rocks_fort</Fort>
    1617      <WallLong>other/palisades_rocks_long</WallLong>
    1718      <WallMedium>other/palisades_rocks_medium</WallMedium>
    1819      <WallShort>other/palisades_rocks_short</WallShort>
     20      <WallCurveQuarter>other/palisades_rocks_curve</WallCurveQuarter>
     21      <WallEnd>other/palisades_rocks_end</WallEnd>
    1922    </Templates>
    2023  </WallSet>
    2124</Entity>
  • binaries/data/mods/public/simulation/templates/structures/athen_fortress.xml

     
    2525  <VisualActor>
    2626    <Actor>structures/athenians/fortress_up.xml</Actor>
    2727  </VisualActor>
     28  <WallPiece>
     29    <Length>24.0</Length>
     30    <Indent>7.6</Indent>
     31  </WallPiece>
    2832</Entity>
  • binaries/data/mods/public/simulation/templates/structures/athen_wall_gate.xml

     
    2020    <Actor>structures/hellenes/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>38.0</Length>
     23    <Length>35.4</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/athen_wall_long.xml

     
    1717    <Actor>structures/hellenes/wall_long.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>37.0</Length>
     20    <Length>36.2</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/athen_wall_medium.xml

     
    1717    <Actor>structures/hellenes/wall_medium.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>24.0</Length>
     20    <Length>24.2</Length>
    2121  </WallPiece>
    22 </Entity>
    23  No newline at end of file
     22</Entity>
  • binaries/data/mods/public/simulation/templates/structures/athen_wall_short.xml

     
    1717    <Actor>structures/hellenes/wall_short.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>13.0</Length>
     20    <Length>12.3</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/athen_wall_tower.xml

     
    1616    <Actor>structures/hellenes/wall_tower.xml</Actor>
    1717  </VisualActor>
    1818  <WallPiece>
    19     <Length>7.5</Length>
     19    <Length>7.1</Length>
    2020  </WallPiece>
    21 </Entity>
    22  No newline at end of file
     21</Entity>
  • binaries/data/mods/public/simulation/templates/structures/brit_fortress.xml

     
    5454    <Actor>structures/britons/fortress_briton.xml</Actor>
    5555    <FoundationActor>structures/fndn_5x5.xml</FoundationActor>
    5656  </VisualActor>
     57  <WallPiece>
     58    <Length>28</Length>
     59  </WallPiece>
    5760</Entity>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_gate.xml

     
    2727    <Actor>structures/celts/wall_gate.xml</Actor>
    2828  </VisualActor>
    2929  <WallPiece>
    30     <Length>25.0</Length>
     30    <Length>37.0</Length>
    3131  </WallPiece>
    3232</Entity>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_long.xml

     
    3636    <Actor>structures/celts/wall_long.xml</Actor>
    3737  </VisualActor>
    3838  <WallPiece>
    39     <Length>37.0</Length>
     39    <Length>36.6</Length>
    4040  </WallPiece>
    4141</Entity>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_medium.xml

     
    3333    <Actor>structures/celts/wall_medium.xml</Actor>
    3434  </VisualActor>
    3535  <WallPiece>
    36     <Length>25.0</Length>
     36    <Length>24.6</Length>
    3737  </WallPiece>
    3838</Entity>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_short.xml

     
    2020    <Actor>structures/celts/wall_short.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>13.0</Length>
     23    <Length>12.5</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/brit_wall_tower.xml

     
    2020    <Actor>structures/celts/wall_tower.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>9.0</Length>
     23    <Length>8.7</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/cart_fortress.xml

     
    3131  <VisualActor>
    3232    <Actor>structures/carthaginians/fortress.xml</Actor>
    3333  </VisualActor>
     34  <WallPiece>
     35    <Length>25.0</Length>
     36    <Indent>6.4</Indent>
     37  </WallPiece>
    3438</Entity>
  • binaries/data/mods/public/simulation/templates/structures/cart_wall_gate.xml

     
    2020    <Actor>structures/carthaginians/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>25.0</Length>
     23    <Length>43.8</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/cart_wall_long.xml

     
    3636    <Actor>structures/carthaginians/wall_long.xml</Actor>
    3737  </VisualActor>
    3838  <WallPiece>
    39     <Length>46.0</Length>
     39    <Length>43.7</Length>
    4040  </WallPiece>
    4141</Entity>
  • binaries/data/mods/public/simulation/templates/structures/cart_wall_medium.xml

     
    3030    <Actor>structures/carthaginians/wall_medium.xml</Actor>
    3131  </VisualActor>
    3232  <WallPiece>
    33     <Length>30.0</Length>
     33    <Length>29.3</Length>
    3434  </WallPiece>
    3535</Entity>
  • binaries/data/mods/public/simulation/templates/structures/cart_wall_short.xml

     
    1717    <Actor>structures/carthaginians/wall_short.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>16.0</Length>
     20    <Length>14.7</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/cart_wall_tower.xml

     
    2020    <FoundationActor>structures/fndn_3x3.xml</FoundationActor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>11.0</Length>
     23    <Length>11.8</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/gaul_fortress.xml

     
    3434  <VisualActor>
    3535    <Actor>structures/gauls/fortress_gallic.xml</Actor>
    3636  </VisualActor>
     37  <WallPiece>
     38    <Length>16.8</Length>
     39    <Indent>5.8</Indent>
     40  </WallPiece>
    3741</Entity>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_gate.xml

     
    2727    <Actor>structures/celts/wall_gate.xml</Actor>
    2828  </VisualActor>
    2929  <WallPiece>
    30     <Length>25.0</Length>
     30    <Length>37.0</Length>
    3131  </WallPiece>
    3232</Entity>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_long.xml

     
    3636    <Actor>structures/celts/wall_long.xml</Actor>
    3737  </VisualActor>
    3838  <WallPiece>
    39     <Length>37.0</Length>
     39    <Length>36.6</Length>
    4040  </WallPiece>
    4141</Entity>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_medium.xml

     
    3333    <Actor>structures/celts/wall_medium.xml</Actor>
    3434  </VisualActor>
    3535  <WallPiece>
    36     <Length>25.0</Length>
     36    <Length>24.6</Length>
    3737  </WallPiece>
    3838</Entity>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_short.xml

     
    2020    <Actor>structures/celts/wall_short.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>13.0</Length>
     23    <Length>12.6</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/gaul_wall_tower.xml

     
    2020    <Actor>structures/celts/wall_tower.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>9.0</Length>
     23    <Length>8.7</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/iber_fortress.xml

     
    3737  <VisualActor>
    3838    <Actor>structures/iberians/fortress.xml</Actor>
    3939  </VisualActor>
     40  <WallPiece>
     41    <Length>24.5</Length>
     42  </WallPiece>
    4043</Entity>
  • binaries/data/mods/public/simulation/templates/structures/iber_wall_long.xml

     
    3636    <Actor>structures/iberians/wall_long.xml</Actor>
    3737  </VisualActor>
    3838  <WallPiece>
    39     <Length>36.0</Length>
     39    <Length>36.4</Length>
    4040  </WallPiece>
    4141</Entity>
  • binaries/data/mods/public/simulation/templates/structures/iber_wall_medium.xml

     
    3333    <Actor>structures/iberians/wall_medium.xml</Actor>
    3434  </VisualActor>
    3535  <WallPiece>
    36     <Length>24.0</Length>
     36    <Length>24.4</Length>
    3737  </WallPiece>
    3838</Entity>
  • binaries/data/mods/public/simulation/templates/structures/iber_wall_short.xml

     
    2020    <Actor>structures/iberians/wall_short.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>12.0</Length>
     23    <Length>12.4</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/iber_wall_tower.xml

     
    2121    <Actor>structures/iberians/wall_tower.xml</Actor>
    2222  </VisualActor>
    2323  <WallPiece>
    24     <Length>10</Length>
     24    <Length>10.8</Length>
    2525  </WallPiece>
    2626</Entity>
  • binaries/data/mods/public/simulation/templates/structures/mace_fortress.xml

     
    4040  <VisualActor>
    4141    <Actor>structures/macedonians/fortress_up.xml</Actor>
    4242  </VisualActor>
     43  <WallPiece>
     44    <Length>24.0</Length>
     45    <Indent>7.6</Indent>
     46  </WallPiece>
    4347</Entity>
  • binaries/data/mods/public/simulation/templates/structures/mace_wall_gate.xml

     
    2020    <Actor>structures/hellenes/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>38.0</Length>
     23    <Length>35.4</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/mace_wall_long.xml

     
    1717    <Actor>structures/hellenes/wall_long.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>37.0</Length>
     20    <Length>36.2</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/mace_wall_medium.xml

     
    1717    <Actor>structures/hellenes/wall_medium.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>24.0</Length>
     20    <Length>24.2</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/mace_wall_short.xml

     
    1717    <Actor>structures/hellenes/wall_short.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>13.0</Length>
     20    <Length>12.3</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/mace_wall_tower.xml

     
    1616    <Actor>structures/hellenes/wall_tower.xml</Actor>
    1717  </VisualActor>
    1818  <WallPiece>
    19     <Length>7.5</Length>
     19    <Length>7.1</Length>
    2020  </WallPiece>
    21 </Entity>
    22  No newline at end of file
     21</Entity>
  • binaries/data/mods/public/simulation/templates/structures/maur_fortress.xml

     
    2828  <VisualActor>
    2929    <Actor>structures/mauryans/fortress.xml</Actor>
    3030  </VisualActor>
     31  <WallPiece>
     32    <Length>22.0</Length>
     33  </WallPiece>
    3134</Entity>
  • binaries/data/mods/public/simulation/templates/structures/maur_wall_gate.xml

     
    2020    <Actor>structures/mauryans/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>37.0</Length>
     23    <Length>36.7</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/maur_wall_long.xml

     
    4242    <Actor>structures/mauryans/wall_long.xml</Actor>
    4343  </VisualActor>
    4444  <WallPiece>
    45     <Length>35.0</Length>
     45    <Length>36.6</Length>
    4646  </WallPiece>
    4747</Entity>
  • binaries/data/mods/public/simulation/templates/structures/maur_wall_medium.xml

     
    3636    <Actor>structures/mauryans/wall_medium.xml</Actor>
    3737  </VisualActor>
    3838  <WallPiece>
    39     <Length>24.0</Length>
     39    <Length>24.4</Length>
    4040  </WallPiece>
    4141</Entity>
  • binaries/data/mods/public/simulation/templates/structures/maur_wall_short.xml

     
    2323    <Actor>structures/mauryans/wall_short.xml</Actor>
    2424  </VisualActor>
    2525  <WallPiece>
    26     <Length>13.0</Length>
     26    <Length>12.4</Length>
    2727  </WallPiece>
    2828</Entity>
  • binaries/data/mods/public/simulation/templates/structures/maur_wall_tower.xml

     
    2525    <Actor>structures/mauryans/wall_tower.xml</Actor>
    2626  </VisualActor>
    2727  <WallPiece>
    28     <Length>9.5</Length>
     28    <Length>7.8</Length>
    2929  </WallPiece>
    3030</Entity>
  • binaries/data/mods/public/simulation/templates/structures/pers_fortress.xml

     
    2020  <VisualActor>
    2121    <Actor>structures/persians/fortress.xml</Actor>
    2222  </VisualActor>
     23  <WallPiece>
     24    <Length>24.5</Length>
     25    <Indent>7.6</Indent>
     26  </WallPiece>
    2327</Entity>
  • binaries/data/mods/public/simulation/templates/structures/pers_wall_tower.xml

     
    1616    <Actor>structures/persians/wall_tower.xml</Actor>
    1717  </VisualActor>
    1818  <WallPiece>
    19     <Length>8.5</Length>
     19    <Length>7.5</Length>
    2020  </WallPiece>
    2121</Entity>
  • binaries/data/mods/public/simulation/templates/structures/ptol_fortress.xml

     
    3131  <VisualActor>
    3232    <Actor>structures/ptolemies/fortress.xml</Actor>
    3333  </VisualActor>
     34  <WallPiece>
     35    <Length>24.0</Length>
     36    <Indent>8.7</Indent>
     37  </WallPiece>
    3438</Entity>
  • binaries/data/mods/public/simulation/templates/structures/ptol_wall_gate.xml

     
    2020    <Actor>structures/ptolemies/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>38.0</Length>
     23    <Length>38.8</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/ptol_wall_medium.xml

     
    3030    <Actor>structures/ptolemies/wall_medium.xml</Actor>
    3131  </VisualActor>
    3232  <WallPiece>
    33     <Length>26.0</Length>
     33    <Length>25.0</Length>
    3434  </WallPiece>
    3535</Entity>
  • binaries/data/mods/public/simulation/templates/structures/ptol_wall_short.xml

     
    1717    <Actor>structures/ptolemies/wall_short.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>14.0</Length>
     20    <Length>16.0</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/ptol_wall_tower.xml

     
    1616    <Actor>structures/ptolemies/wall_tower.xml</Actor>
    1717  </VisualActor>
    1818  <WallPiece>
    19     <Length>10</Length>
     19    <Length>9.0</Length>
    2020  </WallPiece>
    21 </Entity>
    22  No newline at end of file
     21</Entity>
  • binaries/data/mods/public/simulation/templates/structures/ptol_wallset_stone.xml

     
    1414      <WallShort>structures/ptol_wall_short</WallShort>
    1515    </Templates>
    1616    <MaxTowerOverlap>0.90</MaxTowerOverlap>
    17     <MinTowerOverlap>0.05</MinTowerOverlap>
     17    <MinTowerOverlap>0.10</MinTowerOverlap>
    1818  </WallSet>
    1919</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml

     
    101101    <Actor>structures/romans/camp.xml</Actor>
    102102    <FoundationActor>structures/fndn_8x8.xml</FoundationActor>
    103103  </VisualActor>
     104  <WallPiece>
     105    <Length>29.5</Length>
     106    <Indent>8</Indent>
     107  </WallPiece>
    104108</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_fortress.xml

     
    2323  <VisualActor>
    2424    <Actor>structures/romans/fortress.xml</Actor>
    2525  </VisualActor>
     26  <WallPiece>
     27    <Length>25.0</Length>
     28    <Indent>8.4</Indent>
     29  </WallPiece>
    2630</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_tower.xml

     
    4343    <Actor>structures/romans/siege_wall_tower.xml</Actor>
    4444  </VisualActor>
    4545  <WallPiece>
    46     <Length>6.0</Length>
     46    <Length>5.5</Length>
    4747  </WallPiece>
    4848</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_wall_gate.xml

     
    2020    <Actor>structures/romans/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>37.0</Length>
     23    <Length>36.8</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_wall_long.xml

     
    3636    <Actor>structures/romans/wall_long.xml</Actor>
    3737  </VisualActor>
    3838  <WallPiece>
    39     <Length>37.0</Length>
     39    <Length>36.8</Length>
    4040  </WallPiece>
    4141</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_wall_medium.xml

     
    3333    <Actor>structures/romans/wall_medium.xml</Actor>
    3434  </VisualActor>
    3535  <WallPiece>
    36     <Length>25.0</Length>
     36    <Length>24.8</Length>
    3737  </WallPiece>
    3838</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_wall_short.xml

     
    2020    <Actor>structures/romans/wall_short.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>13.0</Length>
     23    <Length>12.9</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_wall_tower.xml

     
    1616    <Actor>structures/romans/wall_tower.xml</Actor>
    1717  </VisualActor>
    1818  <WallPiece>
    19     <Length>9.5</Length>
     19    <Length>10</Length>
    2020  </WallPiece>
    2121</Entity>
  • binaries/data/mods/public/simulation/templates/structures/rome_wallset_siege.xml

     
    1313    <Templates>
    1414      <Tower>structures/rome_siege_wall_tower</Tower>
    1515      <Gate>structures/rome_siege_wall_gate</Gate>
     16      <Fort>structures/rome_army_camp</Fort>
    1617      <WallLong>structures/rome_siege_wall_long</WallLong>
    1718      <WallMedium>structures/rome_siege_wall_medium</WallMedium>
    1819      <WallShort>structures/rome_siege_wall_short</WallShort>
  • binaries/data/mods/public/simulation/templates/structures/sele_fortress.xml

     
    3434  <VisualActor>
    3535    <Actor>structures/seleucids/fortress.xml</Actor>
    3636  </VisualActor>
     37  <WallPiece>
     38    <Length>23</Length>
     39    <Indent>7.8</Indent>
     40  </WallPiece>
    3741</Entity>
  • binaries/data/mods/public/simulation/templates/structures/sele_wall_gate.xml

     
    2020    <Actor>structures/hellenes/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>38.0</Length>
     23    <Length>35.4</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/sele_wall_long.xml

     
    1717    <Actor>structures/hellenes/wall_long.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>37.0</Length>
     20    <Length>36.2</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/sele_wall_medium.xml

     
    1717    <Actor>structures/hellenes/wall_medium.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>24.0</Length>
     20    <Length>24.2</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/sele_wall_short.xml

     
    1717    <Actor>structures/hellenes/wall_short.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>13.0</Length>
     20    <Length>12.3</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/sele_wall_tower.xml

     
    1616    <Actor>structures/hellenes/wall_tower.xml</Actor>
    1717  </VisualActor>
    1818  <WallPiece>
    19     <Length>7.5</Length>
     19    <Length>7.1</Length>
    2020  </WallPiece>
    21 </Entity>
    22  No newline at end of file
     21</Entity>
  • binaries/data/mods/public/simulation/templates/structures/spart_fortress.xml

     
    2525  <VisualActor>
    2626    <Actor>structures/spartans/fortress_up.xml</Actor>
    2727  </VisualActor>
     28  <WallPiece>
     29    <Length>24.0</Length>
     30    <Indent>7.6</Indent>
     31  </WallPiece>
    2832</Entity>
  • binaries/data/mods/public/simulation/templates/structures/spart_wall_gate.xml

     
    2020    <Actor>structures/hellenes/wall_gate.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>38.0</Length>
     23    <Length>35.4</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/spart_wall_long.xml

     
    1717    <Actor>structures/hellenes/wall_long.xml</Actor>
    1818  </VisualActor>
    1919  <WallPiece>
    20     <Length>37.0</Length>
     20    <Length>36.2</Length>
    2121  </WallPiece>
    2222</Entity>
  • binaries/data/mods/public/simulation/templates/structures/spart_wall_medium.xml

     
    2020    <Actor>structures/hellenes/wall_medium.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>24.0</Length>
     23    <Length>24.2</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/spart_wall_short.xml

     
    2020    <Actor>structures/hellenes/wall_short.xml</Actor>
    2121  </VisualActor>
    2222  <WallPiece>
    23     <Length>13.0</Length>
     23    <Length>12.3</Length>
    2424  </WallPiece>
    2525</Entity>
  • binaries/data/mods/public/simulation/templates/structures/spart_wall_tower.xml

     
    1616    <Actor>structures/hellenes/wall_tower.xml</Actor>
    1717  </VisualActor>
    1818  <WallPiece>
    19     <Length>7.5</Length>
     19    <Length>7.1</Length>
    2020  </WallPiece>
    21 </Entity>
    22  No newline at end of file
     21</Entity>