103 | | wallStyles[style]['tower'] = new WallElement('tower', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); |
104 | | wallStyles[style]['endLeft'] = new WallElement('endLeft', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); // Same as tower. To be compatible with palisades... |
105 | | wallStyles[style]['endRight'] = new WallElement('endRight', 'structures/' + style + '_wall_tower', PI, scaleByCiv[style]); // Same as tower. To be compatible with palisades... |
106 | | wallStyles[style]['cornerIn'] = new WallElement('cornerIn', 'structures/' + style + '_wall_tower', 5*PI/4, 0, 0.35*scaleByCiv[style], PI/2); // 2^0.5 / 4 ~= 0.35 ~= 1/3 |
107 | | wallStyles[style]['cornerOut'] = new WallElement('cornerOut', 'structures/' + style + '_wall_tower', 3*PI/4, 0.71*scaleByCiv[style], 0, -PI/2); // // 2^0.5 / 2 ~= 0.71 ~= 2/3 |
108 | | wallStyles[style]['wallShort'] = new WallElement('wallShort', 'structures/' + style + '_wall_short', 0*PI, 2*scaleByCiv[style]); |
109 | | wallStyles[style]['wall'] = new WallElement('wall', 'structures/' + style + '_wall_medium', 0*PI, 4*scaleByCiv[style]); |
110 | | wallStyles[style]['wallLong'] = new WallElement('wallLong', 'structures/' + style + '_wall_long', 0*PI, 6*scaleByCiv[style]); |
| 104 | wallStyles[style]['tower'] = new WallElement('tower', 'structures/' + style + '_wall_tower', PI, wallScaleByType[style]); |
| 105 | wallStyles[style]['endLeft'] = new WallElement('endLeft', 'structures/' + style + '_wall_tower', PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades... |
| 106 | wallStyles[style]['endRight'] = new WallElement('endRight', 'structures/' + style + '_wall_tower', PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades... |
| 107 | wallStyles[style]['cornerIn'] = new WallElement('cornerIn', 'structures/' + style + '_wall_tower', 5*PI/4, 0, 0.35*wallScaleByType[style], PI/2); // 2^0.5 / 4 ~= 0.35 ~= 1/3 |
| 108 | wallStyles[style]['cornerOut'] = new WallElement('cornerOut', 'structures/' + style + '_wall_tower', 3*PI/4, 0.71*wallScaleByType[style], 0, -PI/2); // // 2^0.5 / 2 ~= 0.71 ~= 2/3 |
| 109 | wallStyles[style]['wallShort'] = new WallElement('wallShort', 'structures/' + style + '_wall_short', 0*PI, 2*wallScaleByType[style]); |
| 110 | wallStyles[style]['wall'] = new WallElement('wall', 'structures/' + style + '_wall_medium', 0*PI, 4*wallScaleByType[style]); |
| 111 | wallStyles[style]['wallMedium'] = new WallElement('wall', 'structures/' + style + '_wall_medium', 0*PI, 4*wallScaleByType[style]); |
| 112 | wallStyles[style]['wallLong'] = new WallElement('wallLong', 'structures/' + style + '_wall_long', 0*PI, 6*wallScaleByType[style]); |
131 | | wallStyles[style]['barracks'] = new WallElement('barracks', 'structures/' + civ + '_barracks', PI, 0, 4.5*scaleByCiv[style]); |
132 | | wallStyles[style]['civilCentre'] = new WallElement('civilCentre', 'structures/' + civ + '_civil_centre', PI, 0, 4.5*scaleByCiv[style]); |
133 | | wallStyles[style]['farmstead'] = new WallElement('farmstead', 'structures/' + civ + '_farmstead', PI, 0, 4.5*scaleByCiv[style]); |
134 | | wallStyles[style]['field'] = new WallElement('field', 'structures/' + civ + '_field', PI, 0, 4.5*scaleByCiv[style]); |
135 | | wallStyles[style]['fortress'] = new WallElement('fortress', 'structures/' + civ + '_fortress', PI, 0, 4.5*scaleByCiv[style]); |
136 | | wallStyles[style]['house'] = new WallElement('house', 'structures/' + civ + '_house', PI, 0, 4.5*scaleByCiv[style]); |
137 | | wallStyles[style]['market'] = new WallElement('market', 'structures/' + civ + '_market', PI, 0, 4.5*scaleByCiv[style]); |
138 | | wallStyles[style]['mill'] = new WallElement('mill', 'structures/' + civ + '_mill', PI, 0, 4.5*scaleByCiv[style]); |
139 | | wallStyles[style]['temple'] = new WallElement('temple', 'structures/' + civ + '_temple', PI, 0, 4.5*scaleByCiv[style]); |
| 130 | wallStyles[style]['barracks'] = new WallElement('barracks', 'structures/' + civ + '_barracks', PI, 0, 4.5*wallScaleByType[style]); |
| 131 | wallStyles[style]['civilCentre'] = new WallElement('civilCentre', 'structures/' + civ + '_civil_centre', PI, 0, 4.5*wallScaleByType[style]); |
| 132 | wallStyles[style]['farmstead'] = new WallElement('farmstead', 'structures/' + civ + '_farmstead', PI, 0, 4.5*wallScaleByType[style]); |
| 133 | wallStyles[style]['field'] = new WallElement('field', 'structures/' + civ + '_field', PI, 0, 4.5*wallScaleByType[style]); |
| 134 | wallStyles[style]['fortress'] = new WallElement('fortress', 'structures/' + civ + '_fortress', PI, 0, 4.5*wallScaleByType[style]); |
| 135 | wallStyles[style]['house'] = new WallElement('house', 'structures/' + civ + '_house', PI, 0, 4.5*wallScaleByType[style]); |
| 136 | wallStyles[style]['market'] = new WallElement('market', 'structures/' + civ + '_market', PI, 0, 4.5*wallScaleByType[style]); |
| 137 | wallStyles[style]['mill'] = new WallElement('mill', 'structures/' + civ + '_mill', PI, 0, 4.5*wallScaleByType[style]); |
| 138 | wallStyles[style]['temple'] = new WallElement('temple', 'structures/' + civ + '_temple', PI, 0, 4.5*wallScaleByType[style]); |
141 | | wallStyles[style]['space1'] = new WallElement('space1', undefined, 0*PI, scaleByCiv[style]); |
142 | | wallStyles[style]['space2'] = new WallElement('space2', undefined, 0*PI, 2*scaleByCiv[style]); |
143 | | wallStyles[style]['space3'] = new WallElement('space3', undefined, 0*PI, 3*scaleByCiv[style]); |
144 | | wallStyles[style]['space4'] = new WallElement('space4', undefined, 0*PI, 4*scaleByCiv[style]); |
| 140 | wallStyles[style]['space1'] = new WallElement('space1', undefined, 0*PI, wallScaleByType[style]); |
| 141 | wallStyles[style]['space2'] = new WallElement('space2', undefined, 0*PI, 2*wallScaleByType[style]); |
| 142 | wallStyles[style]['space3'] = new WallElement('space3', undefined, 0*PI, 3*wallScaleByType[style]); |
| 143 | wallStyles[style]['space4'] = new WallElement('space4', undefined, 0*PI, 4*wallScaleByType[style]); |
| 186 | // NOTE: This is not a wall style in the common sense. Use with care! |
| 187 | wallStyles['road'] = {}; |
| 188 | wallStyles['road']['short'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5); |
| 189 | wallStyles['road']['long'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5); |
| 190 | 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 |
| 191 | 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 |
| 192 | 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 |
| 193 | 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 |
| 194 | wallStyles['road']['start'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2); |
| 195 | wallStyles['road']['end'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2); |
| 196 | wallStyles['road']['xStraight'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5); |
| 197 | wallStyles['road']['xLeft'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, PI/2); |
| 198 | wallStyles['road']['xRight'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, -PI/2); |
| 199 | wallStyles['road']['tLeft'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25); |
| 200 | wallStyles['road']['tRight'] = new WallElement('road', "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0*PI, 4.5, -1.25); |
| 269 | // Add some "fortress types" for roads (will only work with style "road") |
| 270 | // ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"]; |
| 271 | var wall = ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"]; |
| 272 | fortressTypes['road01'] = new Fortress('road01', wall); |
| 273 | var wall = ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"]; |
| 274 | fortressTypes['road02'] = new Fortress('road02', wall); |
| 275 | var wall = ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"]; |
| 276 | fortressTypes['road03'] = new Fortress('road03', wall); |
| 277 | var wall = ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short", |
| 278 | "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"]; |
| 279 | fortressTypes['road04'] = new Fortress('road04', wall); |
| 280 | var wall = ["start", "tLeft", "short", "xRight", |
| 281 | "curveLeft", "xRight", "tRight", "cornerLeft", "tRight", |
| 282 | "curveLeft", "short", "tRight", "cornerLeft", "xRight", |
| 283 | "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"]; |
| 284 | fortressTypes['road05'] = new Fortress('road05', wall); |
| 285 | |
724 | | // Just a test function, USE WITH CARE! |
| 759 | //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 760 | // |
| 761 | // Place generic fortress with towers at the edges connected with long walls and gates |
| 762 | // |
| 763 | // This is the default Iberian civ bonus starting wall |
| 764 | // |
| 765 | // style Which wall style should be used, default is the given players civ, palisades for gaia |
| 766 | // irregularity How irregular the wall will be, 0 -> circle, 1 -> very spiky, default is 0.5 |
| 767 | // gateOccurence Integer number, every n walls will be gates instead, default is 3 |
| 768 | // maxTrys How often the function tries to find a better fitting shape at max, default is 100 |
| 769 | // |
| 770 | //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 771 | function placeGenericFortress(centerX, centerY, radius, playerId, style, irregularity, gateOccurence, maxTrys) |
| 772 | { |
| 773 | // Setup optional arguments |
| 774 | radius = (radius || 20); |
| 775 | playerId = (playerId || 0); |
| 776 | if (playerId == 0) |
| 777 | style = (style || "palisades"); |
| 778 | else |
| 779 | style = (style || g_MapSettings.PlayerData[playerId-1].Civ); |
| 780 | irregularity = (irregularity || 0.5); |
| 781 | gateOccurence = (gateOccurence || 3); |
| 782 | maxTrys = (maxTrys || 100); |
| 783 | // Setup some vars |
| 784 | var startAngle = randFloat(0, 2*PI); |
| 785 | var actualOffX = radius*cos(startAngle); |
| 786 | var actualOffY = radius*sin(startAngle); |
| 787 | var actualAngle = startAngle; |
| 788 | var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width; |
| 789 | // Searching for a well fitting point derivation |
| 790 | var tries = 0; |
| 791 | var bestPointDerivation = undefined; |
| 792 | var minOverlap = 1000; |
| 793 | var overlap = undefined; |
| 794 | while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10) |
| 795 | { |
| 796 | var pointDerivation = []; |
| 797 | var distanceToTarget = 1000; |
| 798 | var targetReached = false; |
| 799 | while (!targetReached) |
| 800 | { |
| 801 | var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance); |
| 802 | var tmpAngle = getAngle(actualOffX, actualOffY, |
| 803 | (radius + indent)*cos(actualAngle + (pointDistance / radius)), |
| 804 | (radius + indent)*sin(actualAngle + (pointDistance / radius))); |
| 805 | actualOffX += pointDistance*cos(tmpAngle); |
| 806 | actualOffY += pointDistance*sin(tmpAngle); |
| 807 | actualAngle = getAngle(0, 0, actualOffX, actualOffY); |
| 808 | pointDerivation.push([actualOffX, actualOffY]); |
| 809 | distanceToTarget = getDistance(actualOffX, actualOffY, pointDerivation[0][0], pointDerivation[0][1]); |
| 810 | if ( pointDerivation.length > 3 && distanceToTarget < pointDistance) // Could be done better... |
| 811 | { |
| 812 | targetReached = true; |
| 813 | overlap = pointDistance - getDistance(pointDerivation[pointDerivation.length - 1][0], pointDerivation[pointDerivation.length - 1][1], pointDerivation[0][0], pointDerivation[0][1]); |
| 814 | if (overlap < minOverlap) |
| 815 | { |
| 816 | minOverlap = overlap; |
| 817 | bestPointDerivation = pointDerivation; |
| 818 | } |
| 819 | } |
| 820 | } |
| 821 | tries++; |
| 822 | } |
| 823 | log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries"); |
| 824 | // Place wall |
| 825 | for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++) |
| 826 | { |
| 827 | var startX = centerX + bestPointDerivation[pointIndex][0]; |
| 828 | var startY = centerY + bestPointDerivation[pointIndex][1]; |
| 829 | var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0]; |
| 830 | var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1]; |
| 831 | var angle = getAngle(startX, startY, targetX, targetY); |
| 832 | var wallElement = "wallLong"; |
| 833 | if ((pointIndex + 1) % gateOccurence == 0) |
| 834 | wallElement = "entry"; |
| 835 | if (wallStyles[style][wallElement].entity) |
| 836 | { |
| 837 | placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX |
| 838 | startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY |
| 839 | wallStyles[style][wallElement].entity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle); |
| 840 | } |
| 841 | // Place tower |
| 842 | var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0]; |
| 843 | var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1]; |
| 844 | var angle = getAngle(startX, startY, targetX, targetY); |
| 845 | placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style]["tower"].entity, playerId, angle - PI/2 + wallStyles[style]["tower"].angle); |
| 846 | } |
| 847 | } |
| 848 | |
| 849 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 850 | // Place an generic 'organic' looking wall of repeatant wall elements given by wallPart roughly arround centerX/centerY with roughly the given radius |
| 851 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
726 | | // maxBendOff: Optional, The maximum random bending offset of the wall elements NOTE: If maxBendOff > PI/2 the wall might never close!!! |
727 | | // wallPart: Optional, An array of wall element string, example: ["tower", "wall"] NOTE: Don't use wall elements with bending!!! |
728 | | function placeGenericFortress(centerX, centerY, radius, playerId, wallPart, style, maxBendOff) |
| 853 | // maxBendOff: Optional, The maximum random bending offset of the wall elements |
| 854 | // NOTE: If maxBendOff > PI/3 the wall might not circumvent the center, if > PI/2 the wall might wind up in an infinite loop!!! |
| 855 | // wallPart: Optional, An array of wall element string, example: ["tower", "wall"] |
| 856 | // NOTE: Don't use wall elements with bending like corners! |
| 857 | function placeOrganicFortress(centerX, centerY, radius, playerId, wallPart, style, maxBendOff) |
736 | | var wallLength = 0; |
737 | | for (var eleIndex = 0; eleIndex < wallPart.length; eleIndex++) |
738 | | { |
739 | | wallLength += wallStyles[style][wallPart[eleIndex]].width |
740 | | } |
741 | | if (wallLength > 2*PI*radius || wallLength <= 0) |
742 | | warn("setGenericFortress: sum of the width of wall's elements should satisfy 0 < total length < 2*PI*radius but: radius = " + radius + ", wallPart = " + wallPart + " with total length of " + wallLength); |
743 | | |
744 | | var minEleWidth = 1000000; // Assuming the smallest element is about as wide as deep. |
745 | | for (var eleIndex = 0; eleIndex < wallPart.length; eleIndex++) |
746 | | { |
747 | | eleWidth = wallStyles[style][wallPart[eleIndex]].width; |
748 | | if (eleWidth < minEleWidth) |
749 | | minEleWidth = eleWidth; |
750 | | } |
751 | | var widthSafty = minEleWidth/4; // Can be done better... |
752 | | |
| 864 | // Check arguments for sane values |
| 865 | if (maxBendOff > PI/3 || maxBendOff < 0) |
| 866 | warn("placeOrganicFortress maxBendOff sould satisfy 0 < maxBendOff < PI/3 (~1) to ensure stability but it is: " + maxBendOff); |
| 867 | // Check wall part length against shortest theoretical total wall length (circle perimeter) |
| 868 | var wallPartLength = getWallLength(wallPart, style); |
| 869 | if (wallPartLength > PI*radius || wallPartLength <= 0) |
| 870 | warn("placeOrganicFortress: Given wall part is longer than half the circle perimeter of given radius: Half circle perimeter ~= " + round(PI*radius) +", wallPart total length ~= " + round(wallPartLength)); |
| 871 | // Setting up some variables |