1 | ////////////////////////////////////////////////////////////////////
|
---|
2 | // This file contains functionality to place walls on random maps //
|
---|
3 | ////////////////////////////////////////////////////////////////////
|
---|
4 |
|
---|
5 | // To do:
|
---|
6 | // Check if all wall placement methods work with wall elements with entity === undefined (some still might raise errors in that case)
|
---|
7 | // Rename wall elements to fit the entity names so that entity = "structures/" + "civ + "_" + wallElement.type in the common case (as far as possible)
|
---|
8 | // Perhaps add Roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength
|
---|
9 | // Perhaps add further wall elements cornerInHalf, cornerOutHalf (banding PI/4) and adjust default fortress types to better fit in the octagonal territory of a civil center
|
---|
10 | // Perhaps swap angle and width in WallElement class(?) definition
|
---|
11 | // Adjust argument order to be always the same:
|
---|
12 | // Coordinates (center/start/target)
|
---|
13 | // Wall element arguments (wall/wallPart/fortressType/cornerElement)
|
---|
14 | // playerId (optional, default is 0/gaia)
|
---|
15 | // wallStyle (optional, default is the players civ/"palisades for gaia")
|
---|
16 | // angle/orientation (optional, default is 0)
|
---|
17 | // other (all optional) arguments especially those hard to define (wallPartsAssortment, maybe make an own function for it)
|
---|
18 | // Some arguments don't clearly match to this concept:
|
---|
19 | // endWithFirst (wall or other)
|
---|
20 | // skipFirstWall (wall or other)
|
---|
21 | // gateOccurence (wall or other)
|
---|
22 | // numCorners (wall or other)
|
---|
23 | // skipFirstWall (wall or other)
|
---|
24 | // maxAngle (angle or other)
|
---|
25 | // maxBendOff (angle or other, unused ATM!!!)
|
---|
26 | // irregularity
|
---|
27 | // maxTrys
|
---|
28 | // Add treasures to wall style "others"
|
---|
29 | // Adjust documentation
|
---|
30 | // Perhaps rename "endLeft" to "start" and "endRight" to "end"
|
---|
31 | // ?Use available civ-type wall elements rather than palisades: Remove "endLeft" and "endRight" as default wall elements and adjust default palisade fortress types?
|
---|
32 | // ?Remove "endRight", "endLeft" and adjust generic fortress types palisades?
|
---|
33 | // ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads?
|
---|
34 | // ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending?
|
---|
35 |
|
---|
36 |
|
---|
37 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
38 | // WallElement class definition
|
---|
39 | //
|
---|
40 | // Concept: If placed unrotated the wall's course is towards positive Y (top) with "outside" right (+X) and "inside" left (-X) like unrotated entities has their drop-points right (in rmgen)
|
---|
41 | // The course of the wall will be changed by corners (bending != 0) and so the "inside"/"outside" direction
|
---|
42 | //
|
---|
43 | // type Descriptive string, example: "wallLong". NOTE: Not really needed. Mainly for custom wall elements and to get the wall element type in code
|
---|
44 | // entity Optional. Template name string of the entity to be placed, example: "structures/cart_wall_long". Default is undefined (No entity placed)
|
---|
45 | // angle Optional. The angle (float) added to place the entity so "outside" is right when the wall element is placed unrotated. Default is 0
|
---|
46 | // width Optional. How far this wall element lengthens the wall (float), if unrotated the Y space needed. Default is 0
|
---|
47 | // indent Optional. The lateral indentation of the entity, drawn "inside" (positive values) or pushed "outside" (negative values). Default is 0
|
---|
48 | // bending Optional. How the course of the wall is changed after this element, positive is bending "in"/left/counter clockwise (like entity placement)
|
---|
49 | // NOTE: Bending is not supported by all placement functions (see there)
|
---|
50 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
51 | function WallElement(type, entity, angle, width, indent, bending)
|
---|
52 | {
|
---|
53 | this.type = type;
|
---|
54 | // Default wall element type documentation:
|
---|
55 | // Lengthening straight blocking (mainly left/right symmetric) wall elements (Walls and wall fortifications)
|
---|
56 | // "wall" A blocking straight wall element that mainly lengthens the wall, self-explanatory
|
---|
57 | // "wallShort" self-explanatory
|
---|
58 | // "wallLong" self-explanatory
|
---|
59 | // "tower" A blocking straight wall element with damage potential (but for palisades) that slightly lengthens the wall, example: wall tower, palisade tower(No attack)
|
---|
60 | // "wallFort" A blocking straight wall element with massive damage potential that lengthens the wall, example: fortress, palisade fort
|
---|
61 | // Lengthening straight non/custom blocking (mainly left/right symmetric) wall elements (Gates and entries)
|
---|
62 | // "gate" A blocking straight wall element with passability determined by owner, example: gate (Functionality not yet implemented)
|
---|
63 | // "entry" A non-blocking straight wall element (same width as gate) but without an actual template or just a flag/column/obelisk
|
---|
64 | // "entryTower" A non-blocking straight wall element (same width as gate) represented by a single (maybe indented) template, example: defence tower, wall tower, outpost, watchtower
|
---|
65 | // "entryFort" A non-blocking straight wall element represented by a single (maybe indented) template, example: fortress, palisade fort
|
---|
66 | // Bending wall elements (Wall corners)
|
---|
67 | // "cornerIn" A wall element bending the wall by PI/2 "inside" (left, +, see above), example: wall tower, palisade curve
|
---|
68 | // "cornerOut" A wall element bending the wall by PI/2 "outside" (right, -, see above), example: wall tower, palisade curve
|
---|
69 | // "cornerHalfIn" A wall element bending the wall by PI/4 "inside" (left, +, see above), example: wall tower, palisade curve. NOTE: Not yet implemented
|
---|
70 | // "cornerHalfOut" A wall element bending the wall by PI/4 "outside" (right, -, see above), example: wall tower, palisade curve. NOTE: Not yet implemented
|
---|
71 | // Zero length straight indented (mainly left/right symmetric) wall elements (Outposts/watchtowers and non-defensive base structures)
|
---|
72 | // "outpost" A zero-length wall element without bending far indented so it stands outside the wall, example: outpost, defence tower, watchtower
|
---|
73 | // "house" A zero-length wall element without bending far indented so it stands inside the wall that grants population bonus, example: house, hut, longhouse
|
---|
74 | // "barracks" A zero-length wall element without bending far indented so it stands inside the wall that grants unit production, example: barracks, tavern, ...
|
---|
75 | this.entity = entity;
|
---|
76 | this.angle = (angle !== undefined) ? angle : 0*PI;
|
---|
77 | this.width = (width !== undefined) ? width : 0;
|
---|
78 | this.indent = (indent !== undefined) ? indent : 0;
|
---|
79 | this.bending = (bending !== undefined) ? bending : 0*PI;
|
---|
80 | }
|
---|
81 |
|
---|
82 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
83 | // Fortress class definition
|
---|
84 | //
|
---|
85 | // A "fortress" here is a closed wall build of multiple wall elements attached together defined in Fortress.wall
|
---|
86 | // It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles)
|
---|
87 | //
|
---|
88 | // type Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements
|
---|
89 | // wall Optional. Array of wall element strings. Can be set afterwards. Default is an epty array.
|
---|
90 | // Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"]
|
---|
91 | // centerToFirstElement Optional. Object with properties "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined
|
---|
92 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
93 | function Fortress(type, wall, centerToFirstElement)
|
---|
94 | {
|
---|
95 | this.type = type; // Only usefull to get the type of the actual fortress
|
---|
96 | this.wall = (wall !== undefined) ? wall : [];
|
---|
97 | this.centerToFirstElement = undefined;
|
---|
98 | }
|
---|
99 |
|
---|
100 |
|
---|
101 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
102 | // wallStyles data structure for default wall styles
|
---|
103 | //
|
---|
104 | // A wall style is an associative array with all wall elements of that style in it associated with the wall element type string
|
---|
105 | // wallStyles holds all the wall styles within an associative array with the civ string or another descriptive strings as key
|
---|
106 | // Examples: "athen", "rome_siege", "palisades", "fence", "road"
|
---|
107 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
108 | var wallStyles = {};
|
---|
109 |
|
---|
110 | // Generic civ dependent wall style definition. "rome_siege" needs some tweek...
|
---|
111 | 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, "maur": 1.5, "pers" : 1.5, "ptol" : 1.5, "rome" : 1.5, "spart" : 1.5, "rome_siege" : 1.5};
|
---|
112 | for (var style in wallScaleByType)
|
---|
113 | {
|
---|
114 | var civ = style;
|
---|
115 | if (style == "rome_siege")
|
---|
116 | civ = "rome";
|
---|
117 | wallStyles[style] = {};
|
---|
118 | // Default wall elements
|
---|
119 | wallStyles[style]["tower"] = new WallElement("tower", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]);
|
---|
120 | wallStyles[style]["endLeft"] = new WallElement("endLeft", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
|
---|
121 | wallStyles[style]["endRight"] = new WallElement("endRight", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades...
|
---|
122 | wallStyles[style]["cornerIn"] = new WallElement("cornerIn", "structures/" + style + "_wall_tower", 5*PI/4, 0, 0.35*wallScaleByType[style], PI/2); // 2^0.5 / 4 ~= 0.35 ~= 1/3
|
---|
123 | wallStyles[style]["cornerOut"] = new WallElement("cornerOut", "structures/" + style + "_wall_tower", 3*PI/4, 0.71*wallScaleByType[style], 0, -PI/2); // // 2^0.5 / 2 ~= 0.71 ~= 2/3
|
---|
124 | wallStyles[style]["wallShort"] = new WallElement("wallShort", "structures/" + style + "_wall_short", 0*PI, 2*wallScaleByType[style]);
|
---|
125 | wallStyles[style]["wall"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]);
|
---|
126 | wallStyles[style]["wallMedium"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]);
|
---|
127 | wallStyles[style]["wallLong"] = new WallElement("wallLong", "structures/" + style + "_wall_long", 0*PI, 6*wallScaleByType[style]);
|
---|
128 | // Gate and entrance wall elements
|
---|
129 | var gateWidth = 6*wallScaleByType[style];
|
---|
130 | wallStyles[style]["gate"] = new WallElement("gate", "structures/" + style + "_wall_gate", PI, gateWidth);
|
---|
131 | wallStyles[style]["entry"] = new WallElement("entry", undefined, 0*PI, gateWidth);
|
---|
132 | wallStyles[style]["entryTower"] = new WallElement("entryTower", "structures/" + civ + "_defense_tower", PI, gateWidth, -4*wallScaleByType[style]);
|
---|
133 | wallStyles[style]["entryFort"] = new WallElement("entryFort", "structures/" + civ + "_fortress", 0*PI, 8*wallScaleByType[style], 6*wallScaleByType[style]);
|
---|
134 | // Defensive wall elements with 0 width outside the wall
|
---|
135 | wallStyles[style]["outpost"] = new WallElement("outpost", "structures/" + civ + "_outpost", PI, 0, -4*wallScaleByType[style]);
|
---|
136 | wallStyles[style]["defenseTower"] = new WallElement("defenseTower", "structures/" + civ + "_defense_tower", PI, 0, -4*wallScaleByType[style]);
|
---|
137 | // Base buildings wall elements with 0 width inside the wall
|
---|
138 | wallStyles[style]["barracks"] = new WallElement("barracks", "structures/" + civ + "_barracks", PI, 0, 4.5*wallScaleByType[style]);
|
---|
139 | wallStyles[style]["civilCentre"] = new WallElement("civilCentre", "structures/" + civ + "_civil_centre", PI, 0, 4.5*wallScaleByType[style]);
|
---|
140 | wallStyles[style]["farmstead"] = new WallElement("farmstead", "structures/" + civ + "_farmstead", PI, 0, 4.5*wallScaleByType[style]);
|
---|
141 | wallStyles[style]["field"] = new WallElement("field", "structures/" + civ + "_field", PI, 0, 4.5*wallScaleByType[style]);
|
---|
142 | wallStyles[style]["fortress"] = new WallElement("fortress", "structures/" + civ + "_fortress", PI, 0, 4.5*wallScaleByType[style]);
|
---|
143 | wallStyles[style]["house"] = new WallElement("house", "structures/" + civ + "_house", PI, 0, 4.5*wallScaleByType[style]);
|
---|
144 | wallStyles[style]["market"] = new WallElement("market", "structures/" + civ + "_market", PI, 0, 4.5*wallScaleByType[style]);
|
---|
145 | wallStyles[style]["storehouse"] = new WallElement("storehouse", "structures/" + civ + "_storehouse", PI, 0, 4.5*wallScaleByType[style]);
|
---|
146 | wallStyles[style]["temple"] = new WallElement("temple", "structures/" + civ + "_temple", PI, 0, 4.5*wallScaleByType[style]);
|
---|
147 | // Generic space/gap wall elements
|
---|
148 | wallStyles[style]["space1"] = new WallElement("space1", undefined, 0*PI, wallScaleByType[style]);
|
---|
149 | wallStyles[style]["space2"] = new WallElement("space2", undefined, 0*PI, 2*wallScaleByType[style]);
|
---|
150 | wallStyles[style]["space3"] = new WallElement("space3", undefined, 0*PI, 3*wallScaleByType[style]);
|
---|
151 | wallStyles[style]["space4"] = new WallElement("space4", undefined, 0*PI, 4*wallScaleByType[style]);
|
---|
152 | }
|
---|
153 | // Add wall fortresses for all generic styles
|
---|
154 | wallStyles["athen"]["wallFort"] = new WallElement("wallFort", "structures/athen_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
155 | wallStyles["brit"]["wallFort"] = new WallElement("wallFort", "structures/brit_fortress", PI, 2.8);
|
---|
156 | wallStyles["cart"]["wallFort"] = new WallElement("wallFort", "structures/cart_fortress", PI, 5.1, 1.6);
|
---|
157 | wallStyles["celt"]["wallFort"] = new WallElement("wallFort", "structures/celt_fortress_g", PI, 4.2, 1.5);
|
---|
158 | wallStyles["gaul"]["wallFort"] = new WallElement("wallFort", "structures/gaul_fortress", PI, 4.2, 1.5);
|
---|
159 | wallStyles["hele"]["wallFort"] = new WallElement("wallFort", "structures/hele_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
160 | wallStyles["iber"]["wallFort"] = new WallElement("wallFort", "structures/iber_fortress", PI, 5, 0.2);
|
---|
161 | wallStyles["mace"]["wallFort"] = new WallElement("wallFort", "structures/mace_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
162 | wallStyles["maur"]["wallFort"] = new WallElement("wallFort", "structures/maur_fortress", PI, 5.5);
|
---|
163 | wallStyles["pers"]["wallFort"] = new WallElement("wallFort", "structures/pers_fortress", PI, 5.6/*5.5*/, 1.9/*1.7*/);
|
---|
164 | wallStyles["ptol"]["wallFort"] = new WallElement("wallFort", "structures/athen_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
165 | wallStyles["rome"]["wallFort"] = new WallElement("wallFort", "structures/rome_fortress", PI, 6.3, 2.1);
|
---|
166 | wallStyles["spart"]["wallFort"] = new WallElement("wallFort", "structures/spart_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
167 | // Adjust "rome_siege" style
|
---|
168 | wallStyles["rome_siege"]["wallFort"] = new WallElement("wallFort", "structures/rome_army_camp", PI, 7.2, 2);
|
---|
169 | wallStyles["rome_siege"]["entryFort"] = new WallElement("entryFort", "structures/rome_army_camp", PI, 12, 7);
|
---|
170 | wallStyles["rome_siege"]["house"] = new WallElement("house", "structures/rome_tent", PI, 0, 4);
|
---|
171 |
|
---|
172 | // Add special wall styles not well to implement generic (and to show how custom styles can be added)
|
---|
173 |
|
---|
174 | // Add wall style "palisades"
|
---|
175 | wallScaleByType["palisades"] = 0.55;
|
---|
176 | wallStyles["palisades"] = {};
|
---|
177 | wallStyles["palisades"]["wall"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3);
|
---|
178 | wallStyles["palisades"]["wallMedium"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3);
|
---|
179 | wallStyles["palisades"]["wallLong"] = new WallElement("wall", "other/palisades_rocks_long", 0*PI, 3.5);
|
---|
180 | wallStyles["palisades"]["wallShort"] = new WallElement("wall", "other/palisades_rocks_short", 0*PI, 1.2);
|
---|
181 | wallStyles["palisades"]["tower"] = new WallElement("tower", "other/palisades_rocks_tower", -PI/2, 0.7);
|
---|
182 | wallStyles["palisades"]["wallFort"] = new WallElement("wallFort", "other/palisades_rocks_fort", PI, 1.7);
|
---|
183 | wallStyles["palisades"]["gate"] = new WallElement("gate", "other/palisades_rocks_gate", PI, 3.6);
|
---|
184 | wallStyles["palisades"]["entry"] = new WallElement("entry", undefined, wallStyles["palisades"]["gate"].angle, wallStyles["palisades"]["gate"].width);
|
---|
185 | wallStyles["palisades"]["entryTower"] = new WallElement("entryTower", "other/palisades_rocks_watchtower", 0*PI, wallStyles["palisades"]["gate"].width, -3);
|
---|
186 | wallStyles["palisades"]["entryFort"] = new WallElement("entryFort", "other/palisades_rocks_fort", PI, 6, 3);
|
---|
187 | wallStyles["palisades"]["cornerIn"] = new WallElement("cornerIn", "other/palisades_rocks_curve", 3*PI/4, 2.1, 0.7, PI/2);
|
---|
188 | wallStyles["palisades"]["cornerOut"] = new WallElement("cornerOut", "other/palisades_rocks_curve", 5*PI/4, 2.1, -0.7, -PI/2);
|
---|
189 | wallStyles["palisades"]["outpost"] = new WallElement("outpost", "other/palisades_rocks_outpost", PI, 0, -2);
|
---|
190 | wallStyles["palisades"]["house"] = new WallElement("house", "other/celt_hut", PI, 0, 5);
|
---|
191 | wallStyles["palisades"]["barracks"] = new WallElement("barracks", "other/celt_tavern", PI, 0, 5);
|
---|
192 | wallStyles["palisades"]["endRight"] = new WallElement("endRight", "other/palisades_rocks_end", -PI/2, 0.2);
|
---|
193 | wallStyles["palisades"]["endLeft"] = new WallElement("endLeft", "other/palisades_rocks_end", PI/2, 0.2);
|
---|
194 |
|
---|
195 | // Add special wall style "road"
|
---|
196 | // NOTE: This is not a wall style in the common sense. Use with care!
|
---|
197 | wallStyles["road"] = {};
|
---|
198 | wallStyles["road"]["short"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5);
|
---|
199 | wallStyles["road"]["long"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5);
|
---|
200 | 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
|
---|
201 | 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
|
---|
202 | 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
|
---|
203 | 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
|
---|
204 | wallStyles["road"]["start"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2);
|
---|
205 | wallStyles["road"]["end"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2);
|
---|
206 | wallStyles["road"]["xStraight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5);
|
---|
207 | wallStyles["road"]["xLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, PI/2);
|
---|
208 | wallStyles["road"]["xRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, -PI/2);
|
---|
209 | wallStyles["road"]["tLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25);
|
---|
210 | wallStyles["road"]["tRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0*PI, 4.5, -1.25);
|
---|
211 |
|
---|
212 | // Add special wall element collection "other"
|
---|
213 | // NOTE: This is not a wall style in the common sense. Use with care!
|
---|
214 | wallStyles["other"] = {};
|
---|
215 | wallStyles["other"]["fence"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1);
|
---|
216 | wallStyles["other"]["fence_medium"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1);
|
---|
217 | wallStyles["other"]["fence_short"] = new WallElement("fence_short", "other/fence_short", -PI/2, 1.5);
|
---|
218 | wallStyles["other"]["fence_stone"] = new WallElement("fence_stone", "other/fence_stone", -PI/2, 2.5);
|
---|
219 | wallStyles["other"]["palisade"] = new WallElement("palisade", "other/palisades_rocks_short", 0, 1.2);
|
---|
220 | wallStyles["other"]["column"] = new WallElement("column", "other/column_doric", 0, 1);
|
---|
221 | wallStyles["other"]["obelisk"] = new WallElement("obelisk", "other/obelisk", 0, 2);
|
---|
222 | wallStyles["other"]["spike"] = new WallElement("spike", "other/palisades_angle_spike", -PI/2, 1);
|
---|
223 | wallStyles["other"]["bench"] = new WallElement("bench", "other/bench", PI/2, 1.5);
|
---|
224 | wallStyles["other"]["benchForTable"] = new WallElement("benchForTable", "other/bench", 0, 0.5);
|
---|
225 | wallStyles["other"]["table"] = new WallElement("table", "other/table_rectangle", 0, 1);
|
---|
226 | wallStyles["other"]["table_square"] = new WallElement("table_square", "other/table_square", PI/2, 1);
|
---|
227 | wallStyles["other"]["flag"] = new WallElement("flag", "special/rallypoint", PI, 1);
|
---|
228 | wallStyles["other"]["standing_stone"] = new WallElement("standing_stone", "gaia/special_ruins_standing_stone", PI, 1);
|
---|
229 | wallStyles["other"]["settlement"] = new WallElement("settlement", "gaia/special_settlement", PI, 6);
|
---|
230 | wallStyles["other"]["gap"] = new WallElement("gap", undefined, 0, 2);
|
---|
231 | wallStyles["other"]["gapSmall"] = new WallElement("gapSmall", undefined, 0, 1);
|
---|
232 | wallStyles["other"]["gapLarge"] = new WallElement("gapLarge", undefined, 0, 4);
|
---|
233 | wallStyles["other"]["cornerIn"] = new WallElement("cornerIn", undefined, 0, 0, 0, PI/2);
|
---|
234 | wallStyles["other"]["cornerOut"] = new WallElement("cornerOut", undefined, 0, 0, 0, -PI/2);
|
---|
235 |
|
---|
236 |
|
---|
237 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
238 | // fortressTypes data structure for some default fortress types
|
---|
239 | //
|
---|
240 | // A fortress type is just an instance of the Fortress class with actually something in it
|
---|
241 | // fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size)
|
---|
242 | // Examples: "tiny", "veryLarge"
|
---|
243 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
244 | var fortressTypes = {};
|
---|
245 | // Setup some default fortress types
|
---|
246 | // Add fortress type "tiny"
|
---|
247 | fortressTypes["tiny"] = new Fortress("tiny");
|
---|
248 | var wallPart = ["gate", "tower", "wallShort", "cornerIn", "wallShort", "tower"];
|
---|
249 | fortressTypes["tiny"].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
250 | // Add fortress type "small"
|
---|
251 | fortressTypes["small"] = new Fortress("small");
|
---|
252 | var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "tower"];
|
---|
253 | fortressTypes["small"].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
254 | // Add fortress type "medium"
|
---|
255 | fortressTypes["medium"] = new Fortress("medium");
|
---|
256 | var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "tower"];
|
---|
257 | fortressTypes["medium"].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
258 | // Add fortress type "normal"
|
---|
259 | fortressTypes["normal"] = new Fortress("normal");
|
---|
260 | var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wall", "cornerIn", "wall", "tower"];
|
---|
261 | fortressTypes["normal"].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
262 | // Add fortress type "large"
|
---|
263 | fortressTypes["large"] = new Fortress("large");
|
---|
264 | var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"];
|
---|
265 | fortressTypes["large"].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
266 | // Add fortress type "veryLarge"
|
---|
267 | fortressTypes["veryLarge"] = new Fortress("veryLarge");
|
---|
268 | var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wall", "cornerIn", "wall", "tower"];
|
---|
269 | fortressTypes["veryLarge"].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
270 | // Add fortress type "giant"
|
---|
271 | fortressTypes["giant"] = new Fortress("giant");
|
---|
272 | var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"];
|
---|
273 | fortressTypes["giant"].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
274 |
|
---|
275 | // Setup some better looking semi default fortresses for "palisades" style
|
---|
276 | var fortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"];
|
---|
277 | for (var i = 0; i < fortressTypeKeys.length; i++)
|
---|
278 | {
|
---|
279 | var newKey = fortressTypeKeys[i] + "Palisades";
|
---|
280 | var oldWall = fortressTypes[fortressTypeKeys[i]].wall;
|
---|
281 | fortressTypes[newKey] = new Fortress(newKey);
|
---|
282 | var fillTowersBetween = ["wallShort", "wall", "wallLong", "endLeft", "endRight", "cornerIn", "cornerOut"];
|
---|
283 | for (var j = 0; j < oldWall.length; j++)
|
---|
284 | {
|
---|
285 | 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)
|
---|
286 | if (j+1 < oldWall.length)
|
---|
287 | if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means "exists" here
|
---|
288 | fortressTypes[newKey].wall.push("tower");
|
---|
289 | }
|
---|
290 | }
|
---|
291 |
|
---|
292 | // Setup some balanced (to civ type fortresses) semi default fortresses for "palisades" style
|
---|
293 | // TODO
|
---|
294 |
|
---|
295 | // Add some "fortress types" for roads (will only work with style "road")
|
---|
296 | // ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"];
|
---|
297 | var wall = ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"];
|
---|
298 | fortressTypes["road01"] = new Fortress("road01", wall);
|
---|
299 | var wall = ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"];
|
---|
300 | fortressTypes["road02"] = new Fortress("road02", wall);
|
---|
301 | var wall = ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"];
|
---|
302 | fortressTypes["road03"] = new Fortress("road03", wall);
|
---|
303 | var wall = ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short",
|
---|
304 | "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"];
|
---|
305 | fortressTypes["road04"] = new Fortress("road04", wall);
|
---|
306 | var wall = ["start", "tLeft", "short", "xRight",
|
---|
307 | "curveLeft", "xRight", "tRight", "cornerLeft", "tRight",
|
---|
308 | "curveLeft", "short", "tRight", "cornerLeft", "xRight",
|
---|
309 | "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"];
|
---|
310 | fortressTypes["road05"] = new Fortress("road05", wall);
|
---|
311 |
|
---|
312 |
|
---|
313 | ///////////////////////////////
|
---|
314 | // Define some helper functions
|
---|
315 | ///////////////////////////////
|
---|
316 |
|
---|
317 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
318 | // getWallAlignment
|
---|
319 | //
|
---|
320 | // Returns a list of objects containing all information to place all the wall elements entities with placeObject (but the player ID)
|
---|
321 | // Placing the first wall element at startX/startY placed with an angle given by orientation
|
---|
322 | // An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement
|
---|
323 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
324 | function getWallAlignment(startX, startY, wall, style, orientation)
|
---|
325 | {
|
---|
326 | // Graciously handle arguments
|
---|
327 | if (wall === undefined)
|
---|
328 | wall = [];
|
---|
329 | if (!wallStyles.hasOwnProperty(style))
|
---|
330 | {
|
---|
331 | warn("Function getWallAlignment: Unknown style: " + style + ' (falling back to "athen")');
|
---|
332 | style = "athen";
|
---|
333 | }
|
---|
334 | orientation = (orientation || 0);
|
---|
335 |
|
---|
336 | var alignment = [];
|
---|
337 | var wallX = startX;
|
---|
338 | var wallY = startY;
|
---|
339 | for (var i = 0; i < wall.length; i++)
|
---|
340 | {
|
---|
341 | var element = wallStyles[style][wall[i]];
|
---|
342 | if (element === undefined && i == 0)
|
---|
343 | warn("No valid wall element: " + wall[i]);
|
---|
344 | // Indentation
|
---|
345 | var placeX = wallX - element.indent * cos(orientation);
|
---|
346 | var placeY = wallY - element.indent * sin(orientation);
|
---|
347 | // Add wall elements entity placement arguments to the alignment
|
---|
348 | alignment.push({"x": placeX, "y": placeY, "entity": element.entity, "angle":orientation + element.angle});
|
---|
349 | // Preset vars for the next wall element
|
---|
350 | if (i+1 < wall.length)
|
---|
351 | {
|
---|
352 | orientation += element.bending;
|
---|
353 | var nextElement = wallStyles[style][wall[i+1]];
|
---|
354 | if (nextElement === undefined)
|
---|
355 | warn("No valid wall element: " + wall[i+1]);
|
---|
356 | var distance = (element.width + nextElement.width)/2;
|
---|
357 | // Corrections for elements with indent AND bending
|
---|
358 | var indent = element.indent;
|
---|
359 | var bending = element.bending;
|
---|
360 | if (bending !== 0 && indent !== 0)
|
---|
361 | {
|
---|
362 | // Indent correction to adjust distance
|
---|
363 | distance += indent*sin(bending);
|
---|
364 | // Indent correction to normalize indentation
|
---|
365 | wallX += indent * cos(orientation);
|
---|
366 | wallY += indent * sin(orientation);
|
---|
367 | }
|
---|
368 | // Set the next coordinates of the next element in the wall without indentation adjustment
|
---|
369 | wallX -= distance * sin(orientation);
|
---|
370 | wallY += distance * cos(orientation);
|
---|
371 | }
|
---|
372 | }
|
---|
373 | return alignment;
|
---|
374 | }
|
---|
375 |
|
---|
376 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
377 | // getCenterToFirstElement
|
---|
378 | //
|
---|
379 | // Center calculation works like getting the center of mass assuming all wall elements have the same "weight"
|
---|
380 | //
|
---|
381 | // It returns the vector from the center to the first wall element
|
---|
382 | // Used to get centerToFirstElement of fortresses by default
|
---|
383 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
384 | function getCenterToFirstElement(alignment)
|
---|
385 | {
|
---|
386 | var centerToFirstElement = {"x": 0, "y": 0};
|
---|
387 | for (var i = 0; i < alignment.length; i++)
|
---|
388 | {
|
---|
389 | centerToFirstElement.x -= alignment[i].x/alignment.length;
|
---|
390 | centerToFirstElement.y -= alignment[i].y/alignment.length;
|
---|
391 | }
|
---|
392 | return centerToFirstElement;
|
---|
393 | }
|
---|
394 |
|
---|
395 | //////////////////////////////////////////////////////////////////
|
---|
396 | // getWallLength
|
---|
397 | //
|
---|
398 | // NOTE: Does not support bending wall elements like corners!
|
---|
399 | // e.g. used by placeIrregularPolygonalWall
|
---|
400 | //////////////////////////////////////////////////////////////////
|
---|
401 | function getWallLength(wall, style)
|
---|
402 | {
|
---|
403 | // Graciously handle arguments
|
---|
404 | if (wall === undefined)
|
---|
405 | wall = [];
|
---|
406 | if (!wallStyles.hasOwnProperty(style))
|
---|
407 | {
|
---|
408 | warn("Function getWallLength: Unknown style: " + style + ' (falling back to "athen")');
|
---|
409 | style = "athen";
|
---|
410 | }
|
---|
411 |
|
---|
412 | var length = 0;
|
---|
413 | for (var i = 0; i < wall.length; i++)
|
---|
414 | {
|
---|
415 | length += wallStyles[style][wall[i]].width;
|
---|
416 | }
|
---|
417 | return length;
|
---|
418 | }
|
---|
419 |
|
---|
420 |
|
---|
421 | /////////////////////////////////////////////
|
---|
422 | // Define the different wall placer functions
|
---|
423 | /////////////////////////////////////////////
|
---|
424 |
|
---|
425 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
426 | // placeWall
|
---|
427 | //
|
---|
428 | // Places a wall with wall elements attached to another like determined by WallElement properties.
|
---|
429 | //
|
---|
430 | // startX, startY Where the first wall element should be placed
|
---|
431 | // wall Array of wall element type strings. Example: ["endLeft", "wallLong", "tower", "wallLong", "endRight"]
|
---|
432 | // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
|
---|
433 | // playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia)
|
---|
434 | // orientation Optional. Angle the first wall element is placed. Default is 0
|
---|
435 | // 0 means "outside" or "front" of the wall is right (positive X) like placeObject
|
---|
436 | // It will then be build towards top/positive Y (if no bending wall elements like corners are used)
|
---|
437 | // Raising orientation means the wall is rotated counter-clockwise like placeObject
|
---|
438 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
439 | function placeWall(startX, startY, wall, style, playerId, orientation)
|
---|
440 | {
|
---|
441 | // Graciously handle arguments
|
---|
442 | if (wall === undefined)
|
---|
443 | wall = [];
|
---|
444 | playerId = (playerId || 0);
|
---|
445 | if (!wallStyles.hasOwnProperty(style))
|
---|
446 | {
|
---|
447 | if (playerId == 0)
|
---|
448 | style = (style || "palisades");
|
---|
449 | else
|
---|
450 | style = (getCivCode(playerId-1));
|
---|
451 | }
|
---|
452 | orientation = (orientation || 0);
|
---|
453 |
|
---|
454 | // Get wall alignment
|
---|
455 | var AM = getWallAlignment(startX, startY, wall, style, orientation);
|
---|
456 | // Place the wall
|
---|
457 | for (var iWall = 0; iWall < wall.length; iWall++)
|
---|
458 | {
|
---|
459 | var entity = AM[iWall].entity;
|
---|
460 | if (entity !== undefined)
|
---|
461 | placeObject(AM[iWall].x, AM[iWall].y, entity, playerId, AM[iWall].angle);
|
---|
462 | }
|
---|
463 | }
|
---|
464 |
|
---|
465 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
466 | // placeCustomFortress
|
---|
467 | //
|
---|
468 | // Place a fortress (mainly a closed wall build like placeWall) centered at centerX/centerY
|
---|
469 | // The fortress wall should always start with the main entrance (like "entry" or "gate") to get the orientation right (like placeObject)
|
---|
470 | //
|
---|
471 | // fortress An instance of Fortress with a wall defined
|
---|
472 | // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
|
---|
473 | // playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia)
|
---|
474 | // orientation Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0
|
---|
475 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
476 | function placeCustomFortress(centerX, centerY, fortress, style, playerId, orientation)
|
---|
477 | {
|
---|
478 | // Graciously handle arguments
|
---|
479 | fortress = (fortress || fortressTypes["medium"]);
|
---|
480 | playerId = (playerId || 0);
|
---|
481 | if (!wallStyles.hasOwnProperty(style))
|
---|
482 | {
|
---|
483 | if (playerId == 0)
|
---|
484 | style = (style || "palisades");
|
---|
485 | else
|
---|
486 | style = (getCivCode(playerId-1));
|
---|
487 | }
|
---|
488 | orientation = (orientation || 0);
|
---|
489 |
|
---|
490 | // Calculate center if fortress.centerToFirstElement is undefined (default)
|
---|
491 | var centerToFirstElement = fortress.centerToFirstElement;
|
---|
492 | if (centerToFirstElement === undefined)
|
---|
493 | centerToFirstElement = getCenterToFirstElement(getWallAlignment(0, 0, fortress.wall, style));
|
---|
494 | // Placing the fortress wall
|
---|
495 | var startX = centerX + centerToFirstElement.x * cos(orientation) - centerToFirstElement.y * sin(orientation);
|
---|
496 | var startY = centerY + centerToFirstElement.y * cos(orientation) + centerToFirstElement.x * sin(orientation);
|
---|
497 | placeWall(startX, startY, fortress.wall, style, playerId, orientation)
|
---|
498 | }
|
---|
499 |
|
---|
500 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
501 | // placeFortress
|
---|
502 | //
|
---|
503 | // Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress
|
---|
504 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
505 | function placeFortress(centerX, centerY, type, style, playerId, orientation)
|
---|
506 | {
|
---|
507 | // Graciously handle arguments
|
---|
508 | type = (type || "medium");
|
---|
509 | playerId = (playerId || 0);
|
---|
510 | if (!wallStyles.hasOwnProperty(style))
|
---|
511 | {
|
---|
512 | if (playerId == 0)
|
---|
513 | style = (style || "palisades");
|
---|
514 | else
|
---|
515 | style = (getCivCode(playerId-1));
|
---|
516 | }
|
---|
517 | orientation = (orientation || 0);
|
---|
518 |
|
---|
519 | // Call placeCustomFortress with the given arguments
|
---|
520 | placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation);
|
---|
521 | }
|
---|
522 |
|
---|
523 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
524 | // placeLinearWall
|
---|
525 | //
|
---|
526 | // Places a straight wall from a given coordinate to an other repeatedly using the wall parts.
|
---|
527 | //
|
---|
528 | // startX/startY Coordinate of the approximate beginning of the wall (Not the place of the first wall element)
|
---|
529 | // targetX/targetY Coordinate of the approximate ending of the wall (Not the place of the last wall element)
|
---|
530 | // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"]
|
---|
531 | // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
|
---|
532 | // playerId Optional. Integer number of the player. Default is 0 (gaia)
|
---|
533 | // endWithFirst Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true
|
---|
534 | //
|
---|
535 | // TODO: Maybe add angle offset for more generic looking?
|
---|
536 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
537 | function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId, endWithFirst)
|
---|
538 | {
|
---|
539 | // Setup optional arguments to the default
|
---|
540 | wallPart = (wallPart || ["tower", "wallLong"]);
|
---|
541 | playerId = (playerId || 0);
|
---|
542 | if (!wallStyles.hasOwnProperty(style))
|
---|
543 | {
|
---|
544 | if (playerId == 0)
|
---|
545 | style = (style || "palisades");
|
---|
546 | else
|
---|
547 | style = (getCivCode(playerId-1));
|
---|
548 | }
|
---|
549 | endWithFirst = typeof endWithFirst == "undefined" ? true : endWithFirst;
|
---|
550 |
|
---|
551 | // Check arguments
|
---|
552 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
553 | {
|
---|
554 | var bending = wallStyles[style][wallPart[elementIndex]].bending;
|
---|
555 | if (bending != 0)
|
---|
556 | warn("Bending is not supported by placeLinearWall but a bending wall element is used: " + wallPart[elementIndex] + " -> wallStyles[style][wallPart[elementIndex]].entity");
|
---|
557 | }
|
---|
558 | // Setup number of wall parts
|
---|
559 | var totalLength = getDistance(startX, startY, targetX, targetY);
|
---|
560 | var wallPartLength = 0;
|
---|
561 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
562 | wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
|
---|
563 | var numParts = 0;
|
---|
564 | if (endWithFirst == true)
|
---|
565 | numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);
|
---|
566 | else
|
---|
567 | numParts = ceil(totalLength / wallPartLength);
|
---|
568 | // Setup scale factor
|
---|
569 | var scaleFactor = 1;
|
---|
570 | if (endWithFirst == true)
|
---|
571 | scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);
|
---|
572 | else
|
---|
573 | scaleFactor = totalLength / (numParts * wallPartLength);
|
---|
574 | // Setup angle
|
---|
575 | var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed...
|
---|
576 | var placeAngle = wallAngle - PI/2;
|
---|
577 | // Place wall entities
|
---|
578 | var x = startX;
|
---|
579 | var y = startY;
|
---|
580 | for (var partIndex = 0; partIndex < numParts; partIndex++)
|
---|
581 | {
|
---|
582 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
583 | {
|
---|
584 | var wallEle = wallStyles[style][wallPart[elementIndex]];
|
---|
585 | // Width correction
|
---|
586 | x += scaleFactor * wallEle.width/2 * cos(wallAngle);
|
---|
587 | y += scaleFactor * wallEle.width/2 * sin(wallAngle);
|
---|
588 | // Indent correction
|
---|
589 | var placeX = x - wallEle.indent * sin(wallAngle);
|
---|
590 | var placeY = y + wallEle.indent * cos(wallAngle);
|
---|
591 | // Placement
|
---|
592 | var entity = wallEle.entity;
|
---|
593 | if (entity !== undefined)
|
---|
594 | placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle);
|
---|
595 | x += scaleFactor * wallEle.width/2 * cos(wallAngle);
|
---|
596 | y += scaleFactor * wallEle.width/2 * sin(wallAngle);
|
---|
597 | }
|
---|
598 | }
|
---|
599 | if (endWithFirst == true)
|
---|
600 | {
|
---|
601 | var wallEle = wallStyles[style][wallPart[0]];
|
---|
602 | x += scaleFactor * wallEle.width/2 * cos(wallAngle);
|
---|
603 | y += scaleFactor * wallEle.width/2 * sin(wallAngle);
|
---|
604 | var entity = wallEle.entity;
|
---|
605 | if (entity !== undefined)
|
---|
606 | placeObject(x, y, entity, playerId, placeAngle + wallEle.angle);
|
---|
607 | }
|
---|
608 | }
|
---|
609 |
|
---|
610 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
611 | // placeCircularWall
|
---|
612 | //
|
---|
613 | // Place a circular wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius
|
---|
614 | // The wall can be opened forming more an arc than a circle if maxAngle < 2*PI
|
---|
615 | // The orientation then determines where this open part faces (0 means right like unrotated building's drop-points)
|
---|
616 | //
|
---|
617 | // centerX/Y Coordinates of the circle's center
|
---|
618 | // radius How wide the circle should be (approximate, especially if maxBendOff != 0)
|
---|
619 | // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"]
|
---|
620 | // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
|
---|
621 | // playerId Optional. Integer number of the player. Default is 0 (gaia)
|
---|
622 | // orientation Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0
|
---|
623 | // maxAngle Optional. How far the wall should circumvent the center. Default is 2*PI (full circle)
|
---|
624 | // 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
|
---|
625 | // maxBendOff Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle)
|
---|
626 | //
|
---|
627 | // NOTE: Don't use wall elements with bending like corners!
|
---|
628 | // TODO: Perhaps add eccentricity and maxBendOff functionality (untill now an unused argument)
|
---|
629 | // TODO: Perhaps add functionality for spirals
|
---|
630 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
631 | function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff)
|
---|
632 | {
|
---|
633 | // Setup optional arguments to the default
|
---|
634 | wallPart = (wallPart || ["tower", "wallLong"]);
|
---|
635 | playerId = (playerId || 0);
|
---|
636 | if (!wallStyles.hasOwnProperty(style))
|
---|
637 | {
|
---|
638 | if (playerId == 0)
|
---|
639 | style = (style || "palisades");
|
---|
640 | else
|
---|
641 | style = (getCivCode(playerId-1));
|
---|
642 | }
|
---|
643 | orientation = (orientation || 0);
|
---|
644 | maxAngle = (maxAngle || 2*PI);
|
---|
645 | if (endWithFirst === undefined)
|
---|
646 | {
|
---|
647 | if (maxAngle >= 2*PI - 0.001) // Can this be done better?
|
---|
648 | endWithFirst = false;
|
---|
649 | else
|
---|
650 | endWithFirst = true;
|
---|
651 | }
|
---|
652 | maxBendOff = (maxBendOff || 0);
|
---|
653 |
|
---|
654 | // Check arguments
|
---|
655 | if (maxBendOff > PI/2 || maxBendOff < 0)
|
---|
656 | warn("placeCircularWall maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff);
|
---|
657 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
658 | {
|
---|
659 | var bending = wallStyles[style][wallPart[elementIndex]].bending;
|
---|
660 | if (bending != 0)
|
---|
661 | warn("Bending is not supported by placeCircularWall but a bending wall element is used: " + wallPart[elementIndex]);
|
---|
662 | }
|
---|
663 | // Setup number of wall parts
|
---|
664 | var totalLength = maxAngle * radius;
|
---|
665 | var wallPartLength = 0;
|
---|
666 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
667 | wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
|
---|
668 | var numParts = 0;
|
---|
669 | if (endWithFirst == true)
|
---|
670 | {
|
---|
671 | numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);
|
---|
672 | }
|
---|
673 | else
|
---|
674 | {
|
---|
675 | numParts = ceil(totalLength / wallPartLength);
|
---|
676 | }
|
---|
677 | // Setup scale factor
|
---|
678 | var scaleFactor = 1;
|
---|
679 | if (endWithFirst == true)
|
---|
680 | scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);
|
---|
681 | else
|
---|
682 | scaleFactor = totalLength / (numParts * wallPartLength);
|
---|
683 | // Place wall entities
|
---|
684 | var actualAngle = orientation + (2*PI - maxAngle) / 2;
|
---|
685 | var x = centerX + radius*cos(actualAngle);
|
---|
686 | var y = centerY + radius*sin(actualAngle);
|
---|
687 | for (var partIndex = 0; partIndex < numParts; partIndex++)
|
---|
688 | {
|
---|
689 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
690 | {
|
---|
691 | var wallEle = wallStyles[style][wallPart[elementIndex]];
|
---|
692 | // Width correction
|
---|
693 | var addAngle = scaleFactor * wallEle.width / radius;
|
---|
694 | var targetX = centerX + radius * cos(actualAngle + addAngle);
|
---|
695 | var targetY = centerY + radius * sin(actualAngle + addAngle);
|
---|
696 | var placeX = x + (targetX - x)/2;
|
---|
697 | var placeY = y + (targetY - y)/2;
|
---|
698 | var placeAngle = actualAngle + addAngle/2;
|
---|
699 | // Indent correction
|
---|
700 | placeX -= wallEle.indent * cos(placeAngle);
|
---|
701 | placeY -= wallEle.indent * sin(placeAngle);
|
---|
702 | // Placement
|
---|
703 | var entity = wallEle.entity;
|
---|
704 | if (entity !== undefined)
|
---|
705 | placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle);
|
---|
706 | // Prepare for the next wall element
|
---|
707 | actualAngle += addAngle;
|
---|
708 | x = centerX + radius*cos(actualAngle);
|
---|
709 | y = centerY + radius*sin(actualAngle);
|
---|
710 | }
|
---|
711 | }
|
---|
712 | if (endWithFirst == true)
|
---|
713 | {
|
---|
714 | var wallEle = wallStyles[style][wallPart[0]];
|
---|
715 | var addAngle = scaleFactor * wallEle.width / radius;
|
---|
716 | var targetX = centerX + radius * cos(actualAngle + addAngle);
|
---|
717 | var targetY = centerY + radius * sin(actualAngle + addAngle);
|
---|
718 | var placeX = x + (targetX - x)/2;
|
---|
719 | var placeY = y + (targetY - y)/2;
|
---|
720 | var placeAngle = actualAngle + addAngle/2;
|
---|
721 | placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle);
|
---|
722 | }
|
---|
723 | }
|
---|
724 |
|
---|
725 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
726 | // placePolygonalWall
|
---|
727 | //
|
---|
728 | // Place a polygonal wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius
|
---|
729 | //
|
---|
730 | // centerX/Y Coordinates of the polygon's center
|
---|
731 | // radius How wide the circle should be in which the polygon fits
|
---|
732 | // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["wallLong", "tower"]
|
---|
733 | // cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower"
|
---|
734 | // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
|
---|
735 | // playerId Optional. Integer number of the player. Default is 0 (gaia)
|
---|
736 | // orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)
|
---|
737 | // numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory)
|
---|
738 | // skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true
|
---|
739 | //
|
---|
740 | // NOTE: Don't use wall elements with bending like corners!
|
---|
741 | // TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement
|
---|
742 | // TODO: Check some arguments
|
---|
743 | // TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0
|
---|
744 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
745 | function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall)
|
---|
746 | {
|
---|
747 | // Setup optional arguments to the default
|
---|
748 | wallPart = (wallPart || ["wallLong", "tower"]);
|
---|
749 | cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well...
|
---|
750 | playerId = (playerId || 0);
|
---|
751 | if (!wallStyles.hasOwnProperty(style))
|
---|
752 | {
|
---|
753 | if (playerId == 0)
|
---|
754 | style = (style || "palisades");
|
---|
755 | else
|
---|
756 | style = (getCivCode(playerId-1));
|
---|
757 | }
|
---|
758 | orientation = (orientation || 0);
|
---|
759 | numCorners = (numCorners || 8);
|
---|
760 | skipFirstWall = (skipFirstWall || true);
|
---|
761 |
|
---|
762 | // Setup angles
|
---|
763 | var angleAdd = 2*PI/numCorners;
|
---|
764 | var angleStart = orientation - angleAdd/2;
|
---|
765 | // Setup corners
|
---|
766 | var corners = [];
|
---|
767 | for (var i = 0; i < numCorners; i++)
|
---|
768 | corners.push([centerX + radius*cos(angleStart + i*angleAdd), centerY + radius*sin(angleStart + i*angleAdd)]);
|
---|
769 | // Place Corners and walls
|
---|
770 | for (var i = 0; i < numCorners; i++)
|
---|
771 | {
|
---|
772 | var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
|
---|
773 | placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);
|
---|
774 | if (!(skipFirstWall && i == 0))
|
---|
775 | {
|
---|
776 | placeLinearWall(
|
---|
777 | // Adjustment to the corner element width (approximately)
|
---|
778 | corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // startX
|
---|
779 | corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // startY
|
---|
780 | corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // targetX
|
---|
781 | corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // targetY
|
---|
782 | wallPart, style, playerId);
|
---|
783 | }
|
---|
784 | }
|
---|
785 | }
|
---|
786 |
|
---|
787 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
788 | // placeIrregularPolygonalWall
|
---|
789 | //
|
---|
790 | // Place an irregular polygonal wall of some wall parts to choose from around centerX/centerY with the given radius
|
---|
791 | //
|
---|
792 | // centerX/Y Coordinates of the polygon's center
|
---|
793 | // radius How wide the circle should be in which the polygon fits
|
---|
794 | // cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower"
|
---|
795 | // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
|
---|
796 | // playerId Optional. Integer number of the player. Default is 0 (gaia)
|
---|
797 | // orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)
|
---|
798 | // numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory)
|
---|
799 | // irregularity Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5
|
---|
800 | // skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true
|
---|
801 | // wallPartsAssortment Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^
|
---|
802 | //
|
---|
803 | // NOTE: wallPartsAssortment is put to the end because it's hardest to set
|
---|
804 | // NOTE: Don't use wall elements with bending like corners!
|
---|
805 | // TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement
|
---|
806 | // TODO: Check some arguments
|
---|
807 | // TODO: Perhaps add eccentricity
|
---|
808 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
809 | function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment)
|
---|
810 | {
|
---|
811 | // Setup optional arguments
|
---|
812 | playerId = (playerId || 0);
|
---|
813 | if (!wallStyles.hasOwnProperty(style))
|
---|
814 | {
|
---|
815 | if (playerId == 0)
|
---|
816 | style = (style || "palisades");
|
---|
817 | else
|
---|
818 | style = (getCivCode(playerId-1));
|
---|
819 | }
|
---|
820 |
|
---|
821 | // Generating a generic wall part assortment with each wall part including 1 gate lengthened by walls and towers
|
---|
822 | // NOTE: It might be a good idea to write an own function for that...
|
---|
823 | var defaultWallPartsAssortment = [["wallShort"], ["wall"], ["wallLong"], ["gate", "tower", "wallShort"]];
|
---|
824 | var centeredWallPart = ["gate"];
|
---|
825 | var extandingWallPartAssortment = [["tower", "wallLong"], ["tower", "wall"]];
|
---|
826 | defaultWallPartsAssortment.push(centeredWallPart);
|
---|
827 | for (var i = 0; i < extandingWallPartAssortment.length; i++)
|
---|
828 | {
|
---|
829 | var wallPart = centeredWallPart;
|
---|
830 | for (var j = 0; j < radius; j++)
|
---|
831 | {
|
---|
832 | if (j%2 == 0)
|
---|
833 | wallPart = wallPart.concat(extandingWallPartAssortment[i]);
|
---|
834 | else
|
---|
835 | {
|
---|
836 | extandingWallPartAssortment[i].reverse();
|
---|
837 | wallPart = extandingWallPartAssortment[i].concat(wallPart);
|
---|
838 | extandingWallPartAssortment[i].reverse();
|
---|
839 | }
|
---|
840 | defaultWallPartsAssortment.push(wallPart);
|
---|
841 | }
|
---|
842 | }
|
---|
843 | // Setup optional arguments to the default
|
---|
844 | wallPartsAssortment = (wallPartsAssortment || defaultWallPartsAssortment);
|
---|
845 | cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well...
|
---|
846 | style = (style || "palisades");
|
---|
847 | playerId = (playerId || 0);
|
---|
848 | orientation = (orientation || 0);
|
---|
849 | numCorners = (numCorners || randInt(5, 7));
|
---|
850 | irregularity = (irregularity || 0.5);
|
---|
851 | skipFirstWall = (skipFirstWall || false);
|
---|
852 | // Setup angles
|
---|
853 | var angleToCover = 2*PI;
|
---|
854 | var angleAddList = [];
|
---|
855 | for (var i = 0; i < numCorners; i++)
|
---|
856 | {
|
---|
857 | // Randomize covered angles. Variety scales down with raising angle though...
|
---|
858 | angleAddList.push(angleToCover/(numCorners-i) * (1 + randFloat(-irregularity, irregularity)));
|
---|
859 | angleToCover -= angleAddList[angleAddList.length - 1];
|
---|
860 | }
|
---|
861 | // Setup corners
|
---|
862 | var corners = [];
|
---|
863 | var angleActual = orientation - angleAddList[0]/2;
|
---|
864 | for (var i = 0; i < numCorners; i++)
|
---|
865 | {
|
---|
866 | corners.push([centerX + radius*cos(angleActual), centerY + radius*sin(angleActual)]);
|
---|
867 | if (i < numCorners - 1)
|
---|
868 | angleActual += angleAddList[i+1];
|
---|
869 | }
|
---|
870 | // Setup best wall parts for the different walls (a bit confusing naming...)
|
---|
871 | var wallPartLengths = [];
|
---|
872 | var maxWallPartLength = 0;
|
---|
873 | for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)
|
---|
874 | {
|
---|
875 | var length = wallPartLengths[partIndex];
|
---|
876 | wallPartLengths.push(getWallLength(wallPartsAssortment[partIndex], style));
|
---|
877 | if (length > maxWallPartLength)
|
---|
878 | maxWallPartLength = length;
|
---|
879 | }
|
---|
880 | var wallPartList = []; // This is the list of the wall parts to use for the walls between the corners, not to confuse with wallPartsAssortment!
|
---|
881 | for (var i = 0; i < numCorners; i++)
|
---|
882 | {
|
---|
883 | var bestWallPart = []; // This is a simpel wall part not a wallPartsAssortment!
|
---|
884 | var bestWallLength = 99999999;
|
---|
885 | // NOTE: This is not exactly like the length the wall will be in the end. Has to be tweaked...
|
---|
886 | var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]);
|
---|
887 | var numWallParts = ceil(wallLength/maxWallPartLength);
|
---|
888 | for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)
|
---|
889 | {
|
---|
890 | var linearWallLength = numWallParts*wallPartLengths[partIndex];
|
---|
891 | if (linearWallLength < bestWallLength && linearWallLength > wallLength)
|
---|
892 | {
|
---|
893 | bestWallPart = wallPartsAssortment[partIndex];
|
---|
894 | bestWallLength = linearWallLength;
|
---|
895 | }
|
---|
896 | }
|
---|
897 | wallPartList.push(bestWallPart);
|
---|
898 | }
|
---|
899 | // Place Corners and walls
|
---|
900 | for (var i = 0; i < numCorners; i++)
|
---|
901 | {
|
---|
902 | var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
|
---|
903 | placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);
|
---|
904 | if (!(skipFirstWall && i == 0))
|
---|
905 | {
|
---|
906 | placeLinearWall(
|
---|
907 | // Adjustment to the corner element width (approximately)
|
---|
908 | corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[i]/2), // startX
|
---|
909 | corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[i]/2), // startY
|
---|
910 | corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX
|
---|
911 | corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY
|
---|
912 | wallPartList[i], style, playerId, false);
|
---|
913 | }
|
---|
914 | }
|
---|
915 | }
|
---|
916 |
|
---|
917 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
918 | // placeGenericFortress
|
---|
919 | //
|
---|
920 | // Places a generic fortress with towers at the edges connected with long walls and gates (entries until gates work)
|
---|
921 | // This is the default Iberian civ bonus starting wall
|
---|
922 | //
|
---|
923 | // centerX/Y The approximate center coordinates of the fortress
|
---|
924 | // radius The approximate radius of the wall to be placed
|
---|
925 | // playerId Optional. Integer number of the player. Default is 0 (gaia)
|
---|
926 | // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia
|
---|
927 | // irregularity Optional. Float between 0 (circle) and 1 (very spiky), default is 1/2
|
---|
928 | // gateOccurence Optional. Integer number, every n-th walls will be a gate instead. Default is 3
|
---|
929 | // maxTrys Optional. How often the function tries to find a better fitting shape at max. Default is 100
|
---|
930 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
931 | function placeGenericFortress(centerX, centerY, radius, playerId, style, irregularity, gateOccurence, maxTrys)
|
---|
932 | {
|
---|
933 | // Setup optional arguments
|
---|
934 | radius = (radius || 20);
|
---|
935 | playerId = (playerId || 0);
|
---|
936 | if (!wallStyles.hasOwnProperty(style))
|
---|
937 | {
|
---|
938 | if (playerId == 0)
|
---|
939 | style = (style || "palisades");
|
---|
940 | else
|
---|
941 | style = (getCivCode(playerId-1));
|
---|
942 | }
|
---|
943 | irregularity = (irregularity || 1/2);
|
---|
944 | gateOccurence = (gateOccurence || 3);
|
---|
945 | maxTrys = (maxTrys || 100);
|
---|
946 |
|
---|
947 | // Setup some vars
|
---|
948 | var startAngle = randFloat(0, 2*PI);
|
---|
949 | var actualOffX = radius*cos(startAngle);
|
---|
950 | var actualOffY = radius*sin(startAngle);
|
---|
951 | var actualAngle = startAngle;
|
---|
952 | var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width;
|
---|
953 | // Searching for a well fitting point derivation
|
---|
954 | var tries = 0;
|
---|
955 | var bestPointDerivation = undefined;
|
---|
956 | var minOverlap = 1000;
|
---|
957 | var overlap = undefined;
|
---|
958 | while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10)
|
---|
959 | {
|
---|
960 | var pointDerivation = [];
|
---|
961 | var distanceToTarget = 1000;
|
---|
962 | var targetReached = false;
|
---|
963 | while (!targetReached)
|
---|
964 | {
|
---|
965 | var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance);
|
---|
966 | var tmpAngle = getAngle(actualOffX, actualOffY,
|
---|
967 | (radius + indent)*cos(actualAngle + (pointDistance / radius)),
|
---|
968 | (radius + indent)*sin(actualAngle + (pointDistance / radius)));
|
---|
969 | actualOffX += pointDistance*cos(tmpAngle);
|
---|
970 | actualOffY += pointDistance*sin(tmpAngle);
|
---|
971 | actualAngle = getAngle(0, 0, actualOffX, actualOffY);
|
---|
972 | pointDerivation.push([actualOffX, actualOffY]);
|
---|
973 | distanceToTarget = getDistance(actualOffX, actualOffY, pointDerivation[0][0], pointDerivation[0][1]);
|
---|
974 | var numPoints = pointDerivation.length;
|
---|
975 | if (numPoints > 3 && distanceToTarget < pointDistance) // Could be done better...
|
---|
976 | {
|
---|
977 | targetReached = true;
|
---|
978 | overlap = pointDistance - getDistance(pointDerivation[numPoints - 1][0], pointDerivation[numPoints - 1][1], pointDerivation[0][0], pointDerivation[0][1]);
|
---|
979 | if (overlap < minOverlap)
|
---|
980 | {
|
---|
981 | minOverlap = overlap;
|
---|
982 | bestPointDerivation = pointDerivation;
|
---|
983 | }
|
---|
984 | }
|
---|
985 | }
|
---|
986 | tries++;
|
---|
987 | }
|
---|
988 | log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries");
|
---|
989 | // Place wall
|
---|
990 | for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++)
|
---|
991 | {
|
---|
992 | var startX = centerX + bestPointDerivation[pointIndex][0];
|
---|
993 | var startY = centerY + bestPointDerivation[pointIndex][1];
|
---|
994 | var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0];
|
---|
995 | var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1];
|
---|
996 | var angle = getAngle(startX, startY, targetX, targetY);
|
---|
997 | var wallElement = "wallLong";
|
---|
998 | if ((pointIndex + 1) % gateOccurence == 0)
|
---|
999 | wallElement = "gate";
|
---|
1000 | var entity = wallStyles[style][wallElement].entity;
|
---|
1001 | if (entity)
|
---|
1002 | {
|
---|
1003 | placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX
|
---|
1004 | startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY
|
---|
1005 | entity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle);
|
---|
1006 | }
|
---|
1007 | // Place tower
|
---|
1008 | var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0];
|
---|
1009 | var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1];
|
---|
1010 | var angle = getAngle(startX, startY, targetX, targetY);
|
---|
1011 | placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style]["tower"].entity, playerId, angle - PI/2 + wallStyles[style]["tower"].angle);
|
---|
1012 | }
|
---|
1013 | }
|
---|