Ticket #1449: iber_wall2012-6-7.diff

File iber_wall2012-6-7.diff, 29.7 KB (added by FeXoR, 12 years ago)

Diff for that patch

  • data/mods/public/maps/random/rmgen/misc.js

     
    194194            placePolygonalWall(fx, fz, 15, ['entry'], 'tower', civ, playerid, angle, 7);
    195195        else
    196196        {
    197             placeGenericFortress(fx, fz, 20/*radius*/, playerid, ['tower', 'wall', 'tower', 'entry', 'tower', 'wall'], civ, PI/6/*angle offset (0 to PI/4)*/)
     197            placeGenericFortress(fx, fz, 20/*radius*/, playerid);
    198198        }
    199199    }
    200200}
  • data/mods/public/maps/random/rmgen/wall_builder.js

     
    33////////////////////////////////////////////////////////////////////
    44
    55// To do:
     6// Check if placeGenericFortress always works without gaps for all races
    67// Rename wall elements to fit he entity names so that entity = 'structures/' + 'civ + '_' + wallElement.type in the common case
    78// Add roman army camp to style palisades and add upgraded default palisade fortress types matching civ default fortresses
    89// Add further wall elements cornerHalfIn, cornerHalfOut and adjust default fortress types to better fit in the octagonal territory of a civil center
     
    9293var wallStyles = {};
    9394
    9495// Generic civ dependent wall style definition. 'rome_siege' needs some tweek...
    95 var scaleByCiv = {'athen' : 1.5, 'cart' : 1.8, 'celt' : 1.5, 'hele' : 1.5, 'iber' : 1.5, 'mace' : 1.5, 'pers' : 1.5, 'rome' : 1.5, 'spart' : 1.5, 'rome_siege' : 1.5};
    96 for (var style in scaleByCiv)
     96var wallScaleByType = {'athen' : 1.5, 'cart' : 1.8, 'celt' : 1.5, 'hele' : 1.5, 'iber' : 1.5, 'mace' : 1.5, 'pers' : 1.5, 'rome' : 1.5, 'spart' : 1.5, 'rome_siege' : 1.5};
     97for (var style in wallScaleByType)
    9798{
    9899    var civ = style;
    99100    if (style == 'rome_siege')
    100101        civ = 'rome';
    101102    wallStyles[style] = {};
    102103    // Default wall elements
    103     wallStyles[style]['tower'] = new WallElement('tower', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]);
    104     wallStyles[style]['endLeft'] = new WallElement('endLeft', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); // Same as tower. To be compatible with palisades...
    105     wallStyles[style]['endRight'] = new WallElement('endRight', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); // Same as tower. To be compatible with palisades...
    106     wallStyles[style]['cornerIn'] = new WallElement('cornerIn', 'structures/' + style + '_wall_tower', 5*PI/4, 0, 0.35*scaleByCiv[style], PI/2); // 2^0.5 / 4 ~= 0.35 ~= 1/3
    107     wallStyles[style]['cornerOut'] = new WallElement('cornerOut', 'structures/' + style + '_wall_tower', 3*PI/4, 0.71*scaleByCiv[style], 0, -PI/2); // // 2^0.5 / 2 ~= 0.71 ~= 2/3
    108     wallStyles[style]['wallShort'] = new WallElement('wallShort', 'structures/' + style + '_wall_short', 0*PI, 2*scaleByCiv[style]);
    109     wallStyles[style]['wall'] = new WallElement('wall', 'structures/' + style + '_wall_medium', 0*PI, 4*scaleByCiv[style]);
    110     wallStyles[style]['wallLong'] = new WallElement('wallLong', 'structures/' + style + '_wall_long', 0*PI, 6*scaleByCiv[style]);
     104    wallStyles[style]['tower'] = new WallElement('tower', 'structures/' + style + '_wall_tower', PI, wallScaleByType[style]);
     105    wallStyles[style]['endLeft'] = new WallElement('endLeft', 'structures/' + style + '_wall_tower', PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
     106    wallStyles[style]['endRight'] = new WallElement('endRight', 'structures/' + style + '_wall_tower', PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
     107    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
     108    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
     109    wallStyles[style]['wallShort'] = new WallElement('wallShort', 'structures/' + style + '_wall_short', 0*PI, 2*wallScaleByType[style]);
     110    wallStyles[style]['wall'] = new WallElement('wall', 'structures/' + style + '_wall_medium', 0*PI, 4*wallScaleByType[style]);
     111    wallStyles[style]['wallMedium'] = new WallElement('wall', 'structures/' + style + '_wall_medium', 0*PI, 4*wallScaleByType[style]);
     112    wallStyles[style]['wallLong'] = new WallElement('wallLong', 'structures/' + style + '_wall_long', 0*PI, 6*wallScaleByType[style]);
    111113    // Gate and entrance wall elements
    112114    if (style == 'cart')
    113         var gateWidth = 3.5*scaleByCiv[style];
     115        var gateWidth = 3.5*wallScaleByType[style];
    114116    else if (style == 'celt')
    115         var gateWidth = 4*scaleByCiv[style];
     117        var gateWidth = 4*wallScaleByType[style];
    116118    // else if (style == 'iber')
    117         // var gateWidth = 5.5*scaleByCiv[style];
     119        // var gateWidth = 5.5*wallScaleByType[style];
    118120    else
    119         var gateWidth = 6*scaleByCiv[style];
     121        var gateWidth = 6*wallScaleByType[style];
    120122    wallStyles[style]['gate'] = new WallElement('gate', 'structures/' + style + '_wall_gate', 0*PI, gateWidth);
    121123    wallStyles[style]['entry'] = new WallElement('entry', undefined, 0*PI, gateWidth);
    122     if (civ == 'iber') // Adjust iberians to have no upkeep at entries with a tower for convinience ATM, may be changed
    123         wallStyles[style]['entryTower'] = new WallElement('entryTower', 'structures/' + civ + '_wall_tower', PI, gateWidth, -4*scaleByCiv[style]);
    124     else
    125         wallStyles[style]['entryTower'] = new WallElement('entryTower', 'structures/' + civ + '_defense_tower', PI, gateWidth, -4*scaleByCiv[style]);
    126     wallStyles[style]['entryFort'] = new WallElement('entryFort', 'structures/' + civ + '_fortress', 0*PI, 8*scaleByCiv[style], 6*scaleByCiv[style]);
     124    wallStyles[style]['entryTower'] = new WallElement('entryTower', 'structures/' + civ + '_defense_tower', PI, gateWidth, -4*wallScaleByType[style]);
     125    wallStyles[style]['entryFort'] = new WallElement('entryFort', 'structures/' + civ + '_fortress', 0*PI, 8*wallScaleByType[style], 6*wallScaleByType[style]);
    127126    // Defensive wall elements with 0 width outside the wall
    128     wallStyles[style]['outpost'] = new WallElement('outpost', 'structures/' + civ + '_outpost', PI, 0, -4*scaleByCiv[style]);
    129     wallStyles[style]['defenseTower'] = new WallElement('defenseTower', 'structures/' + civ + '_defenseTower', PI, 0, -4*scaleByCiv[style]);
     127    wallStyles[style]['outpost'] = new WallElement('outpost', 'structures/' + civ + '_outpost', PI, 0, -4*wallScaleByType[style]);
     128    wallStyles[style]['defenseTower'] = new WallElement('defenseTower', 'structures/' + civ + '_defenseTower', PI, 0, -4*wallScaleByType[style]);
    130129    // Base buildings wall elements with 0 width inside the wall
    131     wallStyles[style]['barracks'] = new WallElement('barracks', 'structures/' + civ + '_barracks', PI, 0, 4.5*scaleByCiv[style]);
    132     wallStyles[style]['civilCentre'] = new WallElement('civilCentre', 'structures/' + civ + '_civil_centre', PI, 0, 4.5*scaleByCiv[style]);
    133     wallStyles[style]['farmstead'] = new WallElement('farmstead', 'structures/' + civ + '_farmstead', PI, 0, 4.5*scaleByCiv[style]);
    134     wallStyles[style]['field'] = new WallElement('field', 'structures/' + civ + '_field', PI, 0, 4.5*scaleByCiv[style]);
    135     wallStyles[style]['fortress'] = new WallElement('fortress', 'structures/' + civ + '_fortress', PI, 0, 4.5*scaleByCiv[style]);
    136     wallStyles[style]['house'] = new WallElement('house', 'structures/' + civ + '_house', PI, 0, 4.5*scaleByCiv[style]);
    137     wallStyles[style]['market'] = new WallElement('market', 'structures/' + civ + '_market', PI, 0, 4.5*scaleByCiv[style]);
    138     wallStyles[style]['mill'] = new WallElement('mill', 'structures/' + civ + '_mill', PI, 0, 4.5*scaleByCiv[style]);
    139     wallStyles[style]['temple'] = new WallElement('temple', 'structures/' + civ + '_temple', PI, 0, 4.5*scaleByCiv[style]);
     130    wallStyles[style]['barracks'] = new WallElement('barracks', 'structures/' + civ + '_barracks', PI, 0, 4.5*wallScaleByType[style]);
     131    wallStyles[style]['civilCentre'] = new WallElement('civilCentre', 'structures/' + civ + '_civil_centre', PI, 0, 4.5*wallScaleByType[style]);
     132    wallStyles[style]['farmstead'] = new WallElement('farmstead', 'structures/' + civ + '_farmstead', PI, 0, 4.5*wallScaleByType[style]);
     133    wallStyles[style]['field'] = new WallElement('field', 'structures/' + civ + '_field', PI, 0, 4.5*wallScaleByType[style]);
     134    wallStyles[style]['fortress'] = new WallElement('fortress', 'structures/' + civ + '_fortress', PI, 0, 4.5*wallScaleByType[style]);
     135    wallStyles[style]['house'] = new WallElement('house', 'structures/' + civ + '_house', PI, 0, 4.5*wallScaleByType[style]);
     136    wallStyles[style]['market'] = new WallElement('market', 'structures/' + civ + '_market', PI, 0, 4.5*wallScaleByType[style]);
     137    wallStyles[style]['mill'] = new WallElement('mill', 'structures/' + civ + '_mill', PI, 0, 4.5*wallScaleByType[style]);
     138    wallStyles[style]['temple'] = new WallElement('temple', 'structures/' + civ + '_temple', PI, 0, 4.5*wallScaleByType[style]);
    140139    // Generic space/gap wall elements
    141     wallStyles[style]['space1'] = new WallElement('space1', undefined, 0*PI, scaleByCiv[style]);
    142     wallStyles[style]['space2'] = new WallElement('space2', undefined, 0*PI, 2*scaleByCiv[style]);
    143     wallStyles[style]['space3'] = new WallElement('space3', undefined, 0*PI, 3*scaleByCiv[style]);
    144     wallStyles[style]['space4'] = new WallElement('space4', undefined, 0*PI, 4*scaleByCiv[style]);
     140    wallStyles[style]['space1'] = new WallElement('space1', undefined, 0*PI, wallScaleByType[style]);
     141    wallStyles[style]['space2'] = new WallElement('space2', undefined, 0*PI, 2*wallScaleByType[style]);
     142    wallStyles[style]['space3'] = new WallElement('space3', undefined, 0*PI, 3*wallScaleByType[style]);
     143    wallStyles[style]['space4'] = new WallElement('space4', undefined, 0*PI, 4*wallScaleByType[style]);
    145144}
    146 
    147145// Add wall fortresses for all generic styles
    148146wallStyles['athen']['wallFort'] = new WallElement('wallFort', 'structures/athen_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
    149147wallStyles['cart']['wallFort'] = new WallElement('wallFort', 'structures/cart_fortress', PI, 5.1, 1.6);
     
    158156wallStyles['rome_siege']['wallFort'] = new WallElement('wallFort', 'structures/rome_army_camp', PI, 7.2, 2);
    159157wallStyles['rome_siege']['entryFort'] = new WallElement('entryFort', 'structures/rome_army_camp', PI, 12, 7);
    160158wallStyles['rome_siege']['house'] = new WallElement('house', 'structures/rome_tent', PI, 0, 4);
     159// Add pseudo "theb" wall style (No actual entities available)
     160wallStyles["theb"] = deepcopy(wallStyles["hele"]);
    161161
    162162// Add special wall styles not well to implement generic (and to show how custom styles can be added)
    163163
    164164// Add special wall style 'palisades'
     165wallScaleByType['palisades'] = 0.55;
    165166wallStyles['palisades'] = {};
    166167wallStyles['palisades']['wall'] = new WallElement('wall', 'other/palisades_rocks_medium', 0*PI, 2.3);
     168wallStyles['palisades']['wallMedium'] = new WallElement('wall', 'other/palisades_rocks_medium', 0*PI, 2.3);
    167169wallStyles['palisades']['wallLong'] = new WallElement('wall', 'other/palisades_rocks_long', 0*PI, 3.5);
    168170wallStyles['palisades']['wallShort'] = new WallElement('wall', 'other/palisades_rocks_short', 0*PI, 1.2);
    169171wallStyles['palisades']['tower'] = new WallElement('tower', 'other/palisades_rocks_tower', -PI/2, 0.7);
    170172wallStyles['palisades']['wallFort'] = new WallElement('wallFort', 'other/palisades_rocks_fort', PI, 1.7);
    171 wallStyles['palisades']['gate'] = new WallElement('gate', 'other/palisades_rocks_gate', 0*PI, 3.6);
     173wallStyles['palisades']['gate'] = new WallElement('gate', 'other/palisades_rocks_gate', PI, 3.6);
    172174wallStyles['palisades']['entry'] = new WallElement('entry', undefined, wallStyles['palisades']['gate'].angle, wallStyles['palisades']['gate'].width);
    173175wallStyles['palisades']['entryTower'] = new WallElement('entryTower', 'other/palisades_rocks_watchtower', 0*PI, wallStyles['palisades']['gate'].width, -3);
    174176wallStyles['palisades']['entryFort'] = new WallElement('entryFort', 'other/palisades_rocks_fort', PI, 6, 3);
     
    181183wallStyles['palisades']['endLeft'] = new WallElement('endLeft', 'other/palisades_rocks_end', PI/2, 0.2);
    182184
    183185// Add special wall style 'road'
     186// NOTE: This is not a wall style in the common sense. Use with care!
     187wallStyles['road'] = {};
     188wallStyles['road']['short'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5);
     189wallStyles['road']['long'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5);
     190wallStyles['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
     191wallStyles['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
     192wallStyles['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
     193wallStyles['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
     194wallStyles['road']['start'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2);
     195wallStyles['road']['end'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2);
     196wallStyles['road']['xStraight'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5);
     197wallStyles['road']['xLeft'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, PI/2);
     198wallStyles['road']['xRight'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, -PI/2);
     199wallStyles['road']['tLeft'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25);
     200wallStyles['road']['tRight'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0*PI, 4.5, -1.25);
    184201
    185202// Add special wall element collection 'other'
    186203// NOTE: This is not a wall style in the common sense. Use with care!
    187204wallStyles['other'] = {};
    188205wallStyles['other']['fence'] = new WallElement('fence', 'other/fence_long', -PI/2, 3.1);
     206wallStyles['other']['fence_medium'] = new WallElement('fence', 'other/fence_long', -PI/2, 3.1);
    189207wallStyles['other']['fence_short'] = new WallElement('fence_short', 'other/fence_short', -PI/2, 1.5);
    190208wallStyles['other']['fence_stone'] = new WallElement('fence_stone', 'other/fence_stone', -PI/2, 2.5);
    191209wallStyles['other']['palisade'] = new WallElement('palisade', 'other/palisades_rocks_short', 0, 1.2);
     
    248266    'cornerOut', 'wall', 'outpost', 'wall', 'cornerIn', 'wall', 'outpost', 'wall', 'endRight'];
    249267fortressTypes['giant'].wall = wallPart.concat(wallPart, wallPart, wallPart);
    250268
     269// Add some "fortress types" for roads (will only work with style "road")
     270// ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"];
     271var wall = ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"];
     272fortressTypes['road01'] = new Fortress('road01', wall);
     273var wall = ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"];
     274fortressTypes['road02'] = new Fortress('road02', wall);
     275var wall = ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"];
     276fortressTypes['road03'] = new Fortress('road03', wall);
     277var wall = ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short",
     278    "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"];
     279fortressTypes['road04'] = new Fortress('road04', wall);
     280var wall = ["start", "tLeft", "short", "xRight",
     281    "curveLeft", "xRight", "tRight", "cornerLeft", "tRight",
     282    "curveLeft", "short", "tRight", "cornerLeft", "xRight",
     283    "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"];
     284fortressTypes['road05'] = new Fortress('road05', wall);
     285
    251286// Add (some) iberian civ bonus fortress (The civ can still be set, just an uncommon default fortress)
    252287var wall = ['gate', 'tower', 'wall', 'cornerIn', 'wallLong', 'tower',
    253288    'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower',
     
    294329// An alignement can be used to get the center of a 'wall' (more likely used for closed walls like fortresses) with the getWallCenter function
    295330function getWallAlignment(startX, startY, wall, style, orientation)
    296331{
    297     orientation = (orientation !== undefined) ? orientation : 0*PI;
    298     var alignment = []
     332    orientation = (orientation || 0*PI);
     333    var alignment = [];
    299334    var wallX = startX;
    300335    var wallY = startY;
    301336    for (var i = 0; i < wall.length; i++)
     
    325360                wallX += element.indent * cos(orientation);
    326361                wallY += element.indent * sin(orientation);
    327362            }
    328             // Set the next coordinates of the next element in the wall (meaning without indentation adjustment)
     363            // Set the next coordinates of the next element in the wall without indentation adjustment
    329364            wallX -= distance * sin(orientation);
    330365            wallY += distance * cos(orientation);
    331366        }
     
    421456// style: Optional. An wall style string (like defined in the 'wallStyles' dictionary). Default is 'palisades'
    422457// playerId: Optional. The walls owners player ID (like in the function 'placeObject' so 0 is gaia, 1 is the first player), Default is 0 (gaia)
    423458// endWithFirst: Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true
     459// TODO: Maybe add angle offset for more generic looking?
    424460function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId, endWithFirst)
    425461{
    426462    // Setup optional arguments to the default
     
    488524////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    489525// The wall is not necessarily closed depending on the optional argument maxAngle (better name?)
    490526// NOTE: Don't use wall elements with bending like corners!
    491 // Todo: add eccentricity
     527// TODO: Add eccentricity and maxBendOff functionality (untill now an unused argument)
    492528function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff)
    493529{
    494530    // Setup optional arguments to the default
     
    581617/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    582618// NOTE: Don't use wall elements with bending like corners!
    583619// TODO: Check some arguments
    584 // TODO: Add eccentricity and irregularity (how far the corners can differ from a regulare convex poygon)
     620// TODO: Add eccentricity and perhaps make it call placeIrregularPolygonalWall with irregularity = 0
    585621function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall)
    586622{
    587623    // Setup optional arguments to the default
     
    620656////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    621657// Place an irregular polygonal wall of some wall parts to choose from arround centerX/centerY with the given radius
    622658////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    623 // NOTE: Under construction!!!
    624659// NOTE: wallPartList is put to the end because it's hardest to set
    625660// NOTE: Don't use wall elements with bending like corners!
    626661// TODO: Check some arguments
    627 // TODO: Add eccentricity and irregularity (how far the corners can differ from a regulare convex poygon)
     662// TODO: Add eccentricity
    628663function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment)
    629664{
    630665    // Generating a generic wall part assortment with each wall part including 1 gate enlengthend by walls and towers
     
    721756    }
    722757}
    723758
    724 // Just a test function, USE WITH CARE!
     759////////////////////////////////////////////////////////////////////////////////////////////////////////
     760//
     761//  Place generic fortress with towers at the edges connected with long walls and gates
     762//
     763//  This is the default Iberian civ bonus starting wall
     764//
     765//  style          Which wall style should be used, default is the given players civ, palisades for gaia
     766//  irregularity   How irregular the wall will be, 0 -> circle, 1 -> very spiky, default is 0.5
     767//  gateOccurence  Integer number, every n walls will be gates instead, default is 3
     768//  maxTrys        How often the function tries to find a better fitting shape at max, default is 100
     769//
     770////////////////////////////////////////////////////////////////////////////////////////////////////////
     771function placeGenericFortress(centerX, centerY, radius, playerId, style, irregularity, gateOccurence, maxTrys)
     772{
     773    // Setup optional arguments
     774    radius = (radius || 20);
     775    playerId = (playerId || 0);
     776    if (playerId == 0)
     777        style = (style || "palisades");
     778    else
     779        style = (style || g_MapSettings.PlayerData[playerId-1].Civ);
     780    irregularity = (irregularity || 0.5);
     781    gateOccurence = (gateOccurence || 3);
     782    maxTrys = (maxTrys || 100);
     783    // Setup some vars
     784    var startAngle = randFloat(0, 2*PI);
     785    var actualOffX = radius*cos(startAngle);
     786    var actualOffY = radius*sin(startAngle);
     787    var actualAngle = startAngle;
     788    var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width;
     789    // Searching for a well fitting point derivation
     790    var tries = 0;
     791    var bestPointDerivation = undefined;
     792    var minOverlap = 1000;
     793    var overlap = undefined;
     794    while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10)
     795    {
     796        var pointDerivation = [];
     797        var distanceToTarget = 1000;
     798        var targetReached = false;
     799        while (!targetReached)
     800        {
     801            var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance);
     802            var tmpAngle = getAngle(actualOffX, actualOffY,
     803                (radius + indent)*cos(actualAngle + (pointDistance / radius)),
     804                (radius + indent)*sin(actualAngle + (pointDistance / radius)));
     805            actualOffX += pointDistance*cos(tmpAngle);
     806            actualOffY += pointDistance*sin(tmpAngle);
     807            actualAngle = getAngle(0, 0, actualOffX, actualOffY);
     808            pointDerivation.push([actualOffX, actualOffY]);
     809            distanceToTarget = getDistance(actualOffX, actualOffY, pointDerivation[0][0], pointDerivation[0][1]);
     810            if ( pointDerivation.length > 3 && distanceToTarget < pointDistance) // Could be done better...
     811            {
     812                targetReached = true;
     813                overlap = pointDistance - getDistance(pointDerivation[pointDerivation.length - 1][0], pointDerivation[pointDerivation.length - 1][1], pointDerivation[0][0], pointDerivation[0][1]);
     814                if (overlap < minOverlap)
     815                {
     816                    minOverlap = overlap;
     817                    bestPointDerivation = pointDerivation;
     818                }
     819            }
     820        }
     821        tries++;
     822    }
     823    log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries");
     824    // Place wall
     825    for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++)
     826    {
     827        var startX = centerX + bestPointDerivation[pointIndex][0];
     828        var startY = centerY + bestPointDerivation[pointIndex][1];
     829        var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0];
     830        var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1];
     831        var angle = getAngle(startX, startY, targetX, targetY);
     832        var wallElement = "wallLong";
     833        if ((pointIndex + 1) % gateOccurence == 0)
     834            wallElement = "entry";
     835        if (wallStyles[style][wallElement].entity)
     836        {
     837            placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX
     838                startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY
     839                wallStyles[style][wallElement].entity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle);
     840        }
     841        // Place tower
     842        var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0];
     843        var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1];
     844        var angle = getAngle(startX, startY, targetX, targetY);
     845        placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style]["tower"].entity, playerId, angle - PI/2 + wallStyles[style]["tower"].angle);
     846    }
     847}
     848
     849/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     850// Place an generic 'organic' looking wall of repeatant wall elements given by wallPart roughly arround centerX/centerY with roughly the given radius
     851/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    725852// radius: A float seting the aproximate radius of the fortress
    726 // maxBendOff: Optional, The maximum random bending offset of the wall elements NOTE: If maxBendOff > PI/2 the wall might never close!!!
    727 // wallPart: Optional, An array of wall element string, example: ["tower", "wall"] NOTE: Don't use wall elements with bending!!!
    728 function placeGenericFortress(centerX, centerY, radius, playerId, wallPart, style, maxBendOff)
     853// maxBendOff: Optional, The maximum random bending offset of the wall elements
     854// NOTE: If maxBendOff > PI/3 the wall might not circumvent the center, if > PI/2 the wall might wind up in an infinite loop!!!
     855// wallPart: Optional, An array of wall element string, example: ["tower", "wall"]
     856// NOTE: Don't use wall elements with bending like corners!
     857function placeOrganicFortress(centerX, centerY, radius, playerId, wallPart, style, maxBendOff)
    729858{
    730     if (wallPart == undefined)
     859    // Setup optional arguments to the default
     860    if (wallPart === undefined)
    731861        wallPart = ['tower', 'wall', 'tower', 'entry', 'tower', 'wall'];
    732     if (maxBendOff > PI/2 || maxBendOff < 0)
    733         warn("setGenericFortress maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff);
    734862    if (maxBendOff === undefined)
    735863        maxBendOff = 0;
    736     var wallLength = 0;
    737     for (var eleIndex = 0; eleIndex < wallPart.length; eleIndex++)
    738     {
    739         wallLength += wallStyles[style][wallPart[eleIndex]].width
    740     }
    741     if (wallLength > 2*PI*radius || wallLength <= 0)
    742         warn("setGenericFortress: sum of the width of wall's elements should satisfy 0 < total length < 2*PI*radius but: radius = " + radius + ", wallPart = " + wallPart + " with total length of " + wallLength);
    743    
    744     var minEleWidth = 1000000; // Assuming the smallest element is about as wide as deep.
    745     for (var eleIndex = 0; eleIndex < wallPart.length; eleIndex++)
    746     {
    747         eleWidth = wallStyles[style][wallPart[eleIndex]].width;
    748         if (eleWidth < minEleWidth)
    749             minEleWidth = eleWidth;
    750     }
    751     var widthSafty = minEleWidth/4; // Can be done better...
    752    
     864    // Check arguments for sane values
     865    if (maxBendOff > PI/3 || maxBendOff < 0)
     866        warn("placeOrganicFortress maxBendOff sould satisfy 0 < maxBendOff < PI/3 (~1) to ensure stability but it is: " + maxBendOff);
     867    // Check wall part length against shortest theoretical total wall length (circle perimeter)
     868    var wallPartLength = getWallLength(wallPart, style);
     869    if (wallPartLength > PI*radius || wallPartLength <= 0)
     870        warn("placeOrganicFortress: Given wall part is longer than half the circle perimeter of given radius: Half circle perimeter ~= " + round(PI*radius) +", wallPart total length ~= " + round(wallPartLength));
     871    // Setting up some variables
    753872    var x = radius;
    754873    var y = 0;
    755874    var angle = 0;
     
    757876    var targetY = 0;
    758877    var targetReached = false;
    759878    var eleIndex = 0;
     879    // Start the evil while loope ^^
    760880    while (targetReached == false)
    761881    {
    762882        var wallElement = wallStyles[style][wallPart[eleIndex % wallPart.length]];
    763         var eleWidth = wallElement.width - widthSafty;
    764         // Stabalized bendOff
     883        var eleWidth = wallElement.width; // Reducing this a bit to avoid gaps might be good
     884        // Stabalized bendOff. TODO: Ensure positive eleAngleWidth!!!
    765885        var actualRadius = getDistance(centerX, centerY, centerX + x, centerY + y);
    766886        var bendOff = randFloat(-maxBendOff*radius/actualRadius, maxBendOff*actualRadius/radius);
    767887        // Element width in radians
     
    774894        x = placeX - eleWidth/2 * sin(eleAngle);
    775895        y = placeY + eleWidth/2 * cos(eleAngle);
    776896        angle += eleAngleWidth;
    777         if (eleIndex % wallPart.length == 0 && eleIndex > wallPart.length && (getDistance(x, y, targetX, targetY) < wallLength || angle > 2*PI))
     897        if (eleIndex % wallPart.length == 0 && eleIndex > wallPart.length && (getDistance(x, y, targetX, targetY) < wallPartLength || angle > 2*PI))
    778898            targetReached = true;
    779899        eleIndex++;
    780         // if (eleIndex == 10)
    781             // break;
    782900    }
    783     placeLinearWall(centerX + x, centerY + y, centerX + targetX, centerY + targetY, ['wall', 'tower'], style, playerId, true);
     901    // Close wall with simple linear wall
     902    if (getDistance(centerX + x, centerY + y, centerX + targetX, centerY + targetY) > wallStyles[style]['wallLong'].width)
     903        placeLinearWall(centerX + x, centerY + y, centerX + targetX, centerY + targetY, ['wall', 'tower'], style, playerId, true);
    784904}