Ticket #2944: wallgen_additional_20150816.patch

File wallgen_additional_20150816.patch, 81.4 KB (added by s0600204, 9 years ago)

Follows on from gen_wall_builder2015-8-16.patch

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

    function GetTemplateDataHelper(template, player)  
    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,
    function GetTemplateDataHelper(template, player)  
    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/rmgen/library.js

     
    44/////////////////////////////////////////////////////////////////////////////////////////////
    55
    66const PI = Math.PI;
    7 const TWO_PI = 2 * Math.PI;
     7const TWO_PI = 2 * Math.PI; // mathematically known as 'tau'
    88const TERRAIN_SEPARATOR = "|";
    99const SEA_LEVEL = 160.0;
    1010const CELL_SIZE = 4;
  • binaries/data/mods/public/maps/random/rmgen/wall_builder.js

     
    3333// ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads?
    3434// ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending?
    3535
    36 
    37 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    38 //  WallElement class definition
    39 //
    40 //  Concept: If placed unrotated the wall's build direction 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 build direction of the wall will be changed by corners (bending != 0) and so the "inside"/"outside" direction
    42 //
    43 //  type    Identification string.
    44 //  entPath Optional. Template entity path string of the entity to be placed, example: "structures/cart_wall_long". Default is undefined (No entity placed)
    45 //  angle   Optional. Relative angle to the build direction. 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 build direction 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, entPath, angle, width, indent, 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"];
     45
     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)
    5253{
    53     this.type = type;
    54     this.entPath = entPath;
    55     this.angle = (angle !== undefined) ? angle : 0;
    56     this.width = (width !== undefined) ? width : 0;
    57     this.indent = (indent !== undefined) ? indent : 0;
    58     this.bending = (bending !== undefined) ? bending : 0;
     54    let civInfo = g_CivData[civ];
     55    if (!civInfo.WallSets)
     56        continue;
     57
     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    }
    5973}
    6074
    6175/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    function WallElement(type, entPath, angle, width, indent, bending)  
    7286function Fortress(type, wall, centerToFirstElement)
    7387{
    7488    this.type = type;
    75     this.wall = (wall !== undefined) ? wall : [];
    76     this.centerToFirstElement = undefined;
     89    this.wall = wall || [];
     90    this.centerToFirstElement = centerToFirstElement || undefined;
    7791}
    7892
    79 
    80 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    81 //  wallStyles data structure for default wall styles
    82 //
    83 //  A wall style is an associative array with all wall elements of that style in it associated with the wall element type string
    84 //  wallStyles holds all the wall styles within an associative array with the civ string or another descriptive strings as key
    85 //  Examples: "athen", "rome_siege", "palisades", "fence", "road"
    86 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    87 var wallStyles = {};
    88 
    89 // Get wall element width by template file path and angle
    90 function getTemplateWidthByAngle(entPath, angle)
    91 {
    92     var template = RMS.GetTemplate(entPath);
    93     var width = getTemplateValue(entPath, ["WallPiece", "Length"]) / CELL_SIZE;
    94    
    95     return width;
    96 }
    97 
    98 // Add new WallElement by it's properties
    99 function addNewWallElement(style, type, angle)
    100 {
    101     var templatePath = "structures/" + style + "_" + type
    102     wallStyles[style][type] = new WallElement(type, templatePath, angle, getTemplateWidthByAngle(templatePath, angle));
    103 }
    104 
    105 // Find all wall sets by civ to be then put into wallStyles
    106 var entitiesByCiv = {};
    107 var civList = getCivList();
    108 for (var i = 0; i < civList.length; i++)
    109 {
    110     var civ = civList[i];
    111     var templatePathList = getTempatePathList(civ);
    112     entitiesByCiv[civ] = templatePathList;
    113 }
    114 
    115 // Generic civ dependent wall style definition. Some, e.g. "rome_siege" needs tweaking...
    116 var wallScaleByType = {}; // To be removed TODO
    117 var civData = getFullCivData();
    118 for (var i = 0; i < civList.length; i++)
    119 {
    120     var civ = civList[i];
    121     var wallSets = civData[civ].WallSets;
    122     if (wallSets.hasOwnProperty("Stone"))
    123         wallScaleByType[civ] = wallSets.Stone.Scale;
    124 }
    125 // Non-civ but civ specific wall styles
    126 wallScaleByType.rome_siege = 1.5;
    127 for (var style in wallScaleByType)
    128 {
    129     var civ = style;
    130     if (style == "rome_siege")
    131         civ = "rome";
    132     wallStyles[style] = {};
    133     // Default wall elements
    134     var templatePath = "structures/" + style + "_wall_tower";
    135     var angle = PI;
    136     var width = getTemplateWidthByAngle(templatePath, angle); // DEBUG
    137     log("getTemplateWidthByAngle(" + templatePath + ") =  " + width + ", used to be width = " + wallScaleByType[style]); // DEBUG
    138     // wallStyles[style]["tower"] = new WallElement("tower", templatePath, angle, width);//wallScaleByType[style]);
    139     addNewWallElement(style, "wall_tower", PI);
    140     wallStyles[style]["tower"] = wallStyles[style]["wall_tower"]; // Shortcut
    141    
    142     wallStyles[style]["endLeft"] = new WallElement("endLeft", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
    143     wallStyles[style]["endRight"] = new WallElement("endRight", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
    144     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
    145     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
    146    
    147     var templatePath = "structures/" + style + "_wall_short"; // DEBUG
    148     var angle = 0*PI; // DEBUG
    149     var width = getTemplateWidthByAngle(templatePath, angle); // DEBUG
    150     log("getTemplateWidthByAngle(" + templatePath + ") =  " + width + ", used to be width = " + 2*wallScaleByType[style]); // DEBUG
    151     wallStyles[style]["wallShort"] = new WallElement("wallShort", "structures/" + style + "_wall_short", 0*PI, 2*wallScaleByType[style]);
    152    
    153     var templatePath = "structures/" + style + "_wall_medium"; // DEBUG
    154     var angle = 0*PI; // DEBUG
    155     var width = getTemplateWidthByAngle(templatePath, angle); // DEBUG
    156     log("getTemplateWidthByAngle(" + templatePath + ") =  " + width + ", used to be width = " + 4*wallScaleByType[style]); // DEBUG
    157     wallStyles[style]["wall"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]);
    158    
    159     wallStyles[style]["wallMedium"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]);
    160    
    161     var templatePath = "structures/" + style + "_wall_long"; // DEBUG
    162     var angle = 0*PI; // DEBUG
    163     var width = getTemplateWidthByAngle(templatePath, angle); // DEBUG
    164     log("getTemplateWidthByAngle(" + templatePath + ") =  " + width + ", used to be width = " + 6*wallScaleByType[style]); // DEBUG
    165     wallStyles[style]["wallLong"] = new WallElement("wallLong", "structures/" + style + "_wall_long", 0*PI, 6*wallScaleByType[style]);
    166    
    167     // Gate and entrance wall elements
    168     var gateWidth = 6*wallScaleByType[style];
    169    
    170     var templatePath = "structures/" + style + "_wall_gate"; // DEBUG
    171     var angle = PI; // DEBUG
    172     var width = getTemplateWidthByAngle(templatePath, angle); // DEBUG
    173     log("getTemplateWidthByAngle(" + templatePath + ") =  " + width + ", used to be width = " + 6*wallScaleByType[style]); // DEBUG
    174     wallStyles[style]["gate"] = new WallElement("gate", "structures/" + style + "_wall_gate", PI, gateWidth);
    175    
    176     wallStyles[style]["entry"] = new WallElement("entry", undefined, 0*PI, gateWidth);
    177     wallStyles[style]["entryTower"] = new WallElement("entryTower", "structures/" + civ + "_defense_tower", PI, gateWidth, -4*wallScaleByType[style]);
    178     wallStyles[style]["entryFort"] = new WallElement("entryFort", "structures/" + civ + "_fortress", 0*PI, 8*wallScaleByType[style], 6*wallScaleByType[style]);
    179     // Defensive wall elements with 0 width outside the wall
    180     wallStyles[style]["outpost"] = new WallElement("outpost", "structures/" + civ + "_outpost", PI, 0, -4*wallScaleByType[style]);
    181     wallStyles[style]["defenseTower"] = new WallElement("defenseTower", "structures/" + civ + "_defense_tower", PI, 0, -4*wallScaleByType[style]);
    182     // Base buildings wall elements with 0 width inside the wall
    183     wallStyles[style]["barracks"] = new WallElement("barracks", "structures/" + civ + "_barracks", PI, 0, 4.5*wallScaleByType[style]);
    184     wallStyles[style]["civilCentre"] = new WallElement("civilCentre", "structures/" + civ + "_civil_centre", PI, 0, 4.5*wallScaleByType[style]);
    185     wallStyles[style]["farmstead"] = new WallElement("farmstead", "structures/" + civ + "_farmstead", PI, 0, 4.5*wallScaleByType[style]);
    186     wallStyles[style]["field"] = new WallElement("field", "structures/" + civ + "_field", PI, 0, 4.5*wallScaleByType[style]);
    187     wallStyles[style]["fortress"] = new WallElement("fortress", "structures/" + civ + "_fortress", PI, 0, 4.5*wallScaleByType[style]);
    188     wallStyles[style]["house"] = new WallElement("house", "structures/" + civ + "_house", PI, 0, 4.5*wallScaleByType[style]);
    189     wallStyles[style]["market"] = new WallElement("market", "structures/" + civ + "_market", PI, 0, 4.5*wallScaleByType[style]);
    190     wallStyles[style]["storehouse"] = new WallElement("storehouse", "structures/" + civ + "_storehouse", PI, 0, 4.5*wallScaleByType[style]);
    191     wallStyles[style]["temple"] = new WallElement("temple", "structures/" + civ + "_temple", PI, 0, 4.5*wallScaleByType[style]);
    192     // Generic space/gap wall elements
    193     wallStyles[style]["space1"] = new WallElement("space1", undefined, 0*PI, wallScaleByType[style]);
    194     wallStyles[style]["space2"] = new WallElement("space2", undefined, 0*PI, 2*wallScaleByType[style]);
    195     wallStyles[style]["space3"] = new WallElement("space3", undefined, 0*PI, 3*wallScaleByType[style]);
    196     wallStyles[style]["space4"] = new WallElement("space4", undefined, 0*PI, 4*wallScaleByType[style]);
    197 }
    198 // Adjust "rome_siege" style
    199 wallStyles["rome_siege"]["house"] = new WallElement("house", "structures/rome_tent", PI, 0, 4);
    200 
    201 // Add special wall styles not well to implement generic (and to show how custom styles can be added)
    202 
    203 // Add wall style "palisades"
    204 wallScaleByType["palisades"] = 0.55;
    205 wallStyles["palisades"] = {};
    206 wallStyles["palisades"]["wall"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3);
    207 wallStyles["palisades"]["wallMedium"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3);
    208 wallStyles["palisades"]["wallLong"] = new WallElement("wall", "other/palisades_rocks_long", 0*PI, 3.5);
    209 wallStyles["palisades"]["wallShort"] = new WallElement("wall", "other/palisades_rocks_short", 0*PI, 1.2);
    210 wallStyles["palisades"]["tower"] = new WallElement("tower", "other/palisades_rocks_tower", -PI/2, 0.7);
    211 // wallStyles["palisades"]["wallFort"] = new WallElement("wallFort", "other/palisades_rocks_fort", PI, 1.7);
    212 wallStyles["palisades"]["gate"] = new WallElement("gate", "other/palisades_rocks_gate", PI, 3.6);
    213 wallStyles["palisades"]["entry"] = new WallElement("entry", undefined, wallStyles["palisades"]["gate"].angle, wallStyles["palisades"]["gate"].width);
    214 wallStyles["palisades"]["entryTower"] = new WallElement("entryTower", "other/palisades_rocks_watchtower", 0*PI, wallStyles["palisades"]["gate"].width, -3);
    215 wallStyles["palisades"]["entryFort"] = new WallElement("entryFort", "other/palisades_rocks_fort", PI, 6, 3);
    216 wallStyles["palisades"]["cornerIn"] = new WallElement("cornerIn", "other/palisades_rocks_curve", 3*PI/4, 2.1, 0.7, PI/2);
    217 wallStyles["palisades"]["cornerOut"] = new WallElement("cornerOut", "other/palisades_rocks_curve", 5*PI/4, 2.1, -0.7, -PI/2);
    218 wallStyles["palisades"]["outpost"] = new WallElement("outpost", "other/palisades_rocks_outpost", PI, 0, -2);
    219 wallStyles["palisades"]["house"] = new WallElement("house", "other/celt_hut", PI, 0, 5);
    220 wallStyles["palisades"]["barracks"] = new WallElement("barracks", "structures/gaul_tavern", PI, 0, 5);
    221 wallStyles["palisades"]["endRight"] = new WallElement("endRight", "other/palisades_rocks_end", -PI/2, 0.2);
    222 wallStyles["palisades"]["endLeft"] = new WallElement("endLeft", "other/palisades_rocks_end", PI/2, 0.2);
    223 
    224 // Add special wall style "road"
    225 // NOTE: This is not a wall style in the common sense. Use with care!
    226 wallStyles["road"] = {};
    227 wallStyles["road"]["short"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5);
    228 wallStyles["road"]["long"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5);
    229 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
    230 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
    231 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
    232 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
    233 wallStyles["road"]["start"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2);
    234 wallStyles["road"]["end"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2);
    235 wallStyles["road"]["xStraight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5);
    236 wallStyles["road"]["xLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, PI/2);
    237 wallStyles["road"]["xRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, -PI/2);
    238 wallStyles["road"]["tLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25);
    239 wallStyles["road"]["tRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0*PI, 4.5, -1.25);
    240 
    24193////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    242 //  fortressTypes data structure for some default fortress types
     94//  g_FortressTypes data structure for some default fortress types (defined above)
    24395//
    24496//  A fortress type is just an instance of the Fortress class with actually something in it
    24597//  fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size)
    24698//  Examples: "tiny", "veryLarge"
    24799////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    248 var fortressTypes = {};
    249 // Setup some default fortress types
    250 // Add fortress type "tiny"
    251 fortressTypes["tiny"] = new Fortress("tiny");
    252 var wallPart = ["gate", "tower", "wallShort", "cornerIn", "wallShort", "tower"];
    253 fortressTypes["tiny"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    254 // Add fortress type "small"
    255 fortressTypes["small"] = new Fortress("small");
    256 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "tower"];
    257 fortressTypes["small"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    258 // Add fortress type "medium"
    259 fortressTypes["medium"] = new Fortress("medium");
    260 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "tower"];
    261 fortressTypes["medium"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    262 // Add fortress type "normal"
    263 fortressTypes["normal"] = new Fortress("normal");
    264 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wall", "cornerIn", "wall", "tower"];
    265 fortressTypes["normal"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    266 // Add fortress type "large"
    267 fortressTypes["large"] = new Fortress("large");
    268 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"];
    269 fortressTypes["large"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    270 // Add fortress type "veryLarge"
    271 fortressTypes["veryLarge"] = new Fortress("veryLarge");
    272 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wall", "cornerIn", "wall", "tower"];
    273 fortressTypes["veryLarge"].wall = wallPart.concat(wallPart, wallPart, wallPart);
    274 // Add fortress type "giant"
    275 fortressTypes["giant"] = new Fortress("giant");
    276 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"];
    277 fortressTypes["giant"].wall = wallPart.concat(wallPart, wallPart, wallPart);
     100
     101// Set some default fortress types
     102for (let key of g_FortressTypeKeys)
     103    g_FortressTypes[key] = new Fortress(key);
     104
     105g_FortressTypes["tiny"].wall = ["gate", "tower", "short", "cornerIn", "short", "tower"];
     106g_FortressTypes["small"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "tower"];
     107g_FortressTypes["medium"].wall = ["gate", "tower", "long", "cornerIn", "long", "tower"];
     108g_FortressTypes["normal"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "medium", "cornerIn", "medium", "tower"];
     109g_FortressTypes["large"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"];
     110g_FortressTypes["veryLarge"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "long", "cornerIn", "long", "cornerOut", "medium", "cornerIn", "medium", "tower"];
     111g_FortressTypes["giant"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"];
     112
     113for (let type in g_FortressTypes)
     114{
     115    let wallPart = g_FortressTypes[type].wall;
     116    g_FortressTypes[type].wall = wallPart.concat(wallPart, wallPart, wallPart);
     117}
    278118
    279119// Setup some better looking semi default fortresses for "palisades" style
    280 var fortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"];
    281 for (var i = 0; i < fortressTypeKeys.length; i++)
     120for (let fortType of g_FortressTypeKeys)
    282121{
    283     var newKey = fortressTypeKeys[i] + "Palisades";
    284     var oldWall = fortressTypes[fortressTypeKeys[i]].wall;
    285     fortressTypes[newKey] = new Fortress(newKey);
     122    var newKey = fortType + "Palisades";
     123    var oldWall = g_FortressTypes[fortType].wall;
     124    g_FortressTypes[newKey] = new Fortress(newKey);
    286125    var fillTowersBetween = ["wallShort", "wall", "wallLong", "endLeft", "endRight", "cornerIn", "cornerOut"];
    287126    for (var j = 0; j < oldWall.length; j++)
    288127    {
    289         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)
     128        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)
    290129        if (j+1 < oldWall.length)
    291130            if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means "exists" here
    292                 fortressTypes[newKey].wall.push("tower");
     131                g_FortressTypes[newKey].wall.push("tower");
    293132    }
    294133}
    295134
    296135// Setup some balanced (to civ type fortresses) semi default fortresses for "palisades" style
    297136// TODO
    298137
    299 // Add some "fortress types" for roads (will only work with style "road")
    300 // ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"];
    301 var wall = ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"];
    302 fortressTypes["road01"] = new Fortress("road01", wall);
    303 var wall = ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"];
    304 fortressTypes["road02"] = new Fortress("road02", wall);
    305 var wall = ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"];
    306 fortressTypes["road03"] = new Fortress("road03", wall);
    307 var wall = ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short",
    308     "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"];
    309 fortressTypes["road04"] = new Fortress("road04", wall);
    310 var wall = ["start", "tLeft", "short", "xRight",
    311     "curveLeft", "xRight", "tRight", "cornerLeft", "tRight",
    312     "curveLeft", "short", "tRight", "cornerLeft", "xRight",
    313     "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"];
    314 fortressTypes["road05"] = new Fortress("road05", wall);
    315 
    316138
    317139///////////////////////////////
    318140// Define some helper functions
    319141///////////////////////////////
    320142
     143/**
     144 * Get a wall element of a style.
     145 *
     146 * If the element requested is unknown, the function attempts to derive
     147 * it either from another element, or from a template or whatever.
     148 *
     149 * @param style The style to which this element comes from
     150 * @param element The element to fetch
     151 * @return The wall element requested. Or a tower element.
     152 */
     153function getWallElement(style="athen_stone", element)
     154{
     155    if (g_WallStyleList.indexOf(style) < 0)
     156    {
     157        error("getWallElement: Style '"+style+"' not recognised. (Falling back to '" + FALLBACK_CIV + "_stone'.)");
     158        style = FALLBACK_CIV + "_stone";
     159    }
     160    if (g_WallStyles[style][element])
     161        return g_WallStyles[style][element];
     162
     163    // Attempt to derive any unknown elements.
     164    // Defaults to a wall tower piece
     165    var wallset = g_WallStyles[style];
     166    var civ = style.split("_")[0];
     167    var ret = clone(wallset.tower);
     168
     169    // We use clone() so we don't change the attributes of the object we're referencing
     170    switch (element)
     171    {
     172
     173    case "quarterCurve":
     174        ret.angle += PI/4;
     175        ret.bend = PI/2;
     176        break;
     177
     178    case "eighthCurve":
     179        ret.angle += PI/8;
     180        ret.bend = PI/4;
     181        break;
     182
     183    case "cornerIn":
     184        if (wallset.quarterCurve)
     185            ret = clone(wallset.quarterCurve);
     186        else
     187        {
     188            ret.angle += PI/4
     189            ret.indent = ret.length * 0.25;
     190            ret.length = 0;
     191        }
     192        ret.bend = PI/2;
     193        break;
     194
     195    case "cornerOut":
     196        if (wallset.quarterCurve)
     197        {
     198            ret = clone(wallset.quarterCurve);
     199            ret.angle += PI/2;
     200            ret.indent -= ret.indent*2;
     201        }
     202        else
     203        {
     204            ret.angle -= PI/4;
     205            ret.length *= 0.71;
     206        }
     207        ret.bend = -PI/2;
     208        break;
     209
     210    case "wallShort":
     211        warn("getWallElement: Deprecated use of 'wallShort' (please use 'short')");
     212        ret = clone(wallset.short);
     213        break;
     214
     215    case "wallMedium":
     216    case "wall":
     217        warn("getWallElement: Deprecated use of '"+element+"' (please use 'medium')");
     218        ret = clone(wallset.medium);
     219        break;
     220
     221    case "wallLong":
     222        warn("getWallElement: Deprecated use of 'wallLong' (please use 'long')");
     223        ret = clone(wallset.long);
     224        break;
     225
     226    case "entry":
     227        ret.entPath = undefined;
     228        ret.length = clone(g_WallStyles[style].gate.length);
     229        break;
     230
     231    case "entryTower":
     232        ret.entPath = (g_CivList.indexOf(civ) > -1) ? "structures/"+civ+"_defense_tower" : "other/palisades_rocks_watchtower";
     233        ret.indent = ret.length * -3;
     234        ret.length = clone(g_WallStyles[style].gate.length);
     235        break;
     236
     237    case "entryFort":
     238        ret = clone(g_WallStyles[style].fort);
     239        ret.angle -= PI;
     240        ret.length *= 1.5;
     241        ret.indent = ret.length;
     242        break;
     243
     244    case "endLeft":
     245        warn("getWallElement: Deprecated use of 'endLeft' (please use 'start')");
     246    case "start":
     247        if (wallset.end)
     248        {
     249            ret = clone(wallset.end);
     250            ret.angle += PI;
     251        }
     252        break;
     253
     254    case "endRight":
     255        warn("getWallElement: Deprecated use of 'endRight' (please use 'start')");
     256    case "end":
     257        if (wallset.end)
     258            ret = clone(wallset.end);
     259        break;
     260
     261    default:
     262        // See if it's a structure (ie. house, barracks)
     263        if (g_CivList.indexOf(civ) == -1)
     264            civ = FALLBACK_CIV;
     265        var entPath = "structures/"+civ+"_"+element;
     266        if (RMS.TemplateExists(entPath))
     267        {
     268            if (["outpost", "defense_tower"].indexOf(element) > -1)
     269                ret.indent = ret.length * -3;
     270            else
     271                ret.indent = ret.length * 3.5;
     272            ret.entPath = entPath;
     273            ret.length = 0;
     274        }
     275        else if (element.slice(0.3) === "gap")
     276        {
     277            ret.entPath = undefined;
     278            ret.angle = 0;
     279            ret.length = +element.slice(4);
     280        }
     281        else if (element.slice(0,4) === "turn")
     282        {
     283            ret.entPath = undefined;
     284            ret.angle = PI/2;
     285            ret.length = 0;
     286            if (element.slice(5) === "out")
     287                ret.angle -= ret.angle;
     288        }
     289        else
     290            warn("Unrecognised wall element: "+element+" ("+ style+"). Defaulting to 'tower'.");
     291    }
     292
     293    // cache to save having to calculate this element again
     294    g_WallStyles[style][element] = ret;
     295
     296    return ret;
     297}
     298
     299/**
     300 * Set a wall element of a style.
     301 *
     302 * @param style The style to which this element belongs
     303 * @param element The element to add
     304 * @param path The template path to read values from
     305 */
     306function setWallElement(style, element, path)
     307{
     308    var template = RMS.GetTemplate(path);
     309    template = GetTemplateDataHelper(template);
     310
     311    if (!g_WallStyles[style])
     312        g_WallStyles[style] = {};
     313
     314    var length = (template.wallPiece) ? template.wallPiece.length : template.obstruction.shape.width;
     315    g_WallStyles[style][element] = {
     316            "entPath": path,
     317            "angle": (template.wallPiece) ? template.wallPiece.angle : PI,
     318            "length": length / CELL_SIZE,
     319            "indent": (template.wallPiece) ? template.wallPiece.indent / CELL_SIZE : 0,
     320            "bend": (template.wallPiece) ? template.wallPiece.bend : 0
     321        };
     322}
     323
    321324/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    322325//  getWallAlignment
    323326//
    fortressTypes["road05"] = new Fortress("road05", wall);  
    325328//  Placing the first wall element at startX/startY placed with an angle given by orientation
    326329//  An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement
    327330/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    328 function getWallAlignment(startX, startY, wall, style, orientation)
     331function getWallAlignment(startX, startY, wall=[], style="athen_stone", orientation=0)
    329332{
    330     // Graciously handle arguments
    331     if (wall === undefined)
    332         wall = [];
    333     if (!wallStyles.hasOwnProperty(style))
    334     {
    335         warn("Function getWallAlignment: Unknown style: " + style + ' (falling back to "athen")');
    336         style = "athen";
    337     }
    338     orientation = (orientation || 0);
    339    
    340333    var alignment = [];
    341334    var wallX = startX;
    342335    var wallY = startY;
     336
    343337    for (var i = 0; i < wall.length; i++)
    344338    {
    345         var element = wallStyles[style][wall[i]];
     339        var element = getWallElement(style, wall[i]);
    346340        if (element === undefined && i == 0)
    347             warn("No valid wall element: style = " + style + ", wall[" + i + "] = " + wall[i] + ", wallStyles[" + style + "][wall[" + i + "]] = " + wallStyles[style][wall[i]] + ", element = " + element + ", wall = " + wall);
     341        {
     342            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);
     343            continue;
     344        }
     345
    348346        // Indentation
    349347        var placeX = wallX - element.indent * cos(orientation);
    350348        var placeY = wallY - element.indent * sin(orientation);
     349
    351350        // Add wall elements entity placement arguments to the alignment
    352351        alignment.push({"x": placeX, "y": placeY, "entPath": element.entPath, "angle":orientation + element.angle});
     352
    353353        // Preset vars for the next wall element
    354354        if (i+1 < wall.length)
    355355        {
    356             orientation += element.bending;
    357             var nextElement = wallStyles[style][wall[i+1]];
     356            orientation += element.bend;
     357            var nextElement = getWallElement(style, wall[i+1]);
    358358            if (nextElement === undefined)
    359                 warn("No valid wall element: style = " + style + ", wall[" + (i+1) + "] = " + wall[i+1] + ", wallStyles[" + style + "][wall[" + (i+1) + "]] = " + wallStyles[style][wall[i+1]] + ", nextElement = " + uneval(nextElement) + ", wall = " + wall);
    360             var distance = (element.width + nextElement.width)/2;
     359            {
     360                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);
     361                continue;
     362            }
     363           
     364            var distance = (element.length + nextElement.length)/2 - getOverlap(style);
    361365            // Corrections for elements with indent AND bending
    362366            var indent = element.indent;
    363             var bending = element.bending;
    364             if (bending !== 0 && indent !== 0)
     367            var bend = element.bend;
     368            if (bend !== 0 && indent !== 0)
    365369            {
    366370                // Indent correction to adjust distance
    367                 distance += indent*sin(bending);
     371                distance += indent*sin(bend);
    368372                // Indent correction to normalize indentation
    369373                wallX += indent * cos(orientation);
    370374                wallY += indent * sin(orientation);
    371375            }
     376           
    372377            // Set the next coordinates of the next element in the wall without indentation adjustment
    373378            wallX -= distance * sin(orientation);
    374379            wallY += distance * cos(orientation);
    function getCenterToFirstElement(alignment)  
    400405//  getWallLength
    401406//
    402407//  NOTE: Does not support bending wall elements like corners!
    403 //  e.g. used by placeIrregularPolygonalWall
    404408//////////////////////////////////////////////////////////////////
    405 function getWallLength(wall, style)
     409function getWallLength(style, wall=[])
    406410{
    407411    // Graciously handle arguments
    408     if (wall === undefined)
    409         wall = [];
    410     if (!wallStyles.hasOwnProperty(style))
     412    if (g_WallStyleList.indexOf(style) < 0)
    411413    {
    412         warn("Function getWallLength: Unknown style: " + style + ' (falling back to "athen")');
    413         style = "athen";
     414        warn("getWallLength: Unknown style: '" + style + "'. (Falling back to '" + FALLBACK_CIV + "_stone').");
     415        style = FALLBACK_CIV +"_stone";
    414416    }
    415    
     417
    416418    var length = 0;
    417     for (var i = 0; i < wall.length; i++)
    418     {
    419         length += wallStyles[style][wall[i]].width;
    420     }
     419    var overlap = getOverlap(style);
     420    for (let element of wall)
     421        length += getWallElement(style, element).length - overlap;
     422
    421423    return length;
    422424}
    423425
     426function getOverlap(style)
     427{
     428    if (!style || !g_WallStyles[style])
     429        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
     430    return g_WallStyles[style]["@overlap"];
     431}
     432
    424433
    425434/////////////////////////////////////////////
    426435// Define the different wall placer functions
    function getWallLength(wall, style)  
    440449//                  It will then be build towards top/positive Y (if no bending wall elements like corners are used)
    441450//                  Raising orientation means the wall is rotated counter-clockwise like placeObject
    442451/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    443 function placeWall(startX, startY, wall, style, playerId, orientation)
     452function placeWall(startX, startY, wall=[], style, playerId=0, orientation=0)
    444453{
    445     // Graciously handle arguments
    446     if (wall === undefined)
    447         wall = [];
    448     playerId = (playerId || 0);
    449     if (!wallStyles.hasOwnProperty(style))
    450     {
    451         if (playerId == 0)
    452             style = (style || "palisades");
    453         else
    454             style = (getCivCode(playerId-1));
    455     }
    456     orientation = (orientation || 0);
     454    if (!startX || !startY)
     455        return;
     456   
     457    if (!style || g_WallStyleList.indexOf(style) == -1)
     458        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    457459   
    458460    // Get wall alignment
    459461    var AM = getWallAlignment(startX, startY, wall, style, orientation);
     462   
    460463    // Place the wall
    461464    for (var iWall = 0; iWall < wall.length; iWall++)
    462465    {
    function placeWall(startX, startY, wall, style, playerId, orientation)  
    477480//  playerId       Optional. Number of the player the wall will be placed for. Default is 0 (gaia)
    478481//  orientation    Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0
    479482/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    480 function placeCustomFortress(centerX, centerY, fortress, style, playerId, orientation)
     483function placeCustomFortress(centerX, centerY, fortress, style, playerId=0, orientation=0)
    481484{
    482485    // Graciously handle arguments
    483     fortress = (fortress || fortressTypes["medium"]);
    484     playerId = (playerId || 0);
    485     if (!wallStyles.hasOwnProperty(style))
    486     {
    487         if (playerId == 0)
    488             style = (style || "palisades");
    489         else
    490             style = (getCivCode(playerId-1));
    491     }
    492     orientation = (orientation || 0);
     486    fortress = fortress || g_FortressTypes["medium"];
     487    if (!style || !g_WallStyles[style])
     488        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    493489   
    494490    // Calculate center if fortress.centerToFirstElement is undefined (default)
    495491    var centerToFirstElement = fortress.centerToFirstElement;
    function placeCustomFortress(centerX, centerY, fortress, style, playerId, orient  
    506502//
    507503//  Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress
    508504///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    509 function placeFortress(centerX, centerY, type, style, playerId, orientation)
     505function placeFortress(centerX, centerY, type="medium", style, playerId=0, orientation=0)
    510506{
    511507    // Graciously handle arguments
    512     type = (type || "medium");
    513     playerId = (playerId || 0);
    514     if (!wallStyles.hasOwnProperty(style))
    515     {
    516         if (playerId == 0)
    517             style = (style || "palisades");
    518         else
    519             style = (getCivCode(playerId-1));
    520     }
    521     orientation = (orientation || 0);
     508    if (!style || !g_WallStyles[style])
     509        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    522510   
    523511    // Call placeCustomFortress with the given arguments
    524     placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation);
     512    placeCustomFortress(centerX, centerY, g_FortressTypes[type], style, playerId, orientation);
    525513}
    526514
    527515//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    function placeFortress(centerX, centerY, type, style, playerId, orientation)  
    538526//
    539527//  TODO: Maybe add angle offset for more generic looking?
    540528//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    541 function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId, endWithFirst)
     529function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId=0, endWithFirst=true)
    542530{
    543531    // Setup optional arguments to the default
    544     wallPart = (wallPart || ["tower", "wallLong"]);
    545     playerId = (playerId || 0);
    546     if (!wallStyles.hasOwnProperty(style))
    547     {
    548         if (playerId == 0)
    549             style = (style || "palisades");
    550         else
    551             style = (getCivCode(playerId-1));
    552     }
    553     endWithFirst = typeof endWithFirst == "undefined" ? true : endWithFirst;
     532    wallPart = wallPart || ["tower", "long"];
     533    if (!style || !g_WallStyles[style])
     534        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    554535   
    555536    // Check arguments
    556     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    557     {
    558         var bending = wallStyles[style][wallPart[elementIndex]].bending;
    559         if (bending != 0)
    560             warn("Bending is not supported by placeLinearWall but a bending wall element is used: " + wallPart[elementIndex] + " -> wallStyles[style][wallPart[elementIndex]].entPath");
    561     }
     537    for (let element of wallPart)
     538        if (getWallElement(style, element).bend != 0)
     539            warn("Bending is not supported by placeLinearWall but the following bending wall element was used: " + element);
     540
    562541    // Setup number of wall parts
    563542    var totalLength = getDistance(startX, startY, targetX, targetY);
    564     var wallPartLength = 0;
    565     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    566         wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
     543    var wallPartLength = getWallLength(style, wallPart);
    567544    var numParts = 0;
    568545    if (endWithFirst == true)
    569         numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);
     546        numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength);
    570547    else
    571548        numParts = ceil(totalLength / wallPartLength);
     549
    572550    // Setup scale factor
    573551    var scaleFactor = 1;
    574552    if (endWithFirst == true)
    575         scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);
     553        scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length);
    576554    else
    577555        scaleFactor = totalLength / (numParts * wallPartLength);
     556
    578557    // Setup angle
    579558    var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed...
    580559    var placeAngle = wallAngle - PI/2;
    function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, play  
    585564    {
    586565        for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    587566        {
    588             var wallEle = wallStyles[style][wallPart[elementIndex]];
    589             // Width correction
    590             x += scaleFactor * wallEle.width/2 * cos(wallAngle);
    591             y += scaleFactor * wallEle.width/2 * sin(wallAngle);
     567            let wallEle = getWallElement(style, wallPart[elementIndex]);
     568            let wallLength = (wallEle.length - getOverlap(style)) / 2;
     569            let distX = scaleFactor * wallLength * cos(wallAngle);
     570            let distY = scaleFactor * wallLength * sin(wallAngle);
     571            // Length correction
     572            x += distX;
     573            y += distY;
    592574            // Indent correction
    593             var placeX = x - wallEle.indent * sin(wallAngle);
    594             var placeY = y + wallEle.indent * cos(wallAngle);
     575            let placeX = x - wallEle.indent * sin(wallAngle);
     576            let placeY = y + wallEle.indent * cos(wallAngle);
    595577            // Placement
    596             var entPath = wallEle.entPath;
     578            let entPath = wallEle.entPath;
    597579            if (entPath !== undefined)
    598580                placeObject(placeX, placeY, entPath, playerId, placeAngle + wallEle.angle);
    599             x += scaleFactor * wallEle.width/2 * cos(wallAngle);
    600             y += scaleFactor * wallEle.width/2 * sin(wallAngle);
     581            // Prep for next object
     582            x += distX;
     583            y += distY;
    601584        }
    602585    }
    603586    if (endWithFirst == true)
    604587    {
    605         var wallEle = wallStyles[style][wallPart[0]];
    606         x += scaleFactor * wallEle.width/2 * cos(wallAngle);
    607         y += scaleFactor * wallEle.width/2 * sin(wallAngle);
     588        var wallEle = getWallElement(style, wallPart[0]);
     589        let wallLength = (wallEle.length - getOverlap(style)) / 2;
     590        x += scaleFactor * wallLength * cos(wallAngle);
     591        y += scaleFactor * wallLength * sin(wallAngle);
    608592        var entPath = wallEle.entPath;
    609593        if (entPath !== undefined)
    610594            placeObject(x, y, entPath, playerId, placeAngle + wallEle.angle);
    function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, play  
    633617//  TODO: Check if maxBendOff parameter works in all cases
    634618//  TODO: Perhaps add functionality for spirals
    635619/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    636 function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff)
     620function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId=0, orientation=0, maxAngle=TWO_PI, endWithFirst, maxBendOff=0)
    637621{
    638622    // Setup optional arguments to the default
    639     wallPart = (wallPart || ["tower", "wallLong"]);
    640     playerId = (playerId || 0);
    641     if (!wallStyles.hasOwnProperty(style))
    642     {
    643         if (playerId == 0)
    644             style = (style || "palisades");
    645         else
    646             style = (getCivCode(playerId-1));
    647     }
    648     orientation = (orientation || 0);
    649     maxAngle = (maxAngle || 2*PI);
     623    wallPart = wallPart || ["tower", "long"];
     624    if (!style || !g_WallStyles[style])
     625        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    650626    if (endWithFirst === undefined)
    651627    {
    652         if (maxAngle >= 2*PI - 0.001) // Can this be done better?
     628        if (maxAngle >= TWO_PI - 0.001) // Can this be done better?
    653629            endWithFirst = false;
    654630        else
    655631            endWithFirst = true;
    656632    }
    657     maxBendOff = (maxBendOff || 0);
    658633   
    659634    // Check arguments
    660635    if (maxBendOff > PI/2 || maxBendOff < 0)
    661636        warn("placeCircularWall maxBendOff should satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff);
    662     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    663     {
    664         var bending = wallStyles[style][wallPart[elementIndex]].bending;
    665         if (bending != 0)
    666             warn("Bending is not supported by placeCircularWall but a bending wall element is used: " + wallPart[elementIndex]);
    667     }
     637    for (let element of wallPart)
     638        if (getWallElement(style, element).bend != 0)
     639            warn("Bending is not supported by placeCircularWall but the following bending wall element was used: " + element);
     640
    668641    // Setup number of wall parts
    669642    var totalLength = maxAngle * radius;
    670     var wallPartLength = 0;
    671     for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
    672         wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
     643    var wallPartLength = getWallLength(style, wallPart);
    673644    var numParts = 0;
    674645    if (endWithFirst == true)
    675646    {
    676         numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);
     647        numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength);
    677648    }
    678649    else
    679650    {
    function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId,  
    682653    // Setup scale factor
    683654    var scaleFactor = 1;
    684655    if (endWithFirst == true)
    685         scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);
     656        scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length);
    686657    else
    687658        scaleFactor = totalLength / (numParts * wallPartLength);
    688659    // Place wall entities
    689660    var actualAngle = orientation + (2*PI - maxAngle) / 2;
    690661    var x = centerX + radius*cos(actualAngle);
    691662    var y = centerY + radius*sin(actualAngle);
    692     for (var partIndex = 0; partIndex < numParts; partIndex++)
     663    for (let partIndex = 0; partIndex < numParts; partIndex++)
    693664    {
    694         for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
     665        for (let wallEle of wallPart)
    695666        {
    696             var wallEle = wallStyles[style][wallPart[elementIndex]];
     667            wallEle = getWallElement(style, wallEle);
    697668            // Width correction
    698             var addAngle = scaleFactor * wallEle.width / radius;
    699             var targetX = centerX + radius * cos(actualAngle + addAngle);
    700             var targetY = centerY + radius * sin(actualAngle + addAngle);
    701             var placeX = x + (targetX - x)/2;
    702             var placeY = y + (targetY - y)/2;
    703             var placeAngle = actualAngle + addAngle/2;
     669            let addAngle = scaleFactor * (wallEle.length - getOverlap(style)) / radius;
     670            let targetX = centerX + radius * cos(actualAngle + addAngle);
     671            let targetY = centerY + radius * sin(actualAngle + addAngle);
     672            let placeX = x + (targetX - x)/2;
     673            let placeY = y + (targetY - y)/2;
     674            let placeAngle = actualAngle + addAngle/2;
    704675            // Indent correction
    705676            placeX -= wallEle.indent * cos(placeAngle);
    706677            placeY -= wallEle.indent * sin(placeAngle);
    function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId,  
    716687    }
    717688    if (endWithFirst == true)
    718689    {
    719         var wallEle = wallStyles[style][wallPart[0]];
    720         var addAngle = scaleFactor * wallEle.width / radius;
     690        var wallEle = getWallElement(style, wallPart[0]);
     691        var addAngle = scaleFactor * wallEle.length / radius;
    721692        var targetX = centerX + radius * cos(actualAngle + addAngle);
    722693        var targetY = centerY + radius * sin(actualAngle + addAngle);
    723694        var placeX = x + (targetX - x)/2;
    function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId,  
    747718//  TODO: Check some arguments
    748719//  TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0
    749720/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    750 function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall)
     721function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId=0, orientation=0, numCorners=8, skipFirstWall=true)
    751722{
    752723    // Setup optional arguments to the default
    753     wallPart = (wallPart || ["wallLong", "tower"]);
    754     cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well...
    755     playerId = (playerId || 0);
    756     if (!wallStyles.hasOwnProperty(style))
    757     {
    758         if (playerId == 0)
    759             style = (style || "palisades");
    760         else
    761             style = (getCivCode(playerId-1));
    762     }
    763     orientation = (orientation || 0);
    764     numCorners = (numCorners || 8);
    765     skipFirstWall = (skipFirstWall || true);
    766    
     724    wallPart = wallPart || ["long", "tower"];
     725    cornerWallElement = cornerWallElement || "tower"; // Don't use wide elements for this. Not supported well...
     726    if (!style || !g_WallStyles[style])
     727        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
     728
    767729    // Setup angles
    768     var angleAdd = 2*PI/numCorners;
     730    var angleAdd = TWO_PI/numCorners;
    769731    var angleStart = orientation - angleAdd/2;
     732
    770733    // Setup corners
    771734    var corners = [];
    772     for (var i = 0; i < numCorners; i++)
     735    for (let i = 0; i < numCorners; i++)
    773736        corners.push([centerX + radius*cos(angleStart + i*angleAdd), centerY + radius*sin(angleStart + i*angleAdd)]);
     737
    774738    // Place Corners and walls
    775     for (var i = 0; i < numCorners; i++)
     739    for (let i = 0; i < numCorners; i++)
    776740    {
    777         var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
    778         placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entPath, playerId, angleToCorner);
     741        let angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
     742        placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner);
    779743        if (!(skipFirstWall && i == 0))
    780744        {
     745            let cornerLength = getWallElement(style, cornerWallElement).length / 2;
     746            let cornerAngle = angleToCorner + angleAdd / 2;
     747            let cornerX = cornerLength * sin(cornerAngle);
     748            let cornerY = cornerLength * cos(cornerAngle);
    781749            placeLinearWall(
    782750                // Adjustment to the corner element width (approximately)
    783                 corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // startX
    784                 corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // startY
    785                 corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // targetX
    786                 corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // targetY
     751                corners[i][0] + cornerX, // startX
     752                corners[i][1] - cornerY, // startY
     753                corners[(i+1)%numCorners][0] - cornerX, // targetX
     754                corners[(i+1)%numCorners][1] + cornerY, // targetY
    787755                wallPart, style, playerId);
    788756        }
    789757    }
    function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElemen  
    800768//  style                Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    801769//  playerId             Optional. Integer number of the player. Default is 0 (gaia)
    802770//  orientation          Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)
    803 //  numCorners           Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory)
     771//  numCorners           Optional. How many corners the polygon will have. Default is randomly chosen from 'tween 5 & 7 inclusive
    804772//  irregularity         Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5
    805 //  skipFirstWall        Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true
     773//  skipFirstWall        Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is false
    806774//  wallPartsAssortment  Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^
    807775//
    808776//  NOTE: wallPartsAssortment is put to the end because it's hardest to set
    function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElemen  
    811779//  TODO: Check some arguments
    812780//  TODO: Perhaps add eccentricity
    813781////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    814 function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment)
     782function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement="tower", style, playerId=0, orientation=0, numCorners, irregularity=0.5, skipFirstWall=false, wallPartsAssortment)
    815783{
    816784    // Setup optional arguments
    817     playerId = (playerId || 0);
    818     if (!wallStyles.hasOwnProperty(style))
    819     {
    820         if (playerId == 0)
    821             style = (style || "palisades");
    822         else
    823             style = (getCivCode(playerId-1));
    824     }
    825    
     785    if (!style || !g_WallStyles[style])
     786        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
     787    numCorners = (numCorners || randInt(5, 7));
     788
    826789    // Generating a generic wall part assortment with each wall part including 1 gate lengthened by walls and towers
    827790    // NOTE: It might be a good idea to write an own function for that...
    828     var defaultWallPartsAssortment = [["wallShort"], ["wall"], ["wallLong"], ["gate", "tower", "wallShort"]];
     791    var defaultWallPartsAssortment = [["short"], ["medium"], ["long"], ["gate", "tower", "short"]];
    829792    var centeredWallPart = ["gate"];
    830     var extandingWallPartAssortment = [["tower", "wallLong"], ["tower", "wall"]];
     793    var extandingWallPartAssortment = [["tower", "long"], ["tower", "medium"]];
    831794    defaultWallPartsAssortment.push(centeredWallPart);
    832795    for (var i = 0; i < extandingWallPartAssortment.length; i++)
    833796    {
    function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement  
    847810    }
    848811    // Setup optional arguments to the default
    849812    wallPartsAssortment = (wallPartsAssortment || defaultWallPartsAssortment);
    850     cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well...
    851     style = (style || "palisades");
    852     playerId = (playerId || 0);
    853     orientation = (orientation || 0);
    854     numCorners = (numCorners || randInt(5, 7));
    855     irregularity = (irregularity || 0.5);
    856     skipFirstWall = (skipFirstWall || false);
     813
    857814    // Setup angles
    858     var angleToCover = 2*PI;
     815    var angleToCover = TWO_PI;
    859816    var angleAddList = [];
    860817    for (var i = 0; i < numCorners; i++)
    861818    {
    function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement  
    875832    // Setup best wall parts for the different walls (a bit confusing naming...)
    876833    var wallPartLengths = [];
    877834    var maxWallPartLength = 0;
    878     for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)
     835    for (let wallPart of wallPartsAssortment)
    879836    {
    880         var length = wallPartLengths[partIndex];
    881         wallPartLengths.push(getWallLength(wallPartsAssortment[partIndex], style));
     837        var length = getWallLength(style, wallPart);
     838        wallPartLengths.push(length);
    882839        if (length > maxWallPartLength)
    883840            maxWallPartLength = length;
    884841    }
     842   
    885843    var wallPartList = []; // This is the list of the wall parts to use for the walls between the corners, not to confuse with wallPartsAssortment!
    886844    for (var i = 0; i < numCorners; i++)
    887845    {
    888         var bestWallPart = []; // This is a simpel wall part not a wallPartsAssortment!
    889         var bestWallLength = 99999999;
     846        var bestWallPart = []; // This is a simple wall part not a wallPartsAssortment!
     847        var bestWallLength = Number.MAX_VALUE;
    890848        // NOTE: This is not exactly like the length the wall will be in the end. Has to be tweaked...
    891849        var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]);
    892850        var numWallParts = ceil(wallLength/maxWallPartLength);
    function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement  
    901859        }
    902860        wallPartList.push(bestWallPart);
    903861    }
     862
    904863    // Place Corners and walls
    905864    for (var i = 0; i < numCorners; i++)
    906865    {
    907866        var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
    908         placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entPath, playerId, angleToCorner);
     867        placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner);
    909868        if (!(skipFirstWall && i == 0))
    910869        {
     870            let cornerLength = getWallElement(style, cornerWallElement).length / 2;
    911871            placeLinearWall(
    912872                // Adjustment to the corner element width (approximately)
    913                 corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[i]/2), // startX
    914                 corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[i]/2), // startY
    915                 corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX
    916                 corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY
     873                corners[i][0] + cornerLength * sin(angleToCorner + angleAddList[i]/2), // startX
     874                corners[i][1] - cornerLength * cos(angleToCorner + angleAddList[i]/2), // startY
     875                corners[(i+1)%numCorners][0] - cornerLength * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX
     876                corners[(i+1)%numCorners][1] + cornerLength * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY
    917877                wallPartList[i], style, playerId, false);
    918878        }
    919879    }
    function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement  
    926886//  This is the default Iberian civ bonus starting wall
    927887//
    928888//  centerX/Y      The approximate center coordinates of the fortress
    929 //  radius         The approximate radius of the wall to be placed
     889//  radius         Optional. The approximate radius of the wall to be placed. Default is 20
    930890//  playerId       Optional. Integer number of the player. Default is 0 (gaia)
    931891//  style          Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
    932 //  irregularity   Optional. Float between 0 (circle) and 1 (very spiky), default is 1/2
     892//  irregularity   Optional. Float between 0 (circle) and 1 (very spiky), default is 0.5
    933893//  gateOccurence  Optional. Integer number, every n-th walls will be a gate instead. Default is 3
    934894//  maxTrys        Optional. How often the function tries to find a better fitting shape at max. Default is 100
    935895//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    936 function placeGenericFortress(centerX, centerY, radius, playerId, style, irregularity, gateOccurence, maxTrys)
     896function placeGenericFortress(centerX, centerY, radius=20, playerId=0, style, irregularity=0.5, gateOccurence=3, maxTrys=100)
    937897{
    938898    // Setup optional arguments
    939     radius = (radius || 20);
    940     playerId = (playerId || 0);
    941     if (!wallStyles.hasOwnProperty(style))
    942     {
    943         if (playerId == 0)
    944             style = (style || "palisades");
    945         else
    946             style = (getCivCode(playerId-1));
    947     }
    948     irregularity = (irregularity || 1/2);
    949     gateOccurence = (gateOccurence || 3);
    950     maxTrys = (maxTrys || 100);
     899    if (!style || !g_WallStyles[style])
     900        style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone";
    951901   
    952902    // Setup some vars
    953903    var startAngle = randFloat(0, 2*PI);
    954904    var actualOffX = radius*cos(startAngle);
    955905    var actualOffY = radius*sin(startAngle);
    956906    var actualAngle = startAngle;
    957     var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width;
     907    var pointDistance = getWallLength(style, ["long", "tower"]);
    958908    // Searching for a well fitting point derivation
    959909    var tries = 0;
    960910    var bestPointDerivation = undefined;
    961911    var minOverlap = 1000;
    962912    var overlap = undefined;
    963     while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10)
     913    while (tries < maxTrys && minOverlap > getOverlap(style))
    964914    {
    965915        var pointDerivation = [];
    966916        var distanceToTarget = 1000;
    function placeGenericFortress(centerX, centerY, radius, playerId, style, irregul  
    969919        {
    970920            var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance);
    971921            var tmpAngle = getAngle(actualOffX, actualOffY,
    972                 (radius + indent)*cos(actualAngle + (pointDistance / radius)),
    973                 (radius + indent)*sin(actualAngle + (pointDistance / radius)));
     922                (radius + indent)*cos(actualAngle + pointDistance / radius),
     923                (radius + indent)*sin(actualAngle + pointDistance / radius));
    974924            actualOffX += pointDistance*cos(tmpAngle);
    975925            actualOffY += pointDistance*sin(tmpAngle);
    976926            actualAngle = getAngle(0, 0, actualOffX, actualOffY);
    function placeGenericFortress(centerX, centerY, radius, playerId, style, irregul  
    999949        var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0];
    1000950        var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1];
    1001951        var angle = getAngle(startX, startY, targetX, targetY);
    1002         var wallElement = "wallLong";
     952        var wallElement = "long";
    1003953        if ((pointIndex + 1) % gateOccurence == 0)
    1004954            wallElement = "gate";
    1005         var entPath = wallStyles[style][wallElement].entPath;
     955
     956        var entPath = getWallElement(style, wallElement).entPath;
    1006957        if (entPath)
    1007958        {
    1008959            placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX
    1009960                startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY
    1010                 entPath, playerId, angle - PI/2 + wallStyles[style][wallElement].angle);
     961                entPath, playerId, angle - PI/2 + getWallElement(style, wallElement).angle);
    1011962        }
    1012963        // Place tower
    1013964        var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0];
    1014965        var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1];
    1015966        var angle = getAngle(startX, startY, targetX, targetY);
    1016         placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style]["tower"].entPath, playerId, angle - PI/2 + wallStyles[style]["tower"].angle);
     967
     968        var tower = getWallElement(style, "tower");
     969        placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], tower.entPath, playerId, angle - PI/2 + tower.angle);
    1017970    }
    1018971}
  • binaries/data/mods/public/maps/random/wall_demo.js

    const distToOtherWalls = 10;  
    6161var buildableMapSize = mapSize - 2 * distToMapBorder;
    6262var actualX = distToMapBorder;
    6363var actualY = distToMapBorder;
    64 // Wall styles are chosen by strings so the civ strings got by getCivCode() can be used
    65 var wallStyleList = getCivList();
    66 // Other styles may be available as well...
    67 wallStyleList.push("rome_siege");
    68 wallStyleList.push("palisades");
    69 // Check if all wall styles are present and remove unknown ones
    70 for (var i = 0; i < wallStyleList.length; i++)
    71     if (!wallStyles.hasOwnProperty(wallStyleList[i]))
    72         wallStyleList.splice(i, 1);
    73 
     64var wallStyleList = g_WallStyleList;
    7465
    7566////////////////////////////////////////
    7667// Custom wall placement (element based)
    7768////////////////////////////////////////
    78 var wall = ['endLeft', 'wallLong', 'tower', 'tower', 'tower', 'wall', 'outpost', 'wall', 'cornerOut', 'wall', 'cornerIn', 'wall', 'house', 'endRight', 'entryTower', 'endLeft', 'wallShort', 'barracks', 'gate', 'tower', 'wall', 'endRight'];
     69var wall = ['start', 'long', 'tower', 'medium', 'outpost', 'medium', 'cornerOut', 'medium', 'cornerIn', 'medium', 'house', 'end', 'entryTower', 'start', 'short', 'barracks', 'gate', 'tower', 'medium', 'fort', 'medium', 'end'];
    7970for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
    8071{
    8172    var startX = actualX + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the first wall element
    for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)  
    8475    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)
    8576    // That means the wall will be build towards top (positive Y) if no corners are used
    8677    var playerId = 0; // Owner of the wall (like in placeObject). 0 is Gaia, 1 is Player 1 (default color blue), ...
    87     placeWall(startX, startY, wall, style, playerId, orientation); // Actually placing the wall
     78    placeWall(startX, startY, wall, style, playerId, orientation); // Actually place the wall
    8879}
    8980actualX = distToMapBorder; // Reset actualX
    9081actualY += 80 + distToOtherWalls; // Increase actualY for next wall placement method
    9182
     83
    9284//////////////////////////////////////////////////////////////
    9385// Default fortress placement (chosen by fortress type string)
    9486//////////////////////////////////////////////////////////////
    for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)  
    10597    placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress
    10698}
    10799actualX = distToMapBorder; // Reset actualX
    108 actualY += 2 * fortressRadius + 2 * distToOtherWalls; // Increase actualY for next wall placement method
     100actualY += 2 * fortressRadius + distToOtherWalls; // Increase actualY for next wall placement method
     101
     102//////////////////////////////////////////////////////////////
     103// 'generic' fortress placement (iberian wall circuit code)
     104//////////////////////////////////////////////////////////////
     105var radius = min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall circle
     106for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
     107{
     108    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the fortress
     109    var centerY = actualY + radius; // Y coordinate of the center of the fortress
     110    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
     111    var playerId = 0; // Owner of the wall. 0 is Gaia, 1 is Player 1 (default color blue), ...
     112    placeGenericFortress(centerX, centerY, radius, playerId, style); // Actually place the fortress
     113    placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress
     114}
     115actualX = distToMapBorder; // Reset actualX
     116actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
    109117
    110118//////////////////////////
    111119// Circular wall placement
    for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)  
    118126{
    119127    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle
    120128    var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
    121     var wallPart = ['tower', 'wall', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall']
     129    var wallPart = ['tower', 'medium', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall']
    122130    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
    123131    var maxAngle = PI/2 * (styleIndex%3 + 2); // How far the wall should circumvent the center
    124132    placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle); // Actually placing the wall
    for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)  
    128136actualX = distToMapBorder; // Reset actualX
    129137actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
    130138
    131 ///////////////////////////
    132 // Polygonal wall placement
    133 ///////////////////////////
     139///////////////////////////////////
     140// Regular Polygonal wall placement
     141///////////////////////////////////
    134142// NOTE: Don't use bending wall elements like corners here!
    135143var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons
    136144var centerY = actualY + radius; // Y coordinate of the center of the wall polygon
    for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)  
    140148    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle
    141149    var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
    142150    var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon
    143     var wallPart = ['wall', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall']
     151    var wallPart = ['medium', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall']
    144152    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
    145153    var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have
    146154    var skipFirstWall = true; // If the wall should be open towards orientation
    for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)  
    151159actualX = distToMapBorder; // Reset actualX
    152160actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
    153161
     162/////////////////////////////////////
     163// Irregular Polygonal wall placement
     164/////////////////////////////////////
     165// NOTE: Don't use bending wall elements like corners here!
     166var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons
     167var centerY = actualY + radius; // Y coordinate of the center of the wall polygon
     168var orientation = 0; // Where the wall circle will be open if ???, see below. Otherwise where the first wall will be placed
     169for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)
     170{
     171    var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle
     172    var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
     173    var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon
     174    var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
     175    var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have
     176    var skipFirstWall = true; // If the wall should be open towards orientation
     177    placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, undefined, skipFirstWall);
     178    placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the wall circle
     179    orientation += PI/16; // Increasing orientation to see how rotation works (like for object placement)
     180}
     181actualX = distToMapBorder; // Reset actualX
     182actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method
     183
     184
    154185////////////////////////
    155186// Linear wall placement
    156187////////////////////////
    for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)  
    166197        var endX = startX; // X coordinate the wall will end
    167198        var endY = actualY + (wallIndex + 1) * maxWallLength/numWallsPerStyle; // Y coordinate the wall will end
    168199        var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ...
    169         var wallPart = ['tower', 'wall']; // List of wall elements the wall will be build of
     200        var wallPart = ['tower', 'medium']; // List of wall elements the wall will be build of
    170201        var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'
    171202        placeLinearWall(startX, startY, endX, endY, wallPart, style, playerId); // Actually placing the wall
    172203        // placeObject(startX, startY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall begins
  • binaries/data/mods/public/maps/random/wall_demo.json

     
    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

    WallPiece.prototype.Schema =  
    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

    WallSet.prototype.Schema =  
    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

     
    110110        }
    111111    ],
    112112    "WallSets":
    113     {
    114         "Palisades":
    115         {
    116             "Template": "other/wallset_palisade",
    117             "Scale": 0.55
    118         },
    119         "Stone":
    120         {
    121             "Template": "structures/athen_wallset_stone",
    122             "Scale": 1.5
    123         }
    124     },
     113    [
     114        "other/wallset_palisade",
     115        "structures/athen_wallset_stone"
     116    ],
    125117    "StartEntities":
    126118    [
    127119        {
  • binaries/data/mods/public/simulation/data/civs/brit.json

     
    8888        }
    8989    ],
    9090    "WallSets":
    91     {
    92         "Palisades":
    93         {
    94             "Template": "other/wallset_palisade",
    95             "Scale": 0.55
    96         },
    97         "Stone":
    98         {
    99             "Template": "structures/athen_wallset_stone",
    100             "Scale": 1.5
    101         }
    102     },
     91    [
     92        "other/wallset_palisade",
     93        "structures/brit_wallset_stone"
     94    ],
    10395    "StartEntities":
    10496    [
    10597        {
  • binaries/data/mods/public/simulation/data/civs/cart.json

     
    113113        }       
    114114    ],
    115115    "WallSets":
    116     {
    117         "Palisades":
    118         {
    119             "Template": "other/wallset_palisade",
    120             "Scale": 0.55
    121         },
    122         "Stone":
    123         {
    124             "Template": "structures/athen_wallset_stone",
    125             "Scale": 1.8
    126         }
    127     },
     116    [
     117        "other/wallset_palisade",
     118        "structures/cart_wallset_stone"
     119    ],
    128120    "StartEntities":
    129121    [
    130122        {
  • binaries/data/mods/public/simulation/data/civs/gaul.json

     
    8888        }
    8989    ],
    9090    "WallSets":
    91     {
    92         "Palisades":
    93         {
    94             "Template": "other/wallset_palisade",
    95             "Scale": 0.55
    96         },
    97         "Stone":
    98         {
    99             "Template": "structures/athen_wallset_stone",
    100             "Scale": 1.5
    101         }
    102     },
     91    [
     92        "other/wallset_palisade",
     93        "structures/gaul_wallset_stone"
     94    ],
    10395    "StartEntities":
    10496    [
    10597        {
  • binaries/data/mods/public/simulation/data/civs/iber.json

     
    8686        }
    8787    ],
    8888    "WallSets":
    89     {
    90         "Palisades":
    91         {
    92             "Template": "other/wallset_palisade",
    93             "Scale": 0.55
    94         },
    95         "Stone":
    96         {
    97             "Template": "structures/athen_wallset_stone",
    98             "Scale": 1.5
    99         }
    100     },
     89    [
     90        "other/wallset_palisade",
     91        "structures/iber_wallset_stone"
     92       
     93    ],
    10194    "StartEntities":
    10295    [
    10396        {
  • binaries/data/mods/public/simulation/data/civs/mace.json

     
    115115        }
    116116    ],
    117117    "WallSets":
    118     {
    119         "Palisades":
    120         {
    121             "Template": "other/wallset_palisade",
    122             "Scale": 0.55
    123         },
    124         "Stone":
    125         {
    126             "Template": "structures/athen_wallset_stone",
    127             "Scale": 1.5
    128         }
    129     },
     118    [
     119        "other/wallset_palisade",
     120        "structures/mace_wallset_stone"
     121       
     122    ],
    130123    "StartEntities":
    131124    [
    132125        {
  • binaries/data/mods/public/simulation/data/civs/maur.json

     
    9595        }
    9696    ],
    9797    "WallSets":
    98     {
    99         "Palisades":
    100         {
    101             "Template": "other/wallset_palisade",
    102             "Scale": 0.55
    103         },
    104         "Stone":
    105         {
    106             "Template": "structures/athen_wallset_stone",
    107             "Scale": 1.5
    108         }
    109     },
     98    [
     99        "other/wallset_palisade",
     100        "structures/maur_wallset_stone"
     101       
     102    ],
    110103    "StartEntities":
    111104    [
    112105        {
  • binaries/data/mods/public/simulation/data/civs/pers.json

     
    105105        }
    106106    ],
    107107    "WallSets":
    108     {
    109         "Palisades":
    110         {
    111             "Template": "other/wallset_palisade",
    112             "Scale": 0.55
    113         },
    114         "Stone":
    115         {
    116             "Template": "structures/athen_wallset_stone",
    117             "Scale": 1.5
    118         }
    119     },
     108    [
     109        "other/wallset_palisade",
     110        "structures/pers_wallset_stone"
     111       
     112    ],
    120113    "StartEntities":
    121114    [
    122115        {
  • binaries/data/mods/public/simulation/data/civs/ptol.json

     
    114114        }
    115115    ],
    116116    "WallSets":
    117     {
    118         "Palisades":
    119         {
    120             "Template": "other/wallset_palisade",
    121             "Scale": 0.55
    122         },
    123         "Stone":
    124         {
    125             "Template": "structures/athen_wallset_stone",
    126             "Scale": 1.5
    127         }
    128     },
     117    [
     118        "other/wallset_palisade",
     119        "structures/ptol_wallset_stone"
     120       
     121    ],
    129122    "StartEntities":
    130123    [
    131124        {
  • binaries/data/mods/public/simulation/data/civs/rome.json

     
    9090        }
    9191    ],
    9292    "WallSets":
    93     {
    94         "Palisades":
    95         {
    96             "Template": "other/wallset_palisade",
    97             "Scale": 0.55
    98         },
    99         "Stone":
    100         {
    101             "Template": "structures/athen_wallset_stone",
    102             "Scale": 1.5
    103         },
    104         "Siege":
    105         {
    106             "Template": "structures/rome_wallset_siege",
    107             "Scale": 1.5
    108         }
    109     },
     93    [
     94        "other/wallset_palisade",
     95        "structures/rome_wallset_stone",
     96        "structures/rome_wallset_siege"
     97       
     98    ],
    11099    "StartEntities":
    111100    [
    112101        {
  • binaries/data/mods/public/simulation/data/civs/sele.json

     
    115115        }
    116116    ],
    117117    "WallSets":
    118     {
    119         "Palisades":
    120         {
    121             "Template": "other/wallset_palisade",
    122             "Scale": 0.55
    123         },
    124         "Stone":
    125         {
    126             "Template": "structures/athen_wallset_stone",
    127             "Scale": 1.5
    128         }
    129     },
     118    [
     119        "other/wallset_palisade",
     120        "structures/sele_wallset_stone"
     121       
     122    ],
    130123    "StartEntities":
    131124    [
    132125        {
  • binaries/data/mods/public/simulation/data/civs/spart.json

     
    106106        }
    107107    ],
    108108    "WallSets":
    109     {
    110         "Palisades":
    111         {
    112             "Template": "other/wallset_palisade",
    113             "Scale": 0.55
    114         },
    115         "Stone":
    116         {
    117             "Template": "structures/athen_wallset_stone",
    118             "Scale": 1.5
    119         }
    120     },
     109    [
     110        "other/wallset_palisade",
     111        "structures/spart_wallset_stone"
     112       
     113    ],
    121114    "StartEntities":
    122115    [
    123116        {