diff --git a/binaries/data/mods/public/maps/random/fortress.js b/binaries/data/mods/public/maps/random/fortress.js index 54fec7977e..a58f5823bc 100644 --- a/binaries/data/mods/public/maps/random/fortress.js +++ b/binaries/data/mods/public/maps/random/fortress.js @@ -155,7 +155,7 @@ for (var i=0; i < numPlayers; i++) createArea(placer,[new TerrainPainter(tRoad), paintClass(clPlayer)]); // Place custom fortress - if (civ == "celt" || civ == "iber") + if (civ == "brit" || civ == "celt" || civ == "gaul" || civ == "iber") { var wall = ['entryTower', 'wall', 'wall', 'cornerIn', 'wall', 'barracks', 'wall', 'gate', 'wall', 'house', 'wall', diff --git a/binaries/data/mods/public/maps/random/rmgen/misc.js b/binaries/data/mods/public/maps/random/rmgen/misc.js index 4bfe007318..ca99589bcd 100644 --- a/binaries/data/mods/public/maps/random/rmgen/misc.js +++ b/binaries/data/mods/public/maps/random/rmgen/misc.js @@ -1 +1 @@ -///////////////////////////////////////////////////////////////////////////////////////// // passageMaker // // Function for creating shallow water between two given points by changing the heiight of all tiles in // the path with height less than or equal to "maxheight" to "height" // // x1,z1: Starting point of path // x2,z2: Ending point of path // width: Width of the shallow // maxheight: Maximum height that it changes // height: Height of the shallow // smooth: smooth elevation in borders // tileclass: (Optianal) - Adds those tiles to the class given // terrain: (Optional) - Changes the texture of the elevated land // ///////////////////////////////////////////////////////////////////////////////////////// function passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain) { var mapSize = g_Map.size; for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var a = z1-z2; var b = x2-x1; var c = (z1*(x1-x2))-(x1*(z1-z2)); var dis = abs(a*ix + b*iz + c)/sqrt(a*a + b*b); var k = (a*ix + b*iz + c)/(a*a + b*b); var my = iz-(b*k); var inline = 0; if (b == 0) { if ((iz <= Math.max(z1,z2))&&(Math.min(z1,z2))) { inline = 1; } } else { if ((my <= Math.max(z1,z2))&&(my >= Math.min(z1,z2))) { inline = 1; } } if ((dis <= width)&&(inline)) { if(g_Map.getHeight(ix, iz) <= maxheight) { if (dis >= width - smooth) { g_Map.setHeight(ix, iz, ((width - dis)*(height)+(g_Map.getHeight(ix, iz))*(dis + smooth - width))/(smooth)/2); } else { g_Map.setHeight(ix, iz, height); } if (tileclass !== undefined) { addToClass(ix, iz, tileclass); } if (terrain !== undefined) { placeTerrain(ix, iz, terrain); } } } } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //rndRiver is a fuction that creates random values useful for making a jagged river. // //it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi //it needs the "seed" parameter to use it to make random curves that don't get broken. //seed must be created using randFloat(). or else it won't work // // f: Input: Same as angle in a sine function // seed: Random Seed: Best to implement is to use randFloat() // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function rndRiver(f, seed) { var rndRq = seed; var rndRw = rndRq; var rndRe = 0; var rndRr = f-floor(f); var rndRa = 0; for (var rndRx=0; rndRx<=floor(f); rndRx++) { rndRw = 10*(rndRw-floor(rndRw)); } if (rndRx%2==0) { var rndRs = -1; } else { var rndRs = 1; } rndRe = (floor(rndRw))%5; if (rndRe==0) { rndRa = (rndRs)*2.3*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.5); } else if (rndRe==1) { rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.3)*(rndRr-0.7); } else if (rndRe==2) { rndRa = (rndRs)*22*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.3)*(rndRr-0.3)*(rndRr-0.8); } else if (rndRe==3) { rndRa = (rndRs)*180*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.2)*(rndRr-0.4)*(rndRr-0.6)*(rndRr-0.6)*(rndRr-0.8); } else if (rndRe==4) { rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.7); } return rndRa; } ///////////////////////////////////////////////////////////////////////////////////////// // createStartingPlayerEntities // // Creates the starting player entities // fx&fz: position of player base // playerid: id of player // civEntities: use getStartingEntities(id-1) fo this one // BUILDING_ANGlE: angle of main base building // /////////////////////////////////////////////////////////////////////////////////////////// function createStartingPlayerEntities(fx, fz, playerid, civEntities, BUILDING_ANGlE) { var uDist = 6; var uSpace = 2; placeObject(fx, fz, civEntities[0].Template, playerid, BUILDING_ANGlE); for (var j = 1; j < civEntities.length; ++j) { var uAngle = BUILDING_ANGlE - PI * (2-j) / 2; var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); placeObject(ux, uz, civEntities[j].Template, playerid, uAngle); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeCivDefaultEntities // // Creates the default starting player entities depending on the players civ // fx&fy: position of player base // playerid: id of player // angle: angle of main base building, optional, default is BUILDING_ANGlE // kwargs: Takes some optional keyword arguments to tweek things // 'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeCivDefaultEntities(fx, fz, playerid, angle, kwargs) { // Unpack kwargs kwargs = (kwargs || {}); var iberWall = 'walls'; if ('iberWall' in kwargs) iberWall = kwargs['iberWall']; // Place default civ starting entities var civ = g_MapSettings.PlayerData[playerid-1].Civ; var civEntities = getStartingEntities(playerid-1); var uDist = 6; var uSpace = 2; placeObject(fx, fz, civEntities[0].Template, playerid, angle); for (var j = 1; j < civEntities.length; ++j) { var uAngle = angle - PI * (2-j) / 2; var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); placeObject(ux, uz, civEntities[j].Template, playerid, uAngle); } } // Add defensive structiures for Iberians as their civ bonus if (civ == 'iber' && iberWall != false) { if (iberWall == 'towers') placePolygonalWall(fx, fz, 15, ['entry'], 'tower', civ, playerid, angle, 7); else { placeGenericFortress(fx, fz, 20/*radius*/, playerid, ['tower', 'wall', 'tower', 'entry', 'tower', 'wall'], civ, PI/6/*angle offset (0 to PI/4)*/) } } } ///////////////////////////////////////////////////////////////////////////////////////// // paintTerrainBasedOnHeight // // paints the tiles which have a height between minheight and maxheight with the given terrain // minheight: minimum height of the tile // maxheight: maximum height of the tile // mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight. // 1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than // minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight // terrain: intended terrain texture // /////////////////////////////////////////////////////////////////////////////////////////// function paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain) { var mSize = g_Map.size; for (var qx = 0; qx < mSize; qx++) { for (var qz = 0; qz < mSize; qz++) { if (mode == 0) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 1) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 2) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 3) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { placeTerrain(qx, qz, terrain); } } } } } ///////////////////////////////////////////////////////////////////////////////////////// // paintTileClassBasedOnHeight // // paints the tiles which have a height between minheight and maxheight with the given tile class // minheight: minimum height of the tile // maxheight: maximum height of the tile // mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight. // 1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than // minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight // tileclass: intended tile class // /////////////////////////////////////////////////////////////////////////////////////////// function paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) { var mSize = g_Map.size; for (var qx = 0; qx < mSize; qx++) { for (var qz = 0; qz < mSize; qz++) { if (mode == 0) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 1) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 2) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 3) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { addToClass(qx, qz, tileclass); } } } } } \ No newline at end of file +///////////////////////////////////////////////////////////////////////////////////////// // passageMaker // // Function for creating shallow water between two given points by changing the heiight of all tiles in // the path with height less than or equal to "maxheight" to "height" // // x1,z1: Starting point of path // x2,z2: Ending point of path // width: Width of the shallow // maxheight: Maximum height that it changes // height: Height of the shallow // smooth: smooth elevation in borders // tileclass: (Optianal) - Adds those tiles to the class given // terrain: (Optional) - Changes the texture of the elevated land // ///////////////////////////////////////////////////////////////////////////////////////// function passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain) { var mapSize = g_Map.size; for (var ix = 0; ix < mapSize; ix++) { for (var iz = 0; iz < mapSize; iz++) { var a = z1-z2; var b = x2-x1; var c = (z1*(x1-x2))-(x1*(z1-z2)); var dis = abs(a*ix + b*iz + c)/sqrt(a*a + b*b); var k = (a*ix + b*iz + c)/(a*a + b*b); var my = iz-(b*k); var inline = 0; if (b == 0) { if ((iz <= Math.max(z1,z2))&&(Math.min(z1,z2))) { inline = 1; } } else { if ((my <= Math.max(z1,z2))&&(my >= Math.min(z1,z2))) { inline = 1; } } if ((dis <= width)&&(inline)) { if(g_Map.getHeight(ix, iz) <= maxheight) { if (dis >= width - smooth) { g_Map.setHeight(ix, iz, ((width - dis)*(height)+(g_Map.getHeight(ix, iz))*(dis + smooth - width))/(smooth)/2); } else { g_Map.setHeight(ix, iz, height); } if (tileclass !== undefined) { addToClass(ix, iz, tileclass); } if (terrain !== undefined) { placeTerrain(ix, iz, terrain); } } } } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //rndRiver is a fuction that creates random values useful for making a jagged river. // //it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi //it needs the "seed" parameter to use it to make random curves that don't get broken. //seed must be created using randFloat(). or else it won't work // // f: Input: Same as angle in a sine function // seed: Random Seed: Best to implement is to use randFloat() // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function rndRiver(f, seed) { var rndRq = seed; var rndRw = rndRq; var rndRe = 0; var rndRr = f-floor(f); var rndRa = 0; for (var rndRx=0; rndRx<=floor(f); rndRx++) { rndRw = 10*(rndRw-floor(rndRw)); } if (rndRx%2==0) { var rndRs = -1; } else { var rndRs = 1; } rndRe = (floor(rndRw))%5; if (rndRe==0) { rndRa = (rndRs)*2.3*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.5); } else if (rndRe==1) { rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.3)*(rndRr-0.7); } else if (rndRe==2) { rndRa = (rndRs)*22*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.3)*(rndRr-0.3)*(rndRr-0.8); } else if (rndRe==3) { rndRa = (rndRs)*180*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.2)*(rndRr-0.4)*(rndRr-0.6)*(rndRr-0.6)*(rndRr-0.8); } else if (rndRe==4) { rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.7); } return rndRa; } ///////////////////////////////////////////////////////////////////////////////////////// // createStartingPlayerEntities // // Creates the starting player entities // fx&fz: position of player base // playerid: id of player // civEntities: use getStartingEntities(id-1) fo this one // BUILDING_ANGlE: angle of main base building // /////////////////////////////////////////////////////////////////////////////////////////// function createStartingPlayerEntities(fx, fz, playerid, civEntities, BUILDING_ANGlE) { var uDist = 6; var uSpace = 2; placeObject(fx, fz, civEntities[0].Template, playerid, BUILDING_ANGlE); for (var j = 1; j < civEntities.length; ++j) { var uAngle = BUILDING_ANGlE - PI * (2-j) / 2; var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); placeObject(ux, uz, civEntities[j].Template, playerid, uAngle); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // placeCivDefaultEntities // // Creates the default starting player entities depending on the players civ // fx&fy: position of player base // playerid: id of player // angle: angle of main base building, optional, default is BUILDING_ANGlE // kwargs: Takes some optional keyword arguments to tweek things // 'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeCivDefaultEntities(fx, fz, playerid, angle, kwargs) { // Unpack kwargs kwargs = (kwargs || {}); var iberWall = 'walls'; if ('iberWall' in kwargs) iberWall = kwargs['iberWall']; // Place default civ starting entities var civ = g_MapSettings.PlayerData[playerid-1].Civ; var civEntities = getStartingEntities(playerid-1); var uDist = 6; var uSpace = 2; placeObject(fx, fz, civEntities[0].Template, playerid, angle); for (var j = 1; j < civEntities.length; ++j) { var uAngle = angle - PI * (2-j) / 2; var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); for (var numberofentities = 0; numberofentities < count; numberofentities++) { var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); placeObject(ux, uz, civEntities[j].Template, playerid, uAngle); } } // Add defensive structiures for Iberians as their civ bonus if (civ == 'iber' && iberWall != false) { if (iberWall == 'towers') placePolygonalWall(fx, fz, 15, ['entry'], 'tower', civ, playerid, angle, 7); else placeGenericFortress(fx, fz, 20/*radius*/, playerid); } } ///////////////////////////////////////////////////////////////////////////////////////// // paintTerrainBasedOnHeight // // paints the tiles which have a height between minheight and maxheight with the given terrain // minheight: minimum height of the tile // maxheight: maximum height of the tile // mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight. // 1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than // minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight // terrain: intended terrain texture // /////////////////////////////////////////////////////////////////////////////////////////// function paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain) { var mSize = g_Map.size; for (var qx = 0; qx < mSize; qx++) { for (var qz = 0; qz < mSize; qz++) { if (mode == 0) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 1) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 2) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { placeTerrain(qx, qz, terrain); } } else if (mode == 3) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { placeTerrain(qx, qz, terrain); } } } } } ///////////////////////////////////////////////////////////////////////////////////////// // paintTileClassBasedOnHeight // // paints the tiles which have a height between minheight and maxheight with the given tile class // minheight: minimum height of the tile // maxheight: maximum height of the tile // mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight. // 1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than // minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight // tileclass: intended tile class // /////////////////////////////////////////////////////////////////////////////////////////// function paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) { var mSize = g_Map.size; for (var qx = 0; qx < mSize; qx++) { for (var qz = 0; qz < mSize; qz++) { if (mode == 0) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 1) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) < maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 2) { if ((g_Map.getHeight(qx, qz) > minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { addToClass(qx, qz, tileclass); } } else if (mode == 3) { if ((g_Map.getHeight(qx, qz) >= minheight)&&(g_Map.getHeight(qx, qz) <= maxheight)) { addToClass(qx, qz, tileclass); } } } } } \ No newline at end of file diff --git a/binaries/data/mods/public/maps/random/rmgen/wall_builder.js b/binaries/data/mods/public/maps/random/rmgen/wall_builder.js index c3f9e82159..bb4f0d39d6 100644 --- a/binaries/data/mods/public/maps/random/rmgen/wall_builder.js +++ b/binaries/data/mods/public/maps/random/rmgen/wall_builder.js @@ -3,60 +3,75 @@ //////////////////////////////////////////////////////////////////// // To do: -// Rename wall elements to fit he entity names so that entity = 'structures/' + 'civ + '_' + wallElement.type in the common case -// Add roman army camp to style palisades and add upgraded default palisade fortress types matching civ default fortresses -// Add further wall elements cornerHalfIn, cornerHalfOut and adjust default fortress types to better fit in the octagonal territory of a civil center -// Add civil center, corral, farmstead, field, market, mill, temple -// Adjust default fortress types -// Add wall style 'roads' -// Add trsures to 'others' +// Check if all wall placement methods work with wall elements with entity === undefined (some still might raise errors in that case) +// Rename wall elements to fit the entity names so that entity = "structures/" + "civ + "_" + wallElement.type in the common case (as far as possible) +// Perhaps add roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength +// Perhaps add further wall elements cornerInHalf, cornerOutHalf (banding PI/4) and adjust default fortress types to better fit in the octagonal territory of a civil center +// Perhaps swap angle and width in WallElement class(?) definition +// Adjust argument order to be always the same: +// Coordinates (center/start/target) +// Wall element arguments (wall/wallPart/fortressType/cornerElement) +// playerId (optional, default is 0/gaia) +// wallStyle (optional, default is the players civ/"palisades for gaia") +// angle/orientation (optional, default is 0) +// other (all optional) arguments especially those hard to define (wallPartsAssortment, maybe make an own function for it) +// Some arguments don't clearly match to this concept: +// endWithFirst (wall or other) +// skipFirstWall (wall or other) +// gateOccurence (wall or other) +// numCorners (wall or other) +// skipFirstWall (wall or other) +// maxAngle (angle or other) +// maxBendOff (angle or other, unused ATM!!!) +// irregularity +// maxTrys +// Add tresures to wall style "others" // Adjust documentation -// ?Use available civ-type wall elements rather than palisades: Remove 'endLeft' and 'endRight' as default wall elements and adjust default palisade fortress types? -// ?Remove endRight, endLeft and adjust generic fortress types palisades? +// Perhaps rename "endLeft" to "start" and "endRight" to "end" +// ?Use available civ-type wall elements rather than palisades: Remove "endLeft" and "endRight" as default wall elements and adjust default palisade fortress types? +// ?Remove "endRight", "endLeft" and adjust generic fortress types palisades? // ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads? // ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending? -/////////////////////////////// -// WallElement class definition -/////////////////////////////// - -// argument type: Descriptive string, example: 'wall'. NOTE: Not really needed. Mainly for custom wall elements and to get the wall element type in code. -// argument entity: Optional. Template string to be placed, example: 'structures/cart_wall'. Default is undefined (No entity placed) -// argument angle: Optional. Placement angle so that 'outside' is 'right' (towards positive X like a unit placed with angle 0). Default is 0 (0*PI) -// argument width: Optional. The width it lengthens the wall, width because it's the needed space in a right angle to 'outside'. Default is 0 -// argument indent: Optional. The indentation means its drawn inside (positive values) or pushed outwards (negative values). Default is 0 -// NOTE: Bending is only used for fortresses and custom walls. Linear/circular walls walls use no/generic bending -// argument bending: Optional. How the direction of the wall is changed after this element, positive is bending 'in' (counter clockwise like entity placement) +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// WallElement class definition +// +// Concept: If placed unrotated the wall's course is towards positive Y (top) with "outside" right (+X) and "inside" left (-X) like unrotated entities has their droppoints right (in rmgen) +// The coure of the wall will be changed by corners (bending != 0) and so the "inside"/"outside" direction +// +// type Descriptive string, example: "wallLong". NOTE: Not really needed. Mainly for custom wall elements and to get the wall element type in code +// entity Optional. Template name string of the entity to be placed, example: "structures/cart_wall_long". Default is undefined (No entity placed) +// angle Optional. The angle (float) added to place the entity so "outside" is right when the wall element is placed unrotated. Default is 0 +// width Optional. How far this wall element enlengthens the wall (float), if unrotated the Y space needed. Default is 0 +// indent Optional. The lateral indentation of the entity, drawn "inside" (positive values) or pushed "outside" (negative values). Default is 0 +// bending Optional. How the course of the wall is changed after this element, positive is bending "in"/left/counter clockwise (like entity placement) +// NOTE: Bending is not supported by all placement functions (see there) +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function WallElement(type, entity, angle, width, indent, bending) { - // NOTE: Not all wall elements have a symetry. So there's an direction 'outside' (towards right/positive X by default) - // In this sense 'left'/'right' means left/right of you when standing upon the wall and look 'outside' - // The wall is build towards 'left' so the next wall element will be placed left of the previous one (towards positive Y by default) - // In this sense the wall's direction is left meaning the 'bending' of a corner is used for the element following the corner - // With 'inside' and 'outside' defined as above, corners bend 'in'/'out' meaning placemant angle is increased/decreased (counter clockwise like object placement) this.type = type; - // Wall element type documentation: + // Default wall element type documentation: // Enlengthening straight blocking (mainly left/right symetric) wall elements (Walls and wall fortifications) - // 'wall': A blocking straight wall element that mainly lengthens the wall, self-explanatory - // 'wallShort': self-explanatory - // 'wallLong': self-explanatory - // 'tower': A blocking straight wall element with damage potential (but for palisades) that slightly lengthens the wall, exsample: wall tower, palisade tower(No attack) - // 'wallFort': A blocking straight wall element with massive damage potential that lengthens the wall, exsample: fortress, palisade fort + // "wall" A blocking straight wall element that mainly lengthens the wall, self-explanatory + // "wallShort" self-explanatory + // "wallLong" self-explanatory + // "tower" A blocking straight wall element with damage potential (but for palisades) that slightly lengthens the wall, exsample: wall tower, palisade tower(No attack) + // "wallFort" A blocking straight wall element with massive damage potential that lengthens the wall, exsample: fortress, palisade fort // Enlengthening straight non/custom blocking (mainly left/right symetric) wall elements (Gates and entrys) - // 'gate': A blocking straight wall element with passability determined by owner, example: gate (Functionality not yet implemented) - // 'entry': A non-blocking straight wall element (same width as gate) but without an actual template or just a flag/column/obelisk - // 'entryTower': A non-blocking straight wall element (same width as gate) represented by a single (maybe indented) template, example: defense tower, wall tower, outpost, watchtower - // 'entryFort': A non-blocking straight wall element represented by a single (maybe indented) template, example: fortress, palisade fort + // "gate" A blocking straight wall element with passability determined by owner, example: gate (Functionality not yet implemented) + // "entry" A non-blocking straight wall element (same width as gate) but without an actual template or just a flag/column/obelisk + // "entryTower" A non-blocking straight wall element (same width as gate) represented by a single (maybe indented) template, example: defense tower, wall tower, outpost, watchtower + // "entryFort" A non-blocking straight wall element represented by a single (maybe indented) template, example: fortress, palisade fort // Bending wall elements (Wall corners) - // 'cornerIn': A wall element bending the wall by PI/2 'inside' (left, +, see above), example: wall tower, palisade curve - // 'cornerOut': A wall element bending the wall by PI/2 'outside' (right, -, see above), example: wall tower, palisade curve - // 'cornerHalfIn': A wall element bending the wall by PI/4 'inside' (left, +, see above), example: wall tower, palisade curve. NOTE: Not yet implemented - // 'cornerHalfOut': A wall element bending the wall by PI/4 'outside' (right, -, see above), example: wall tower, palisade curve. NOTE: Not yet implemented + // "cornerIn" A wall element bending the wall by PI/2 "inside" (left, +, see above), example: wall tower, palisade curve + // "cornerOut" A wall element bending the wall by PI/2 "outside" (right, -, see above), example: wall tower, palisade curve + // "cornerHalfIn" A wall element bending the wall by PI/4 "inside" (left, +, see above), example: wall tower, palisade curve. NOTE: Not yet implemented + // "cornerHalfOut" A wall element bending the wall by PI/4 "outside" (right, -, see above), example: wall tower, palisade curve. NOTE: Not yet implemented // Zero length straight indented (mainly left/right symetric) wall elements (Outposts/watchtowers and non-defensive base structures) - // 'outpost': A zero-length wall element without bending far indented so it stands outside the wall, exsample: outpost, defense tower, watchtower - // 'house': A zero-length wall element without bending far indented so it stands inside the wall that grants population bonus, exsample: house, hut, longhouse - // 'barracks': A zero-length wall element without bending far indented so it stands inside the wall that grants unit production, exsample: barracks, tavern, ... + // "outpost" A zero-length wall element without bending far indented so it stands outside the wall, exsample: outpost, defense tower, watchtower + // "house" A zero-length wall element without bending far indented so it stands inside the wall that grants population bonus, exsample: house, hut, longhouse + // "barracks" A zero-length wall element without bending far indented so it stands inside the wall that grants unit production, exsample: barracks, tavern, ... this.entity = entity; this.angle = (angle !== undefined) ? angle : 0*PI; this.width = (width !== undefined) ? width : 0; @@ -64,268 +79,292 @@ function WallElement(type, entity, angle, width, indent, bending) this.bending = (bending !== undefined) ? bending : 0*PI; } - -//////////////////////////// -// Fortress class definition -//////////////////////////// - -// A list would do for symetric fortresses but if 'getCenter' don't do sufficient the center can be set manually -// argument type: Descriptive string, example: 'tiny'. Not really needed (WallTool.wallTypes['type string'] is used). Mainly for custom wall elements. -// argument wall: Optional. Array of wall element strings. Can be set afterwards. Default is an epty array. - // Example: ['entrance', 'wall', 'cornerIn', 'wall', 'gate', 'wall', 'entrance', 'wall', 'cornerIn', 'wall', 'gate', 'wall', 'cornerIn', 'wall'] -// argument center: Optional. Array of 2 floats determinig the vector from the center to the 1st wall element. Can be set afterwards. Default is [0, 0]. (REALLY???) - // NOTE: The center will be recalculated when WallTool.setFortress is called. To avoid this set WallTool.calculateCenter to false. -function Fortress(type, wall, center) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Fortress class definition +// +// A "fortress" here is a closed wall build of multiple wall elements attached togather defined in Fortress.wall +// It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles) +// +// type Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements +// wall Optional. Array of wall element strings. Can be set afterwards. Default is an epty array. +// Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"] +// centerToFirstElement Optional. Object with propertys "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function Fortress(type, wall, centerToFirstElement) { - this.type = type; // Only usefull to get the type of the actual fortress (by 'WallTool.fortress.type') + this.type = type; // Only usefull to get the type of the actual fortress this.wall = (wall !== undefined) ? wall : []; - this.center = [0, 0]; // X/Z offset (in default orientation) from first wall element to center, perhaps should be the other way around... + this.centerToFirstElement = undefined; } -/////////////////////////////////////////////// -// Setup data structure for default wall styles -/////////////////////////////////////////////// - -// A wall style is an associative array with all wall elements of that style in it associated with the wall element type string. -// wallStyles holds all the wall styles within an associative array while a wall style is associated with the civ string or another descriptive strings like 'palisades', 'fence', 'cart', 'celt'... +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// wallStyles data structure for default wall styles +// +// A wall style is an associative array with all wall elements of that style in it associated with the wall element type string +// wallStyles holds all the wall styles within an associative array with the civ string or another descriptive strings as key +// Examples: "athen", "rome_siege", "palisades", "fence", "road" +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// var wallStyles = {}; -// Generic civ dependent wall style definition. 'rome_siege' needs some tweek... -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}; -for (var style in scaleByCiv) +// Generic civ dependent wall style definition. "rome_siege" needs some tweek... +var wallScaleByType = {"athen" : 1.5, "brit" : 1.5, "cart" : 1.8, "celt" : 1.5, "gaul" : 1.5, "hele" : 1.5, "iber" : 1.5, "mace" : 1.5, "pers" : 1.5, "rome" : 1.5, "spart" : 1.5, "rome_siege" : 1.5}; +for (var style in wallScaleByType) { var civ = style; - if (style == 'rome_siege') - civ = 'rome'; + if (style == "rome_siege") + civ = "rome"; wallStyles[style] = {}; // Default wall elements - wallStyles[style]['tower'] = new WallElement('tower', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); - wallStyles[style]['endLeft'] = new WallElement('endLeft', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); // Same as tower. To be compatible with palisades... - wallStyles[style]['endRight'] = new WallElement('endRight', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); // Same as tower. To be compatible with palisades... - 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 - 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 - wallStyles[style]['wallShort'] = new WallElement('wallShort', 'structures/' + style + '_wall_short', 0*PI, 2*scaleByCiv[style]); - wallStyles[style]['wall'] = new WallElement('wall', 'structures/' + style + '_wall_medium', 0*PI, 4*scaleByCiv[style]); - wallStyles[style]['wallLong'] = new WallElement('wallLong', 'structures/' + style + '_wall_long', 0*PI, 6*scaleByCiv[style]); + wallStyles[style]["tower"] = new WallElement("tower", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); + wallStyles[style]["endLeft"] = new WallElement("endLeft", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades... + wallStyles[style]["endRight"] = new WallElement("endRight", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades... + 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 + 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 + wallStyles[style]["wallShort"] = new WallElement("wallShort", "structures/" + style + "_wall_short", 0*PI, 2*wallScaleByType[style]); + wallStyles[style]["wall"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]); + wallStyles[style]["wallMedium"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]); + wallStyles[style]["wallLong"] = new WallElement("wallLong", "structures/" + style + "_wall_long", 0*PI, 6*wallScaleByType[style]); // Gate and entrance wall elements - if (style == 'cart') - var gateWidth = 3.5*scaleByCiv[style]; - else if (style == 'celt') - var gateWidth = 4*scaleByCiv[style]; - // else if (style == 'iber') - // var gateWidth = 5.5*scaleByCiv[style]; + if (style == "cart") + var gateWidth = 3.5*wallScaleByType[style]; + else if (style == "brit" || style == "celt" || style == "gaul") + var gateWidth = 4*wallScaleByType[style]; else - var gateWidth = 6*scaleByCiv[style]; - wallStyles[style]['gate'] = new WallElement('gate', 'structures/' + style + '_wall_gate', 0*PI, gateWidth); - wallStyles[style]['entry'] = new WallElement('entry', undefined, 0*PI, gateWidth); - if (civ == 'iber') // Adjust iberians to have no upkeep at entries with a tower for convinience ATM, may be changed - wallStyles[style]['entryTower'] = new WallElement('entryTower', 'structures/' + civ + '_wall_tower', PI, gateWidth, -4*scaleByCiv[style]); - else - wallStyles[style]['entryTower'] = new WallElement('entryTower', 'structures/' + civ + '_defense_tower', PI, gateWidth, -4*scaleByCiv[style]); - wallStyles[style]['entryFort'] = new WallElement('entryFort', 'structures/' + civ + '_fortress', 0*PI, 8*scaleByCiv[style], 6*scaleByCiv[style]); + var gateWidth = 6*wallScaleByType[style]; + wallStyles[style]["gate"] = new WallElement("gate", "structures/" + style + "_wall_gate", 0*PI, gateWidth); + wallStyles[style]["entry"] = new WallElement("entry", undefined, 0*PI, gateWidth); + wallStyles[style]["entryTower"] = new WallElement("entryTower", "structures/" + civ + "_defense_tower", PI, gateWidth, -4*wallScaleByType[style]); + wallStyles[style]["entryFort"] = new WallElement("entryFort", "structures/" + civ + "_fortress", 0*PI, 8*wallScaleByType[style], 6*wallScaleByType[style]); // Defensive wall elements with 0 width outside the wall - wallStyles[style]['outpost'] = new WallElement('outpost', 'structures/' + civ + '_outpost', PI, 0, -4*scaleByCiv[style]); - wallStyles[style]['defenseTower'] = new WallElement('defenseTower', 'structures/' + civ + '_defenseTower', PI, 0, -4*scaleByCiv[style]); + wallStyles[style]["outpost"] = new WallElement("outpost", "structures/" + civ + "_outpost", PI, 0, -4*wallScaleByType[style]); + wallStyles[style]["defenseTower"] = new WallElement("defenseTower", "structures/" + civ + "_defenseTower", PI, 0, -4*wallScaleByType[style]); // Base buildings wall elements with 0 width inside the wall - wallStyles[style]['barracks'] = new WallElement('barracks', 'structures/' + civ + '_barracks', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['civilCentre'] = new WallElement('civilCentre', 'structures/' + civ + '_civil_centre', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['farmstead'] = new WallElement('farmstead', 'structures/' + civ + '_farmstead', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['field'] = new WallElement('field', 'structures/' + civ + '_field', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['fortress'] = new WallElement('fortress', 'structures/' + civ + '_fortress', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['house'] = new WallElement('house', 'structures/' + civ + '_house', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['market'] = new WallElement('market', 'structures/' + civ + '_market', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['mill'] = new WallElement('mill', 'structures/' + civ + '_mill', PI, 0, 4.5*scaleByCiv[style]); - wallStyles[style]['temple'] = new WallElement('temple', 'structures/' + civ + '_temple', PI, 0, 4.5*scaleByCiv[style]); + wallStyles[style]["barracks"] = new WallElement("barracks", "structures/" + civ + "_barracks", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["civilCentre"] = new WallElement("civilCentre", "structures/" + civ + "_civil_centre", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["farmstead"] = new WallElement("farmstead", "structures/" + civ + "_farmstead", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["field"] = new WallElement("field", "structures/" + civ + "_field", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["fortress"] = new WallElement("fortress", "structures/" + civ + "_fortress", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["house"] = new WallElement("house", "structures/" + civ + "_house", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["market"] = new WallElement("market", "structures/" + civ + "_market", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["mill"] = new WallElement("mill", "structures/" + civ + "_mill", PI, 0, 4.5*wallScaleByType[style]); + wallStyles[style]["temple"] = new WallElement("temple", "structures/" + civ + "_temple", PI, 0, 4.5*wallScaleByType[style]); // Generic space/gap wall elements - wallStyles[style]['space1'] = new WallElement('space1', undefined, 0*PI, scaleByCiv[style]); - wallStyles[style]['space2'] = new WallElement('space2', undefined, 0*PI, 2*scaleByCiv[style]); - wallStyles[style]['space3'] = new WallElement('space3', undefined, 0*PI, 3*scaleByCiv[style]); - wallStyles[style]['space4'] = new WallElement('space4', undefined, 0*PI, 4*scaleByCiv[style]); + wallStyles[style]["space1"] = new WallElement("space1", undefined, 0*PI, wallScaleByType[style]); + wallStyles[style]["space2"] = new WallElement("space2", undefined, 0*PI, 2*wallScaleByType[style]); + wallStyles[style]["space3"] = new WallElement("space3", undefined, 0*PI, 3*wallScaleByType[style]); + wallStyles[style]["space4"] = new WallElement("space4", undefined, 0*PI, 4*wallScaleByType[style]); } - // Add wall fortresses for all generic styles -wallStyles['athen']['wallFort'] = new WallElement('wallFort', 'structures/athen_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); -wallStyles['cart']['wallFort'] = new WallElement('wallFort', 'structures/cart_fortress', PI, 5.1, 1.6); -wallStyles['celt']['wallFort'] = new WallElement('wallFort', 'structures/celt_fortress_g', PI, 4.2, 1.5); -wallStyles['hele']['wallFort'] = new WallElement('wallFort', 'structures/hele_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); -wallStyles['iber']['wallFort'] = new WallElement('wallFort', 'structures/iber_fortress', PI, 5, 0.2); -wallStyles['mace']['wallFort'] = new WallElement('wallFort', 'structures/mace_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); -wallStyles['pers']['wallFort'] = new WallElement('wallFort', 'structures/pers_fortress', PI, 5.6/*5.5*/, 1.9/*1.7*/); -wallStyles['rome']['wallFort'] = new WallElement('wallFort', 'structures/rome_fortress', PI, 6.3, 2.1); -wallStyles['spart']['wallFort'] = new WallElement('wallFort', 'structures/spart_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); -// Adjust 'rome_siege' style -wallStyles['rome_siege']['wallFort'] = new WallElement('wallFort', 'structures/rome_army_camp', PI, 7.2, 2); -wallStyles['rome_siege']['entryFort'] = new WallElement('entryFort', 'structures/rome_army_camp', PI, 12, 7); -wallStyles['rome_siege']['house'] = new WallElement('house', 'structures/rome_tent', PI, 0, 4); +wallStyles["athen"]["wallFort"] = new WallElement("wallFort", "structures/athen_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); +wallStyles["brit"]["wallFort"] = new WallElement("wallFort", "structures/brit_fortress", PI, 2.8); +wallStyles["cart"]["wallFort"] = new WallElement("wallFort", "structures/cart_fortress", PI, 5.1, 1.6); +wallStyles["celt"]["wallFort"] = new WallElement("wallFort", "structures/celt_fortress_g", PI, 4.2, 1.5); +wallStyles["gaul"]["wallFort"] = new WallElement("wallFort", "structures/gaul_fortress", PI, 4.2, 1.5); +wallStyles["hele"]["wallFort"] = new WallElement("wallFort", "structures/hele_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); +wallStyles["iber"]["wallFort"] = new WallElement("wallFort", "structures/iber_fortress", PI, 5, 0.2); +wallStyles["mace"]["wallFort"] = new WallElement("wallFort", "structures/mace_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); +wallStyles["pers"]["wallFort"] = new WallElement("wallFort", "structures/pers_fortress", PI, 5.6/*5.5*/, 1.9/*1.7*/); +wallStyles["rome"]["wallFort"] = new WallElement("wallFort", "structures/rome_fortress", PI, 6.3, 2.1); +wallStyles["spart"]["wallFort"] = new WallElement("wallFort", "structures/spart_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */); +// Adjust "rome_siege" style +wallStyles["rome_siege"]["wallFort"] = new WallElement("wallFort", "structures/rome_army_camp", PI, 7.2, 2); +wallStyles["rome_siege"]["entryFort"] = new WallElement("entryFort", "structures/rome_army_camp", PI, 12, 7); +wallStyles["rome_siege"]["house"] = new WallElement("house", "structures/rome_tent", PI, 0, 4); // Add special wall styles not well to implement generic (and to show how custom styles can be added) -// Add special wall style 'palisades' -wallStyles['palisades'] = {}; -wallStyles['palisades']['wall'] = new WallElement('wall', 'other/palisades_rocks_medium', 0*PI, 2.3); -wallStyles['palisades']['wallLong'] = new WallElement('wall', 'other/palisades_rocks_long', 0*PI, 3.5); -wallStyles['palisades']['wallShort'] = new WallElement('wall', 'other/palisades_rocks_short', 0*PI, 1.2); -wallStyles['palisades']['tower'] = new WallElement('tower', 'other/palisades_rocks_tower', -PI/2, 0.7); -wallStyles['palisades']['wallFort'] = new WallElement('wallFort', 'other/palisades_rocks_fort', PI, 1.7); -wallStyles['palisades']['gate'] = new WallElement('gate', 'other/palisades_rocks_gate', 0*PI, 3.6); -wallStyles['palisades']['entry'] = new WallElement('entry', undefined, wallStyles['palisades']['gate'].angle, wallStyles['palisades']['gate'].width); -wallStyles['palisades']['entryTower'] = new WallElement('entryTower', 'other/palisades_rocks_watchtower', 0*PI, wallStyles['palisades']['gate'].width, -3); -wallStyles['palisades']['entryFort'] = new WallElement('entryFort', 'other/palisades_rocks_fort', PI, 6, 3); -wallStyles['palisades']['cornerIn'] = new WallElement('cornerIn', 'other/palisades_rocks_curve', 3*PI/4, 2.1, 0.7, PI/2); -wallStyles['palisades']['cornerOut'] = new WallElement('cornerOut', 'other/palisades_rocks_curve', 5*PI/4, 2.1, -0.7, -PI/2); -wallStyles['palisades']['outpost'] = new WallElement('outpost', 'other/palisades_rocks_outpost', PI, 0, -2); -wallStyles['palisades']['house'] = new WallElement('house', 'other/celt_hut', PI, 0, 5); -wallStyles['palisades']['barracks'] = new WallElement('barracks', 'other/celt_tavern', PI, 0, 5); -wallStyles['palisades']['endRight'] = new WallElement('endRight', 'other/palisades_rocks_end', -PI/2, 0.2); -wallStyles['palisades']['endLeft'] = new WallElement('endLeft', 'other/palisades_rocks_end', PI/2, 0.2); +// Add wall style "palisades" +wallScaleByType["palisades"] = 0.55; +wallStyles["palisades"] = {}; +wallStyles["palisades"]["wall"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3); +wallStyles["palisades"]["wallMedium"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3); +wallStyles["palisades"]["wallLong"] = new WallElement("wall", "other/palisades_rocks_long", 0*PI, 3.5); +wallStyles["palisades"]["wallShort"] = new WallElement("wall", "other/palisades_rocks_short", 0*PI, 1.2); +wallStyles["palisades"]["tower"] = new WallElement("tower", "other/palisades_rocks_tower", -PI/2, 0.7); +wallStyles["palisades"]["wallFort"] = new WallElement("wallFort", "other/palisades_rocks_fort", PI, 1.7); +wallStyles["palisades"]["gate"] = new WallElement("gate", "other/palisades_rocks_gate", PI, 3.6); +wallStyles["palisades"]["entry"] = new WallElement("entry", undefined, wallStyles["palisades"]["gate"].angle, wallStyles["palisades"]["gate"].width); +wallStyles["palisades"]["entryTower"] = new WallElement("entryTower", "other/palisades_rocks_watchtower", 0*PI, wallStyles["palisades"]["gate"].width, -3); +wallStyles["palisades"]["entryFort"] = new WallElement("entryFort", "other/palisades_rocks_fort", PI, 6, 3); +wallStyles["palisades"]["cornerIn"] = new WallElement("cornerIn", "other/palisades_rocks_curve", 3*PI/4, 2.1, 0.7, PI/2); +wallStyles["palisades"]["cornerOut"] = new WallElement("cornerOut", "other/palisades_rocks_curve", 5*PI/4, 2.1, -0.7, -PI/2); +wallStyles["palisades"]["outpost"] = new WallElement("outpost", "other/palisades_rocks_outpost", PI, 0, -2); +wallStyles["palisades"]["house"] = new WallElement("house", "other/celt_hut", PI, 0, 5); +wallStyles["palisades"]["barracks"] = new WallElement("barracks", "other/celt_tavern", PI, 0, 5); +wallStyles["palisades"]["endRight"] = new WallElement("endRight", "other/palisades_rocks_end", -PI/2, 0.2); +wallStyles["palisades"]["endLeft"] = new WallElement("endLeft", "other/palisades_rocks_end", PI/2, 0.2); -// Add special wall style 'road' - -// Add special wall element collection 'other' +// Add special wall style "road" // NOTE: This is not a wall style in the common sense. Use with care! -wallStyles['other'] = {}; -wallStyles['other']['fence'] = new WallElement('fence', 'other/fence_long', -PI/2, 3.1); -wallStyles['other']['fence_short'] = new WallElement('fence_short', 'other/fence_short', -PI/2, 1.5); -wallStyles['other']['fence_stone'] = new WallElement('fence_stone', 'other/fence_stone', -PI/2, 2.5); -wallStyles['other']['palisade'] = new WallElement('palisade', 'other/palisades_rocks_short', 0, 1.2); -wallStyles['other']['column'] = new WallElement('column', 'other/column_doric', 0, 1); -wallStyles['other']['obelisk'] = new WallElement('obelisk', 'other/obelisk', 0, 2); -wallStyles['other']['spike'] = new WallElement('spike', 'other/palisades_angle_spike', -PI/2, 1); -wallStyles['other']['bench'] = new WallElement('bench', 'other/bench', PI/2, 1.5); -wallStyles['other']['benchForTable'] = new WallElement('benchForTable', 'other/bench', 0, 0.5); -wallStyles['other']['table'] = new WallElement('table', 'other/table_rectangle', 0, 1); -wallStyles['other']['table_square'] = new WallElement('table_square', 'other/table_square', PI/2, 1); -wallStyles['other']['flag'] = new WallElement('flag', 'special/rallypoint', PI, 1); -wallStyles['other']['standing_stone'] = new WallElement('standing_stone', 'gaia/special_ruins_standing_stone', PI, 1); -wallStyles['other']['settlement'] = new WallElement('settlement', 'gaia/special_settlement', PI, 6); -wallStyles['other']['gap'] = new WallElement('gap', undefined, 0, 2); -wallStyles['other']['gapSmall'] = new WallElement('gapSmall', undefined, 0, 1); -wallStyles['other']['gapLarge'] = new WallElement('gapLarge', undefined, 0, 4); -wallStyles['other']['cornerIn'] = new WallElement('cornerIn', undefined, 0, 0, 0, PI/2); -wallStyles['other']['cornerOut'] = new WallElement('cornerOut', undefined, 0, 0, 0, -PI/2); +wallStyles["road"] = {}; +wallStyles["road"]["short"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5); +wallStyles["road"]["long"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5); +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 +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 +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 +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 +wallStyles["road"]["start"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2); +wallStyles["road"]["end"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2); +wallStyles["road"]["xStraight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5); +wallStyles["road"]["xLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, PI/2); +wallStyles["road"]["xRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, -PI/2); +wallStyles["road"]["tLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25); +wallStyles["road"]["tRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0*PI, 4.5, -1.25); + +// Add special wall element collection "other" +// NOTE: This is not a wall style in the common sense. Use with care! +wallStyles["other"] = {}; +wallStyles["other"]["fence"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1); +wallStyles["other"]["fence_medium"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1); +wallStyles["other"]["fence_short"] = new WallElement("fence_short", "other/fence_short", -PI/2, 1.5); +wallStyles["other"]["fence_stone"] = new WallElement("fence_stone", "other/fence_stone", -PI/2, 2.5); +wallStyles["other"]["palisade"] = new WallElement("palisade", "other/palisades_rocks_short", 0, 1.2); +wallStyles["other"]["column"] = new WallElement("column", "other/column_doric", 0, 1); +wallStyles["other"]["obelisk"] = new WallElement("obelisk", "other/obelisk", 0, 2); +wallStyles["other"]["spike"] = new WallElement("spike", "other/palisades_angle_spike", -PI/2, 1); +wallStyles["other"]["bench"] = new WallElement("bench", "other/bench", PI/2, 1.5); +wallStyles["other"]["benchForTable"] = new WallElement("benchForTable", "other/bench", 0, 0.5); +wallStyles["other"]["table"] = new WallElement("table", "other/table_rectangle", 0, 1); +wallStyles["other"]["table_square"] = new WallElement("table_square", "other/table_square", PI/2, 1); +wallStyles["other"]["flag"] = new WallElement("flag", "special/rallypoint", PI, 1); +wallStyles["other"]["standing_stone"] = new WallElement("standing_stone", "gaia/special_ruins_standing_stone", PI, 1); +wallStyles["other"]["settlement"] = new WallElement("settlement", "gaia/special_settlement", PI, 6); +wallStyles["other"]["gap"] = new WallElement("gap", undefined, 0, 2); +wallStyles["other"]["gapSmall"] = new WallElement("gapSmall", undefined, 0, 1); +wallStyles["other"]["gapLarge"] = new WallElement("gapLarge", undefined, 0, 4); +wallStyles["other"]["cornerIn"] = new WallElement("cornerIn", undefined, 0, 0, 0, PI/2); +wallStyles["other"]["cornerOut"] = new WallElement("cornerOut", undefined, 0, 0, 0, -PI/2); -/////////////////////////////////////////////////////// -// Setup data structure for some default fortress types -/////////////////////////////////////////////////////// - -// A fortress type is just an instance of the fortress class with actually something in it. -// fortressTypes holds all the fortressess within an associative array while a fortress is associated with a descriptive string maching the map sizes, example: 'tiny', 'giant' +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// fortressTypes data structure for some default fortress types +// +// A fortress type is just an instance of the Fortress class with actually something in it +// fortressTypes holds all the fortressess within an associative array with a descriptive string as key (e.g. maching the map size) +// Eexamples: "tiny", "veryLarge" +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// var fortressTypes = {}; // Setup some default fortress types -// Add fortress type 'tiny' -fortressTypes['tiny'] = new Fortress('tiny'); -var wallPart = ['entry', 'wall', 'cornerIn', 'wall']; -fortressTypes['tiny'].wall = wallPart.concat(wallPart, wallPart, wallPart); -// Add fortress type 'small' -fortressTypes['small'] = new Fortress('small'); -var wallPart = ['entry', 'endLeft', 'wall', 'cornerIn', 'wall', 'endRight']; -fortressTypes['small'].wall = wallPart.concat(wallPart, wallPart, wallPart); -// Add fortress type 'medium' -fortressTypes['medium'] = new Fortress('medium'); -var wallPart = ['entry', 'endLeft', 'wall', 'outpost', 'wall', - 'cornerIn', 'wall', 'outpost', 'wall', 'endRight']; -fortressTypes['medium'].wall = wallPart.concat(wallPart, wallPart, wallPart); -// Add fortress type 'normal' -fortressTypes['normal'] = new Fortress('normal'); -var wallPart = ['entry', 'endLeft', 'wall', 'tower', 'wall', - 'cornerIn', 'wall', 'tower', 'wall', 'endRight']; -fortressTypes['normal'].wall = wallPart.concat(wallPart, wallPart, wallPart); -// Add fortress type 'large' -fortressTypes['large'] = new Fortress('large'); -var wallPart = ['entry', 'endLeft', 'wall', 'outpost', 'wall', 'cornerIn', 'wall', - 'cornerOut', 'wall', 'cornerIn', 'wall', 'outpost', 'wall', 'endRight']; -fortressTypes['large'].wall = wallPart.concat(wallPart, wallPart, wallPart); -// Add fortress type 'veryLarge' -fortressTypes['veryLarge'] = new Fortress('veryLarge'); -var wallPart = ['entry', 'endLeft', 'wall', 'tower', 'wall', 'cornerIn', 'wall', - 'cornerOut', 'wall', 'cornerIn', 'wall', 'tower', 'wall', 'endRight']; -fortressTypes['veryLarge'].wall = wallPart.concat(wallPart, wallPart, wallPart); -// Add fortress type 'giant' -fortressTypes['giant'] = new Fortress('giant'); -var wallPart = ['entry', 'endLeft', 'wall', 'outpost', 'wall', 'cornerIn', 'wall', 'outpost', 'wall', - 'cornerOut', 'wall', 'outpost', 'wall', 'cornerIn', 'wall', 'outpost', 'wall', 'endRight']; -fortressTypes['giant'].wall = wallPart.concat(wallPart, wallPart, wallPart); +// Add fortress type "tiny" +fortressTypes["tiny"] = new Fortress("tiny"); +var wallPart = ["entry", "wall", "cornerIn", "wall"]; +fortressTypes["tiny"].wall = wallPart.concat(wallPart, wallPart, wallPart); +// Add fortress type "small" +fortressTypes["small"] = new Fortress("small"); +var wallPart = ["entry", "endLeft", "wall", "cornerIn", "wall", "endRight"]; +fortressTypes["small"].wall = wallPart.concat(wallPart, wallPart, wallPart); +// Add fortress type "medium" +fortressTypes["medium"] = new Fortress("medium"); +var wallPart = ["entry", "endLeft", "wall", "outpost", "wall", + "cornerIn", "wall", "outpost", "wall", "endRight"]; +fortressTypes["medium"].wall = wallPart.concat(wallPart, wallPart, wallPart); +// Add fortress type "normal" +fortressTypes["normal"] = new Fortress("normal"); +var wallPart = ["entry", "endLeft", "wall", "tower", "wall", + "cornerIn", "wall", "tower", "wall", "endRight"]; +fortressTypes["normal"].wall = wallPart.concat(wallPart, wallPart, wallPart); +// Add fortress type "large" +fortressTypes["large"] = new Fortress("large"); +var wallPart = ["entry", "endLeft", "wall", "outpost", "wall", "cornerIn", "wall", + "cornerOut", "wall", "cornerIn", "wall", "outpost", "wall", "endRight"]; +fortressTypes["large"].wall = wallPart.concat(wallPart, wallPart, wallPart); +// Add fortress type "veryLarge" +fortressTypes["veryLarge"] = new Fortress("veryLarge"); +var wallPart = ["entry", "endLeft", "wall", "tower", "wall", "cornerIn", "wall", + "cornerOut", "wall", "cornerIn", "wall", "tower", "wall", "endRight"]; +fortressTypes["veryLarge"].wall = wallPart.concat(wallPart, wallPart, wallPart); +// Add fortress type "giant" +fortressTypes["giant"] = new Fortress("giant"); +var wallPart = ["entry", "endLeft", "wall", "outpost", "wall", "cornerIn", "wall", "outpost", "wall", + "cornerOut", "wall", "outpost", "wall", "cornerIn", "wall", "outpost", "wall", "endRight"]; +fortressTypes["giant"].wall = wallPart.concat(wallPart, wallPart, wallPart); -// Add (some) iberian civ bonus fortress (The civ can still be set, just an uncommon default fortress) -var wall = ['gate', 'tower', 'wall', 'cornerIn', 'wallLong', 'tower', - 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower', - 'gate', 'wall', 'cornerIn', 'wall', 'cornerOut', 'wall', 'cornerIn', 'wallLong', 'tower', - 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower', 'wall', 'cornerIn', 'wall']; -fortressTypes['iberCivBonus'] = new Fortress('iberCivBonus', wall); -var wall = ['gate', 'tower', 'wall', 'cornerIn', 'wall', 'cornerOut', 'wall', 'cornerIn', 'wallLong', 'tower', - 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower', 'wall', 'cornerIn', 'wall', 'cornerOut', - 'gate', 'tower', 'wall', 'cornerIn', 'wallLong', 'tower', - 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower']; -fortressTypes['iberCivBonus2'] = new Fortress('iberCivBonus2', wall); -var wall = ['gate', 'tower', 'wall', 'cornerOut', 'wallShort', 'cornerIn', 'wall', 'cornerIn', 'wallLong', 'cornerIn', 'wallShort', 'cornerOut', 'wall', 'tower', - 'gate', 'tower', 'wallLong', 'cornerIn', 'wallLong', 'cornerIn', 'wallShort', 'cornerOut', - 'gate', 'tower', 'wall', 'cornerIn', 'wall', 'cornerOut', 'wallShort', 'cornerIn', 'wall', 'tower', - 'gate', 'tower', 'wallShort', 'cornerIn', 'wall', 'tower', 'wallShort', 'tower']; -fortressTypes['iberCivBonus3'] = new Fortress('iberCivBonus3', wall); - - -// Setup some semi default fortresses for 'palisades' style -var fortressTypeKeys = ['tiny', 'small', 'medium', 'normal', 'large', 'veryLarge', 'giant']; +// Setup some better looking semi default fortresses for "palisades" style +var fortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"]; for (var i = 0; i < fortressTypeKeys.length; i++) { - var newKey = fortressTypeKeys[i] + 'Palisades'; + var newKey = fortressTypeKeys[i] + "Palisades"; var oldWall = fortressTypes[fortressTypeKeys[i]].wall; - fortressTypes[newKey] = new Fortress(newKey, []); // [] just to make sure it's an array though it's an array by default - var fillTowersBetween = ['wall', 'endLeft', 'endRight', 'cornerIn', 'cornerOut']; + fortressTypes[newKey] = new Fortress(newKey); + var fillTowersBetween = ["wall", "endLeft", "endRight", "cornerIn", "cornerOut"]; for (var j = 0; j < oldWall.length; j++) { - fortressTypes[newKey].wall.push(oldWall[j]); // Only works if the first element is an entry or gate (not in fillTowersBetween) + 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) if (j+1 < oldWall.length) - if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means 'exists' here - fortressTypes[newKey].wall.push('tower'); + if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means "exists" here + fortressTypes[newKey].wall.push("tower"); } } +// Setup some balanced (to civ type fortresses) semi default fortresses for "palisades" style +// TODO -/////////////////////////////////////////////////////////////////////////////// -// Define some helper functions: getWallAlignment, getWallCenter, getWallLength -/////////////////////////////////////////////////////////////////////////////// +// Add some "fortress types" for roads (will only work with style "road") +// ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"]; +var wall = ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"]; +fortressTypes["road01"] = new Fortress("road01", wall); +var wall = ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"]; +fortressTypes["road02"] = new Fortress("road02", wall); +var wall = ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"]; +fortressTypes["road03"] = new Fortress("road03", wall); +var wall = ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short", + "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"]; +fortressTypes["road04"] = new Fortress("road04", wall); +var wall = ["start", "tLeft", "short", "xRight", + "curveLeft", "xRight", "tRight", "cornerLeft", "tRight", + "curveLeft", "short", "tRight", "cornerLeft", "xRight", + "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"]; +fortressTypes["road05"] = new Fortress("road05", wall); -// Get alignment of a wall -// Returns a list of lists of most arguments needed to place the different wall elements for a given wall -// Placing the first wall element at startX/startY placed with angle given by orientation -// An alignement can be used to get the center of a 'wall' (more likely used for closed walls like fortresses) with the getWallCenter function + +/////////////////////////////// +// Define some helper functions +/////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// getWallAlignment +// +// Returns a list of objects containing all information to place all the wall elements entities with placeObject (but the player ID) +// Placing the first wall element at startX/startY placed with an angle given by orientation +// An alignement can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function getWallAlignment(startX, startY, wall, style, orientation) { - orientation = (orientation !== undefined) ? orientation : 0*PI; - var alignment = [] + orientation = (orientation || 0); + var alignment = []; var wallX = startX; var wallY = startY; for (var i = 0; i < wall.length; i++) { - if (wallStyles[style][wall[i]] === undefined) - warn('No valid wall element: ' + wall[i]); - var element = wallStyles[style][wall[i]] + var element = wallStyles[style][wall[i]]; + if (element === undefined && i == 0) + warn("No valid wall element: " + wall[i]); // Indentation var placeX = wallX - element.indent * cos(orientation); var placeY = wallY - element.indent * sin(orientation); - // Add element alignment - alignment.push([placeX, placeY, element.entity, orientation + element.angle]); + // Add wall elements entity placement arguments to the alignment + alignment.push({"x": placeX, "y": placeY, "entity": element.entity, "angle":orientation + element.angle}); // Preset vars for the next wall element if (i+1 < wall.length) { orientation += element.bending; - if (wallStyles[style][wall[i+1]] === undefined) - warn('No valid wall element: ' + wall[i+1]); var nextElement = wallStyles[style][wall[i+1]]; + if (nextElement === undefined) + warn("No valid wall element: " + wall[i+1]); var distance = (element.width + nextElement.width)/2; // Corrections for elements with indent AND bending - if (element.bending !== 0 && element.indent !== 0) + var indent = element.indent; + var bending = element.bending; + if (bending !== 0 && indent !== 0) { // Indent correction to adjust distance - distance += element.indent*sin(element.bending); + distance += indent*sin(bending); // Indent correction to normalize indentation - wallX += element.indent * cos(orientation); - wallY += element.indent * sin(orientation); + wallX += indent * cos(orientation); + wallY += indent * sin(orientation); } - // Set the next coordinates of the next element in the wall (meaning without indentation adjustment) + // Set the next coordinates of the next element in the wall without indentation adjustment wallX -= distance * sin(orientation); wallY += distance * cos(orientation); } @@ -333,24 +372,31 @@ function getWallAlignment(startX, startY, wall, style, orientation) return alignment; } -// Get the center of a wall (mainly usefull for closed walls like fortresses) -// Center calculation works like getting the center of mass assuming all wall elements have the same 'waight' -// It returns the vector (array [x, y]) from the first wall element to the center -function getWallCenter(alignment) +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// getCenterToFirstElement +// +// Center calculation works like getting the center of mass assuming all wall elements have the same "weight" +// +// It returns the vector from the center to the first wall element +// Used to get centerToFirstElement of fortresses by default +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function getCenterToFirstElement(alignment) { - var x = 0; - var y = 0; + var centerToFirstElement = {"x": 0, "y": 0}; for (var i = 0; i < alignment.length; i++) { - x += alignment[i][0]/alignment.length; - y += alignment[i][1]/alignment.length; + centerToFirstElement.x -= alignment[i].x/alignment.length; + centerToFirstElement.y -= alignment[i].y/alignment.length; } - var center = [x, y]; - return center; + return centerToFirstElement; } -// Get the length of a wall used by placeIrregularPolygonalWall -// NOTE: Does not support bending wall elements like corners! +////////////////////////////////////////////////////////////////// +// getWallLength +// +// NOTE: Does not support bending wall elements like corners! +// e.g. used by placeIrregularPolygonalWall +////////////////////////////////////////////////////////////////// function getWallLength(wall, style) { var length = 0; @@ -366,73 +412,121 @@ function getWallLength(wall, style) // Define the different wall placer functions ///////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////////////// -// Place simple wall starting with the first wall element placed at startX/startY -///////////////////////////////////////////////////////////////////////////////// -// orientation: 0 means 'outside' or 'front' of the wall is right (positive X) like placeObject -// It will then be build towards top (positive Y) if no bending wall elements like corners are used -// Raising orientation means the wall is rotated counter-clockwise like placeObject +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// placeWall +// +// Places a wall with wall elements attached to another like determined by WallElement properties. +// +// startX, startY Where the first wall element should be placed +// wall Array of wall element type strings. Example: ["endLeft", "wallLong", "tower", "wallLong", "endRight"] +// style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia +// playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) +// orientation Optional. Angle the first wall element is placed. Default is 0 +// 0 means "outside" or "front" of the wall is right (positive X) like placeObject +// It will then be build towards top/positive Y (if no bending wall elements like corners are used) +// Raising orientation means the wall is rotated counter-clockwise like placeObject +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeWall(startX, startY, wall, style, playerId, orientation) { + // Setup optional arguments + playerId = (playerId || 0); + if (playerId == 0) + style = (style || "palisades"); + else + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); + orientation = (orientation || 0); + // Get wall alignment var AM = getWallAlignment(startX, startY, wall, style, orientation); + // Place the wall for (var iWall = 0; iWall < wall.length; iWall++) { - if (AM[iWall][2] !== undefined) - placeObject(AM[iWall][0], AM[iWall][1], AM[iWall][2], playerId, AM[iWall][3]); + var entity = AM[iWall].entity; + if (entity !== undefined) + placeObject(AM[iWall].x, AM[iWall].y, entity, playerId, AM[iWall].angle); } } -////////////////////////////////////////////////////////////////////////////////////////////////// -// Place a fortress (mainly a closed wall build like placeWall) with the center at centerX/centerY -////////////////////////////////////////////////////////////////////////////////////////////////// -// Should always start with the main entrance (like 'entry' or 'gate') to get the orientation right (like placeObject) -function placeCustomFortress(centerX, centerY, fortress, style, playerId, orientation, scipGetCenter) +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// placeCustomFortress +// +// Place a fortress (mainly a closed wall build like placeWall) centered at centerX/centerY +// The fortress wall should always start with the main entrance (like "entry" or "gate") to get the orientation right (like placeObject) +// +// fortress An instance of Fortress with a wall defined +// style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia +// playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) +// orientation Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0 +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function placeCustomFortress(centerX, centerY, fortress, style, playerId, orientation) { - if (!scipGetCenter) - { - var alignment = getWallAlignment(0, 0, fortress.wall, style); - var center = getWallCenter(alignment); - var startX = centerX - center[0] * cos(orientation) + center[1] * sin(orientation); - var startY = centerY - center[1] * cos(orientation) - center[0] * sin(orientation); - } + // Setup optional arguments + fortress = (fortress || fortressTypes["tiny"]); + playerId = (playerId || 0); + if (playerId == 0) + style = (style || "palisades"); else - { - var startX = centerX + fortress.center[0]; - var startY = centerY + fortress.center[1]; - } + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); + orientation = (orientation || 0); + // Calculate center if fortress.centerToFirstElement is undefined (default) + var centerToFirstElement = fortress.centerToFirstElement; + if (centerToFirstElement === undefined) + centerToFirstElement = getCenterToFirstElement(getWallAlignment(0, 0, fortress.wall, style)); + // Placing the fortress wall + var startX = centerX + centerToFirstElement.x * cos(orientation) - centerToFirstElement.y * sin(orientation); + var startY = centerY + centerToFirstElement.y * cos(orientation) + centerToFirstElement.x * sin(orientation); placeWall(startX, startY, fortress.wall, style, playerId, orientation) } -function placeFortress(centerX, centerY, type, style, playerId, orientation, scipGetCenter) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// placeFortress +// +// Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function placeFortress(centerX, centerY, type, style, playerId, orientation) { - placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation, scipGetCenter); + // Setup optional arguments + type = (type || "tiny"); + playerId = (playerId || 0); + if (playerId == 0) + style = (style || "palisades"); + else + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); + orientation = (orientation || 0); + // Call placeCustomFortress with the given arguments + placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation); } -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Place a linear wall of repeatant wall elements given in the argument wallPart from startX/startY to targetX/targetY -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// startX: x coordinate of the beginning of the wall -// startY: y coordinate of the beginning of the wall -// targetX: x coordinate of the ending of the wall -// targetY: y coordinate of the ending of the wall -// NOTE: Start and target coordinates are exact (besides the scale offset) meaning the wall will begin/end at the given coordinates (not the first/last entity is placed there) -// wallPart: Optional. An array of wall element type strings (see WallElement.type). Default is ['wall'] -// NOTE: Don't use wall elements with bending like corners! -// style: Optional. An wall style string (like defined in the 'wallStyles' dictionary). Default is 'palisades' -// 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) -// endWithFirst: Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// placeLinearWall +// +// Places a straight wall from a given coordinate to an other repeatant using the wall parts. +// +// startX/startY Coordinate of the approximate beginning of the wall (Not the place of the first wall element) +// targetX/targetY Coordinate of the approximate ending of the wall (Not the place of the last wall element) +// wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"] +// style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia +// playerId Optional. Integer number of the player. Default is 0 (gaia) +// endWithFirst Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true +// +// TODO: Maybe add angle offset for more generic looking? +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId, endWithFirst) { // Setup optional arguments to the default - wallPart = (wallPart || ['wall']); - style = (style || 'palisades'); + wallPart = (wallPart || ["tower", "wallLong"]); playerId = (playerId || 0); - // endWithFirst = (endWithFirst || true); - endWithFirst = typeof endWithFirst == 'undefined' ? true : endWithFirst; + if (playerId == 0) + style = (style || "palisades"); + else + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); + endWithFirst = typeof endWithFirst == "undefined" ? true : endWithFirst; // Check arguments for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) - if (wallStyles[style][wallPart[elementIndex]].bending != 0) + { + var bending = wallStyles[style][wallPart[elementIndex]].bending; + if (bending != 0) warn("Bending is not supported by placeLinearWall but a bending wall element is used: " + wallPart[elementIndex] + " -> wallStyles[style][wallPart[elementIndex]].entity"); + } // Setup number of wall parts var totalLength = getDistance(startX, startY, targetX, targetY); var wallPartLength = 0; @@ -440,17 +534,17 @@ function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, play wallPartLength += wallStyles[style][wallPart[elementIndex]].width; var numParts = 0; if (endWithFirst == true) - numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength) + numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength); else numParts = ceil(totalLength / wallPartLength); // Setup scale factor var scaleFactor = 1; if (endWithFirst == true) - scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width) + scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width); else scaleFactor = totalLength / (numParts * wallPartLength); // Setup angle - var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function 'getAngle()' is about to be changed... + var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed... var placeAngle = wallAngle - PI/2; // Place wall entities var x = startX; @@ -467,8 +561,9 @@ function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, play var placeX = x - wallEle.indent * sin(wallAngle); var placeY = y + wallEle.indent * cos(wallAngle); // Placement - if (wallEle.entity !== undefined) - placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle); + var entity = wallEle.entity; + if (entity !== undefined) + placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle); x += scaleFactor * wallEle.width/2 * cos(wallAngle); y += scaleFactor * wallEle.width/2 * sin(wallAngle); } @@ -478,43 +573,61 @@ function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, play var wallEle = wallStyles[style][wallPart[0]]; x += scaleFactor * wallEle.width/2 * cos(wallAngle); y += scaleFactor * wallEle.width/2 * sin(wallAngle); - if (wallEle.entity !== undefined) - placeObject(x, y, wallEle.entity, playerId, placeAngle + wallEle.angle); + var entity = wallEle.entity; + if (entity !== undefined) + placeObject(x, y, entity, playerId, placeAngle + wallEle.angle); } } -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Place a circular wall of repeatant wall elements given in the argument wallPart arround centerX/centerY with the given radius -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// The wall is not necessarily closed depending on the optional argument maxAngle (better name?) -// NOTE: Don't use wall elements with bending like corners! -// Todo: add eccentricity +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// placeCircularWall +// +// Place a circular wall of repeatant wall elements given in the argument wallPart arround centerX/centerY with the given radius +// The wall can be opend forming more an arc than a circle if maxAngle < 2*PI +// The orientation then determines where this open part faces (0 means right like unrotated building's droppoints) +// +// centerX/Y Coordinates of the circle's center +// radius How wide the circle should be (aproximate, especially if maxBendOff != 0) +// wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"] +// style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia +// playerId Optional. Integer number of the player. Default is 0 (gaia) +// orientation Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0 +// maxAngle Optional. How far the wall should circumvent the center. Default is 2*PI (full circle) +// endWithFirst Optional. Boolean. If true the 1st wall element in the wallPart array will finalize the wall. Default is false for full circles, else true +// maxBendOff Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle) +// +// NOTE: Don't use wall elements with bending like corners! +// TODO: Perhaps add eccentricity and maxBendOff functionality (untill now an unused argument) +// TODO: Perhaps add functionality for spirals +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff) { // Setup optional arguments to the default - wallPart = (wallPart || ['wall']); - style = (style || 'palisades'); + wallPart = (wallPart || ["tower", "wallLong"]); playerId = (playerId || 0); + if (playerId == 0) + style = (style || "palisades"); + else + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); orientation = (orientation || 0); maxAngle = (maxAngle || 2*PI); if (endWithFirst === undefined) { if (maxAngle >= 2*PI - 0.001) // Can this be done better? - { endWithFirst = false; - } else - { endWithFirst = true; - } } maxBendOff = (maxBendOff || 0); // Check arguments if (maxBendOff > PI/2 || maxBendOff < 0) - warn('placeCircularWall maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: ' + maxBendOff); + warn("placeCircularWall maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff); for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) - if (wallStyles[style][wallPart[elementIndex]].bending != 0) + { + var bending = wallStyles[style][wallPart[elementIndex]].bending; + if (bending != 0) warn("Bending is not supported by placeCircularWall but a bending wall element is used: " + wallPart[elementIndex]); + } // Setup number of wall parts var totalLength = maxAngle * radius; var wallPartLength = 0; @@ -532,7 +645,7 @@ function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, // Setup scale factor var scaleFactor = 1; if (endWithFirst == true) - scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width) + scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width); else scaleFactor = totalLength / (numParts * wallPartLength); // Place wall entities @@ -555,8 +668,9 @@ function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, placeX -= wallEle.indent * cos(placeAngle); placeY -= wallEle.indent * sin(placeAngle); // Placement - if (wallEle.entity !== undefined) - placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle); + var entity = wallEle.entity; + if (entity !== undefined) + placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle); // Prepare for the next wall element actualAngle += addAngle; x = centerX + radius*cos(actualAngle); @@ -577,21 +691,38 @@ function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Place a polygonal wall of repeatant wall elements given in the argument wallPart arround centerX/centerY with the given radius +// placePolygonalWall +// +// Place a polygonal wall of repeatant wall elements given in the argument wallPart arround centerX/centerY with the given radius +// +// centerX/Y Coordinates of the polygon's center +// radius How wide the circle should be in wich the polygon fits +// wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["wallLong", "tower"] +// cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower" +// style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia +// playerId Optional. Integer number of the player. Default is 0 (gaia) +// orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right) +// numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory) +// skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true +// +// NOTE: Don't use wall elements with bending like corners! +// TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement +// TODO: Check some arguments +// TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// NOTE: Don't use wall elements with bending like corners! -// TODO: Check some arguments -// TODO: Add eccentricity and irregularity (how far the corners can differ from a regulare convex poygon) function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall) { // Setup optional arguments to the default - wallPart = (wallPart || ['wall']); - cornerWallElement = (cornerWallElement || 'tower'); // Don't use wide elements for this. Not supported well... - style = (style || 'palisades'); + wallPart = (wallPart || ["wallLong", "tower"]); + cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well... playerId = (playerId || 0); + if (playerId == 0) + style = (style || "palisades"); + else + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); orientation = (orientation || 0); numCorners = (numCorners || 8); - skipFirstWall = (skipFirstWall || false); + skipFirstWall = (skipFirstWall || true); // Setup angles var angleAdd = 2*PI/numCorners; var angleStart = orientation - angleAdd/2; @@ -618,21 +749,41 @@ function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElemen } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Place an irregular polygonal wall of some wall parts to choose from arround centerX/centerY with the given radius +// placeIrregularPolygonalWall +// +// Place an irregular polygonal wall of some wall parts to choose from arround centerX/centerY with the given radius +// +// centerX/Y Coordinates of the polygon's center +// radius How wide the circle should be in wich the polygon fits +// cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower" +// style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia +// playerId Optional. Integer number of the player. Default is 0 (gaia) +// orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right) +// numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory) +// irregularity Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5 +// skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true +// wallPartsAssortment Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to decribe ^^ +// +// NOTE: wallPartsAssortment is put to the end because it's hardest to set +// NOTE: Don't use wall elements with bending like corners! +// TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement +// TODO: Check some arguments +// TODO: Perhaps add eccentricity //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// NOTE: Under construction!!! -// NOTE: wallPartList is put to the end because it's hardest to set -// NOTE: Don't use wall elements with bending like corners! -// TODO: Check some arguments -// TODO: Add eccentricity and irregularity (how far the corners can differ from a regulare convex poygon) function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment) { + // Setup optional arguments + playerId = (playerId || 0); + if (playerId == 0) + style = (style || "palisades"); + else + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); // Generating a generic wall part assortment with each wall part including 1 gate enlengthend by walls and towers // NOTE: It might be a good idea to write an own function for that... - var defaultWallPartsAssortment = [['wallShort'], ['wall'], ['wallLong'], ['gate', 'tower', 'wallShort']]; - var centeredWallPart = ['gate']; // NOTE: Since gates are not functional yet entrys are used instead... - var extandingWallPartAssortment = [['tower', 'wallLong'], ['tower', 'wall']]; - defaultWallPartsAssortment.push(centeredWallPart) + var defaultWallPartsAssortment = [["wallShort"], ["wall"], ["wallLong"], ["gate", "tower", "wallShort"]]; + var centeredWallPart = ["gate"]; // NOTE: Since gates are not functional yet entrys are used instead... + var extandingWallPartAssortment = [["tower", "wallLong"], ["tower", "wall"]]; + defaultWallPartsAssortment.push(centeredWallPart); for (var i = 0; i < extandingWallPartAssortment.length; i++) { var wallPart = centeredWallPart; @@ -651,8 +802,8 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement } // Setup optional arguments to the default wallPartsAssortment = (wallPartsAssortment || defaultWallPartsAssortment); - cornerWallElement = (cornerWallElement || 'tower'); // Don't use wide elements for this. Not supported well... - style = (style || 'palisades'); + cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well... + style = (style || "palisades"); playerId = (playerId || 0); orientation = (orientation || 0); numCorners = (numCorners || randInt(5, 7)); @@ -674,16 +825,17 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement { corners.push([centerX + radius*cos(angleActual), centerY + radius*sin(angleActual)]); if (i < numCorners - 1) - angleActual += angleAddList[i+1] + angleActual += angleAddList[i+1]; } // Setup best wall parts for the different walls (a bit confusing naming...) var wallPartLengths = []; var maxWallPartLength = 0; for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++) { + var length = wallPartLengths[partIndex]; wallPartLengths.push(getWallLength(wallPartsAssortment[partIndex], style)); - if (wallPartLengths[partIndex] > maxWallPartLength) - maxWallPartLength = wallPartLengths[partIndex]; + if (length > maxWallPartLength) + maxWallPartLength = length; } var wallPartList = []; // This is the list of the wall parts to use for the walls between the corners, not to confuse with wallPartsAssortment! for (var i = 0; i < numCorners; i++) @@ -691,17 +843,18 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement var bestWallPart = []; // This is a simpel wall part not a wallPartsAssortment! var bestWallLength = 99999999; // NOTE: This is not exsactly like the length the wall will be in the end. Has to be tweeked... - var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]) + var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]); var numWallParts = ceil(wallLength/maxWallPartLength); for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++) { - if (numWallParts*wallPartLengths[partIndex] < bestWallLength && numWallParts*wallPartLengths[partIndex] > wallLength) + var linearWallLength = numWallParts*wallPartLengths[partIndex]; + if (linearWallLength < bestWallLength && linearWallLength > wallLength) { bestWallPart = wallPartsAssortment[partIndex]; - bestWallLength = numWallParts*wallPartLengths[partIndex]; + bestWallLength = linearWallLength; } } - wallPartList.push(bestWallPart) + wallPartList.push(bestWallPart); } // Place Corners and walls for (var i = 0; i < numCorners; i++) @@ -721,64 +874,96 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement } } -// Just a test function, USE WITH CARE! -// radius: A float seting the aproximate radius of the fortress -// maxBendOff: Optional, The maximum random bending offset of the wall elements NOTE: If maxBendOff > PI/2 the wall might never close!!! -// wallPart: Optional, An array of wall element string, example: ["tower", "wall"] NOTE: Don't use wall elements with bending!!! -function placeGenericFortress(centerX, centerY, radius, playerId, wallPart, style, maxBendOff) +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// placeGenericFortress +// +// Places a generic fortress with towers at the edges connected with long walls and gates (entries untill gates work) +// This is the default Iberian civ bonus starting wall +// +// centerX/Y The aproximate center coordinates of the fortress +// radius The approximate radius of the wall to be placed +// playerId Optional. Integer number of the player. Default is 0 (gaia) +// style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia +// irregularity Optional. Float between 0 (circle) and 1 (very spiky), default is 1/2 +// gateOccurence Optional. Integer number, every n-th walls will be a gate instead. Default is 3 +// maxTrys Optional. How often the function tries to find a better fitting shape at max. Default is 100 +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function placeGenericFortress(centerX, centerY, radius, playerId, style, irregularity, gateOccurence, maxTrys) { - if (wallPart == undefined) - wallPart = ['tower', 'wall', 'tower', 'entry', 'tower', 'wall']; - if (maxBendOff > PI/2 || maxBendOff < 0) - warn("setGenericFortress maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff); - if (maxBendOff === undefined) - maxBendOff = 0; - var wallLength = 0; - for (var eleIndex = 0; eleIndex < wallPart.length; eleIndex++) + // Setup optional arguments + radius = (radius || 20); + playerId = (playerId || 0); + if (playerId == 0) + style = (style || "palisades"); + else + style = (style || g_MapSettings.PlayerData[playerId-1].Civ); + irregularity = (irregularity || 1/2); + gateOccurence = (gateOccurence || 3); + maxTrys = (maxTrys || 100); + // Setup some vars + var startAngle = randFloat(0, 2*PI); + var actualOffX = radius*cos(startAngle); + var actualOffY = radius*sin(startAngle); + var actualAngle = startAngle; + var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width; + // Searching for a well fitting point derivation + var tries = 0; + var bestPointDerivation = undefined; + var minOverlap = 1000; + var overlap = undefined; + while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10) { - wallLength += wallStyles[style][wallPart[eleIndex]].width + var pointDerivation = []; + var distanceToTarget = 1000; + var targetReached = false; + while (!targetReached) + { + var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance); + var tmpAngle = getAngle(actualOffX, actualOffY, + (radius + indent)*cos(actualAngle + (pointDistance / radius)), + (radius + indent)*sin(actualAngle + (pointDistance / radius))); + actualOffX += pointDistance*cos(tmpAngle); + actualOffY += pointDistance*sin(tmpAngle); + actualAngle = getAngle(0, 0, actualOffX, actualOffY); + pointDerivation.push([actualOffX, actualOffY]); + distanceToTarget = getDistance(actualOffX, actualOffY, pointDerivation[0][0], pointDerivation[0][1]); + var numPoints = pointDerivation.length; + if (numPoints > 3 && distanceToTarget < pointDistance) // Could be done better... + { + targetReached = true; + overlap = pointDistance - getDistance(pointDerivation[numPoints - 1][0], pointDerivation[numPoints - 1][1], pointDerivation[0][0], pointDerivation[0][1]); + if (overlap < minOverlap) + { + minOverlap = overlap; + bestPointDerivation = pointDerivation; + } + } + } + tries++; } - if (wallLength > 2*PI*radius || wallLength <= 0) - 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); - - var minEleWidth = 1000000; // Assuming the smallest element is about as wide as deep. - for (var eleIndex = 0; eleIndex < wallPart.length; eleIndex++) + log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries"); + // Place wall + for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++) { - eleWidth = wallStyles[style][wallPart[eleIndex]].width; - if (eleWidth < minEleWidth) - minEleWidth = eleWidth; + var startX = centerX + bestPointDerivation[pointIndex][0]; + var startY = centerY + bestPointDerivation[pointIndex][1]; + var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0]; + var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1]; + var angle = getAngle(startX, startY, targetX, targetY); + var wallElement = "wallLong"; + if ((pointIndex + 1) % gateOccurence == 0) + wallElement = "entry"; // Has to be changed to "gate" if gates work... + var entity = wallStyles[style][wallElement].entity; + if (entity) + { + placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX + startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY + entity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle); + } + // Place tower + var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0]; + var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1]; + var angle = getAngle(startX, startY, targetX, targetY); + placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style]["tower"].entity, playerId, angle - PI/2 + wallStyles[style]["tower"].angle); } - var widthSafty = minEleWidth/4; // Can be done better... - - var x = radius; - var y = 0; - var angle = 0; - var targetX = radius; - var targetY = 0; - var targetReached = false; - var eleIndex = 0; - while (targetReached == false) - { - var wallElement = wallStyles[style][wallPart[eleIndex % wallPart.length]]; - var eleWidth = wallElement.width - widthSafty; - // Stabalized bendOff - var actualRadius = getDistance(centerX, centerY, centerX + x, centerY + y); - var bendOff = randFloat(-maxBendOff*radius/actualRadius, maxBendOff*actualRadius/radius); - // Element width in radians - var eleAngleWidth = eleWidth*cos(bendOff) / radius; // A/L = da/dl -> da = A * dl / L -> da = 2*PI * eleWidth / (2*PI * radius) -> da = eleWidth/radius - var eleAngle = angle + eleAngleWidth/2 + bendOff; - var placeX = x - eleWidth/2 * sin(eleAngle); - var placeY = y + eleWidth/2 * cos(eleAngle); - if (wallElement.entity) - placeObject(centerX + placeX, centerY + placeY, wallElement.entity, playerId, eleAngle + wallElement.angle); - x = placeX - eleWidth/2 * sin(eleAngle); - y = placeY + eleWidth/2 * cos(eleAngle); - angle += eleAngleWidth; - if (eleIndex % wallPart.length == 0 && eleIndex > wallPart.length && (getDistance(x, y, targetX, targetY) < wallLength || angle > 2*PI)) - targetReached = true; - eleIndex++; - // if (eleIndex == 10) - // break; - } - placeLinearWall(centerX + x, centerY + y, centerX + targetX, centerY + targetY, ['wall', 'tower'], style, playerId, true); } diff --git a/binaries/data/mods/public/maps/random/wall_demo.js b/binaries/data/mods/public/maps/random/wall_demo.js index 846aaafa81..963233defb 100644 --- a/binaries/data/mods/public/maps/random/wall_demo.js +++ b/binaries/data/mods/public/maps/random/wall_demo.js @@ -63,7 +63,7 @@ var actualX = distToMapBorder; var actualY = distToMapBorder; // Wall styles are chosen by strings so the civ strings got by g_MapSettings.PlayerData[playerId - 1].Civ can be used // Other styles may be present as well but besides the civ styles only 'palisades' includes all wall element types (yet) -const wallStyleList = ['athen', 'cart', 'celt', 'hele', 'iber', 'mace', 'pers', 'rome', 'spart', 'rome_siege', 'palisades']; +const wallStyleList = ["athen", "brit", "cart", "celt", "gaul", "hele", "iber", "mace", "pers", "rome", "spart", "rome_siege", "palisades"]; //////////////////////////////////////// @@ -111,11 +111,11 @@ var orientation = 0; // Where the wall circle will be open if maxAngle < 2*PI, s for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++) { var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle - var playerID = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... + var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... var wallPart = ['tower', 'wall', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall'] var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'celt', 'hele', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' var maxAngle = PI/2 * (styleIndex%3 + 2); // How far the wall should circumvent the center - placeCircularWall(centerX, centerY, radius, wallPart, style, playerID, orientation, maxAngle); // Actually placing the wall + placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle); // Actually placing the wall placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the wall circle orientation += PI/16; // Increasing orientation to see how rotation works (like for object placement) } @@ -132,13 +132,13 @@ var orientation = 0; // Where the wall circle will be open if ???, see below. Ot for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++) { var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle - var playerID = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... + var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon var wallPart = ['wall', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall'] var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'celt', 'hele', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have var skipFirstWall = true; // If the wall should be open towards orientation - placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerID, orientation, numCorners, skipFirstWall); + placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall); placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the wall circle orientation += PI/16; // Increasing orientation to see how rotation works (like for object placement) } @@ -157,12 +157,12 @@ for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++) { var startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * distToOtherWalls; // X coordinate the wall will start from var startY = actualY; // Y coordinate the wall will start from - var endX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * distToOtherWalls; // X coordinate the wall will end + var endX = startX; // X coordinate the wall will end var endY = actualY + (wallIndex + 1) * maxWallLength/numWallsPerStyle; // Y coordinate the wall will end - var playerID = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... + var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... var wallPart = ['tower', 'wall']; // List of wall elements the wall will be build of var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'celt', 'hele', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' - placeLinearWall(startX, startY, endX, endY, wallPart, style, playerID, false); // Actually placing the wall + placeLinearWall(startX, startY, endX, endY, wallPart, style, playerId); // Actually placing the wall // placeObject(startX, startY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall begins // placeObject(endX, endY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall ends }