1 | ////////////////////////////////////////////////////////////////////
|
---|
2 | // This file contains functionality to place walls on random maps //
|
---|
3 | ////////////////////////////////////////////////////////////////////
|
---|
4 |
|
---|
5 | // To do:
|
---|
6 | // Check if placeGenericFortress always works without gaps for all races
|
---|
7 | // Rename wall elements to fit he entity names so that entity = 'structures/' + 'civ + '_' + wallElement.type in the common case
|
---|
8 | // Add roman army camp to style palisades and add upgraded default palisade fortress types matching civ default fortresses
|
---|
9 | // Add further wall elements cornerHalfIn, cornerHalfOut and adjust default fortress types to better fit in the octagonal territory of a civil center
|
---|
10 | // Add civil center, corral, farmstead, field, market, mill, temple
|
---|
11 | // Adjust default fortress types
|
---|
12 | // Add wall style 'roads'
|
---|
13 | // Add trsures to 'others'
|
---|
14 | // Adjust documentation
|
---|
15 | // ?Use available civ-type wall elements rather than palisades: Remove 'endLeft' and 'endRight' as default wall elements and adjust default palisade fortress types?
|
---|
16 | // ?Remove endRight, endLeft and adjust generic fortress types palisades?
|
---|
17 | // ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads?
|
---|
18 | // ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending?
|
---|
19 |
|
---|
20 |
|
---|
21 | ///////////////////////////////
|
---|
22 | // WallElement class definition
|
---|
23 | ///////////////////////////////
|
---|
24 |
|
---|
25 | // argument type: Descriptive string, example: 'wall'. NOTE: Not really needed. Mainly for custom wall elements and to get the wall element type in code.
|
---|
26 | // argument entity: Optional. Template string to be placed, example: 'structures/cart_wall'. Default is undefined (No entity placed)
|
---|
27 | // 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)
|
---|
28 | // 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
|
---|
29 | // argument indent: Optional. The indentation means its drawn inside (positive values) or pushed outwards (negative values). Default is 0
|
---|
30 | // NOTE: Bending is only used for fortresses and custom walls. Linear/circular walls walls use no/generic bending
|
---|
31 | // argument bending: Optional. How the direction of the wall is changed after this element, positive is bending 'in' (counter clockwise like entity placement)
|
---|
32 | function WallElement(type, entity, angle, width, indent, bending)
|
---|
33 | {
|
---|
34 | // NOTE: Not all wall elements have a symetry. So there's an direction 'outside' (towards right/positive X by default)
|
---|
35 | // In this sense 'left'/'right' means left/right of you when standing upon the wall and look 'outside'
|
---|
36 | // The wall is build towards 'left' so the next wall element will be placed left of the previous one (towards positive Y by default)
|
---|
37 | // In this sense the wall's direction is left meaning the 'bending' of a corner is used for the element following the corner
|
---|
38 | // With 'inside' and 'outside' defined as above, corners bend 'in'/'out' meaning placemant angle is increased/decreased (counter clockwise like object placement)
|
---|
39 | this.type = type;
|
---|
40 | // Wall element type documentation:
|
---|
41 | // Enlengthening straight blocking (mainly left/right symetric) wall elements (Walls and wall fortifications)
|
---|
42 | // 'wall': A blocking straight wall element that mainly lengthens the wall, self-explanatory
|
---|
43 | // 'wallShort': self-explanatory
|
---|
44 | // 'wallLong': self-explanatory
|
---|
45 | // 'tower': A blocking straight wall element with damage potential (but for palisades) that slightly lengthens the wall, exsample: wall tower, palisade tower(No attack)
|
---|
46 | // 'wallFort': A blocking straight wall element with massive damage potential that lengthens the wall, exsample: fortress, palisade fort
|
---|
47 | // Enlengthening straight non/custom blocking (mainly left/right symetric) wall elements (Gates and entrys)
|
---|
48 | // 'gate': A blocking straight wall element with passability determined by owner, example: gate (Functionality not yet implemented)
|
---|
49 | // 'entry': A non-blocking straight wall element (same width as gate) but without an actual template or just a flag/column/obelisk
|
---|
50 | // '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
|
---|
51 | // 'entryFort': A non-blocking straight wall element represented by a single (maybe indented) template, example: fortress, palisade fort
|
---|
52 | // Bending wall elements (Wall corners)
|
---|
53 | // 'cornerIn': A wall element bending the wall by PI/2 'inside' (left, +, see above), example: wall tower, palisade curve
|
---|
54 | // 'cornerOut': A wall element bending the wall by PI/2 'outside' (right, -, see above), example: wall tower, palisade curve
|
---|
55 | // 'cornerHalfIn': A wall element bending the wall by PI/4 'inside' (left, +, see above), example: wall tower, palisade curve. NOTE: Not yet implemented
|
---|
56 | // 'cornerHalfOut': A wall element bending the wall by PI/4 'outside' (right, -, see above), example: wall tower, palisade curve. NOTE: Not yet implemented
|
---|
57 | // Zero length straight indented (mainly left/right symetric) wall elements (Outposts/watchtowers and non-defensive base structures)
|
---|
58 | // 'outpost': A zero-length wall element without bending far indented so it stands outside the wall, exsample: outpost, defense tower, watchtower
|
---|
59 | // 'house': A zero-length wall element without bending far indented so it stands inside the wall that grants population bonus, exsample: house, hut, longhouse
|
---|
60 | // 'barracks': A zero-length wall element without bending far indented so it stands inside the wall that grants unit production, exsample: barracks, tavern, ...
|
---|
61 | this.entity = entity;
|
---|
62 | this.angle = (angle !== undefined) ? angle : 0*PI;
|
---|
63 | this.width = (width !== undefined) ? width : 0;
|
---|
64 | this.indent = (indent !== undefined) ? indent : 0;
|
---|
65 | this.bending = (bending !== undefined) ? bending : 0*PI;
|
---|
66 | }
|
---|
67 |
|
---|
68 |
|
---|
69 | ////////////////////////////
|
---|
70 | // Fortress class definition
|
---|
71 | ////////////////////////////
|
---|
72 |
|
---|
73 | // A list would do for symetric fortresses but if 'getCenter' don't do sufficient the center can be set manually
|
---|
74 | // argument type: Descriptive string, example: 'tiny'. Not really needed (WallTool.wallTypes['type string'] is used). Mainly for custom wall elements.
|
---|
75 | // argument wall: Optional. Array of wall element strings. Can be set afterwards. Default is an epty array.
|
---|
76 | // Example: ['entrance', 'wall', 'cornerIn', 'wall', 'gate', 'wall', 'entrance', 'wall', 'cornerIn', 'wall', 'gate', 'wall', 'cornerIn', 'wall']
|
---|
77 | // 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???)
|
---|
78 | // NOTE: The center will be recalculated when WallTool.setFortress is called. To avoid this set WallTool.calculateCenter to false.
|
---|
79 | function Fortress(type, wall, center)
|
---|
80 | {
|
---|
81 | this.type = type; // Only usefull to get the type of the actual fortress (by 'WallTool.fortress.type')
|
---|
82 | this.wall = (wall !== undefined) ? wall : [];
|
---|
83 | this.center = [0, 0]; // X/Z offset (in default orientation) from first wall element to center, perhaps should be the other way around...
|
---|
84 | }
|
---|
85 |
|
---|
86 |
|
---|
87 | ///////////////////////////////////////////////
|
---|
88 | // Setup data structure for default wall styles
|
---|
89 | ///////////////////////////////////////////////
|
---|
90 |
|
---|
91 | // A wall style is an associative array with all wall elements of that style in it associated with the wall element type string.
|
---|
92 | // 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'...
|
---|
93 | var wallStyles = {};
|
---|
94 |
|
---|
95 | // Generic civ dependent wall style definition. 'rome_siege' needs some tweek...
|
---|
96 | var wallScaleByType = {'athen' : 1.5, 'cart' : 1.8, 'celt' : 1.5, 'hele' : 1.5, 'iber' : 1.5, 'mace' : 1.5, 'pers' : 1.5, 'rome' : 1.5, 'spart' : 1.5, 'rome_siege' : 1.5};
|
---|
97 | for (var style in wallScaleByType)
|
---|
98 | {
|
---|
99 | var civ = style;
|
---|
100 | if (style == 'rome_siege')
|
---|
101 | civ = 'rome';
|
---|
102 | wallStyles[style] = {};
|
---|
103 | // Default wall elements
|
---|
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]);
|
---|
113 | // Gate and entrance wall elements
|
---|
114 | if (style == 'cart')
|
---|
115 | var gateWidth = 3.5*wallScaleByType[style];
|
---|
116 | else if (style == 'celt')
|
---|
117 | var gateWidth = 4*wallScaleByType[style];
|
---|
118 | // else if (style == 'iber')
|
---|
119 | // var gateWidth = 5.5*wallScaleByType[style];
|
---|
120 | else
|
---|
121 | var gateWidth = 6*wallScaleByType[style];
|
---|
122 | wallStyles[style]['gate'] = new WallElement('gate', 'structures/' + style + '_wall_gate', 0*PI, gateWidth);
|
---|
123 | wallStyles[style]['entry'] = new WallElement('entry', undefined, 0*PI, gateWidth);
|
---|
124 | wallStyles[style]['entryTower'] = new WallElement('entryTower', 'structures/' + civ + '_defense_tower', PI, gateWidth, -4*wallScaleByType[style]);
|
---|
125 | wallStyles[style]['entryFort'] = new WallElement('entryFort', 'structures/' + civ + '_fortress', 0*PI, 8*wallScaleByType[style], 6*wallScaleByType[style]);
|
---|
126 | // Defensive wall elements with 0 width outside the wall
|
---|
127 | wallStyles[style]['outpost'] = new WallElement('outpost', 'structures/' + civ + '_outpost', PI, 0, -4*wallScaleByType[style]);
|
---|
128 | wallStyles[style]['defenseTower'] = new WallElement('defenseTower', 'structures/' + civ + '_defenseTower', PI, 0, -4*wallScaleByType[style]);
|
---|
129 | // Base buildings wall elements with 0 width inside the wall
|
---|
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]);
|
---|
139 | // Generic space/gap wall elements
|
---|
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]);
|
---|
144 | }
|
---|
145 | // Add wall fortresses for all generic styles
|
---|
146 | wallStyles['athen']['wallFort'] = new WallElement('wallFort', 'structures/athen_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
147 | wallStyles['cart']['wallFort'] = new WallElement('wallFort', 'structures/cart_fortress', PI, 5.1, 1.6);
|
---|
148 | wallStyles['celt']['wallFort'] = new WallElement('wallFort', 'structures/celt_fortress_g', PI, 4.2, 1.5);
|
---|
149 | wallStyles['hele']['wallFort'] = new WallElement('wallFort', 'structures/hele_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
150 | wallStyles['iber']['wallFort'] = new WallElement('wallFort', 'structures/iber_fortress', PI, 5, 0.2);
|
---|
151 | wallStyles['mace']['wallFort'] = new WallElement('wallFort', 'structures/mace_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
152 | wallStyles['pers']['wallFort'] = new WallElement('wallFort', 'structures/pers_fortress', PI, 5.6/*5.5*/, 1.9/*1.7*/);
|
---|
153 | wallStyles['rome']['wallFort'] = new WallElement('wallFort', 'structures/rome_fortress', PI, 6.3, 2.1);
|
---|
154 | wallStyles['spart']['wallFort'] = new WallElement('wallFort', 'structures/spart_fortress', 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);
|
---|
155 | // Adjust 'rome_siege' style
|
---|
156 | wallStyles['rome_siege']['wallFort'] = new WallElement('wallFort', 'structures/rome_army_camp', PI, 7.2, 2);
|
---|
157 | wallStyles['rome_siege']['entryFort'] = new WallElement('entryFort', 'structures/rome_army_camp', PI, 12, 7);
|
---|
158 | wallStyles['rome_siege']['house'] = new WallElement('house', 'structures/rome_tent', PI, 0, 4);
|
---|
159 | // Add pseudo "theb" wall style (No actual entities available)
|
---|
160 | wallStyles["theb"] = deepcopy(wallStyles["hele"]);
|
---|
161 |
|
---|
162 | // Add special wall styles not well to implement generic (and to show how custom styles can be added)
|
---|
163 |
|
---|
164 | // Add special wall style 'palisades'
|
---|
165 | wallScaleByType['palisades'] = 0.55;
|
---|
166 | wallStyles['palisades'] = {};
|
---|
167 | wallStyles['palisades']['wall'] = new WallElement('wall', 'other/palisades_rocks_medium', 0*PI, 2.3);
|
---|
168 | wallStyles['palisades']['wallMedium'] = new WallElement('wall', 'other/palisades_rocks_medium', 0*PI, 2.3);
|
---|
169 | wallStyles['palisades']['wallLong'] = new WallElement('wall', 'other/palisades_rocks_long', 0*PI, 3.5);
|
---|
170 | wallStyles['palisades']['wallShort'] = new WallElement('wall', 'other/palisades_rocks_short', 0*PI, 1.2);
|
---|
171 | wallStyles['palisades']['tower'] = new WallElement('tower', 'other/palisades_rocks_tower', -PI/2, 0.7);
|
---|
172 | wallStyles['palisades']['wallFort'] = new WallElement('wallFort', 'other/palisades_rocks_fort', PI, 1.7);
|
---|
173 | wallStyles['palisades']['gate'] = new WallElement('gate', 'other/palisades_rocks_gate', PI, 3.6);
|
---|
174 | wallStyles['palisades']['entry'] = new WallElement('entry', undefined, wallStyles['palisades']['gate'].angle, wallStyles['palisades']['gate'].width);
|
---|
175 | wallStyles['palisades']['entryTower'] = new WallElement('entryTower', 'other/palisades_rocks_watchtower', 0*PI, wallStyles['palisades']['gate'].width, -3);
|
---|
176 | wallStyles['palisades']['entryFort'] = new WallElement('entryFort', 'other/palisades_rocks_fort', PI, 6, 3);
|
---|
177 | wallStyles['palisades']['cornerIn'] = new WallElement('cornerIn', 'other/palisades_rocks_curve', 3*PI/4, 2.1, 0.7, PI/2);
|
---|
178 | wallStyles['palisades']['cornerOut'] = new WallElement('cornerOut', 'other/palisades_rocks_curve', 5*PI/4, 2.1, -0.7, -PI/2);
|
---|
179 | wallStyles['palisades']['outpost'] = new WallElement('outpost', 'other/palisades_rocks_outpost', PI, 0, -2);
|
---|
180 | wallStyles['palisades']['house'] = new WallElement('house', 'other/celt_hut', PI, 0, 5);
|
---|
181 | wallStyles['palisades']['barracks'] = new WallElement('barracks', 'other/celt_tavern', PI, 0, 5);
|
---|
182 | wallStyles['palisades']['endRight'] = new WallElement('endRight', 'other/palisades_rocks_end', -PI/2, 0.2);
|
---|
183 | wallStyles['palisades']['endLeft'] = new WallElement('endLeft', 'other/palisades_rocks_end', PI/2, 0.2);
|
---|
184 |
|
---|
185 | // Add special wall style 'road'
|
---|
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);
|
---|
201 |
|
---|
202 | // Add special wall element collection 'other'
|
---|
203 | // NOTE: This is not a wall style in the common sense. Use with care!
|
---|
204 | wallStyles['other'] = {};
|
---|
205 | wallStyles['other']['fence'] = new WallElement('fence', 'other/fence_long', -PI/2, 3.1);
|
---|
206 | wallStyles['other']['fence_medium'] = new WallElement('fence', 'other/fence_long', -PI/2, 3.1);
|
---|
207 | wallStyles['other']['fence_short'] = new WallElement('fence_short', 'other/fence_short', -PI/2, 1.5);
|
---|
208 | wallStyles['other']['fence_stone'] = new WallElement('fence_stone', 'other/fence_stone', -PI/2, 2.5);
|
---|
209 | wallStyles['other']['palisade'] = new WallElement('palisade', 'other/palisades_rocks_short', 0, 1.2);
|
---|
210 | wallStyles['other']['column'] = new WallElement('column', 'other/column_doric', 0, 1);
|
---|
211 | wallStyles['other']['obelisk'] = new WallElement('obelisk', 'other/obelisk', 0, 2);
|
---|
212 | wallStyles['other']['spike'] = new WallElement('spike', 'other/palisades_angle_spike', -PI/2, 1);
|
---|
213 | wallStyles['other']['bench'] = new WallElement('bench', 'other/bench', PI/2, 1.5);
|
---|
214 | wallStyles['other']['benchForTable'] = new WallElement('benchForTable', 'other/bench', 0, 0.5);
|
---|
215 | wallStyles['other']['table'] = new WallElement('table', 'other/table_rectangle', 0, 1);
|
---|
216 | wallStyles['other']['table_square'] = new WallElement('table_square', 'other/table_square', PI/2, 1);
|
---|
217 | wallStyles['other']['flag'] = new WallElement('flag', 'special/rallypoint', PI, 1);
|
---|
218 | wallStyles['other']['standing_stone'] = new WallElement('standing_stone', 'gaia/special_ruins_standing_stone', PI, 1);
|
---|
219 | wallStyles['other']['settlement'] = new WallElement('settlement', 'gaia/special_settlement', PI, 6);
|
---|
220 | wallStyles['other']['gap'] = new WallElement('gap', undefined, 0, 2);
|
---|
221 | wallStyles['other']['gapSmall'] = new WallElement('gapSmall', undefined, 0, 1);
|
---|
222 | wallStyles['other']['gapLarge'] = new WallElement('gapLarge', undefined, 0, 4);
|
---|
223 | wallStyles['other']['cornerIn'] = new WallElement('cornerIn', undefined, 0, 0, 0, PI/2);
|
---|
224 | wallStyles['other']['cornerOut'] = new WallElement('cornerOut', undefined, 0, 0, 0, -PI/2);
|
---|
225 |
|
---|
226 |
|
---|
227 | ///////////////////////////////////////////////////////
|
---|
228 | // Setup data structure for some default fortress types
|
---|
229 | ///////////////////////////////////////////////////////
|
---|
230 |
|
---|
231 | // A fortress type is just an instance of the fortress class with actually something in it.
|
---|
232 | // 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'
|
---|
233 | var fortressTypes = {};
|
---|
234 | // Setup some default fortress types
|
---|
235 | // Add fortress type 'tiny'
|
---|
236 | fortressTypes['tiny'] = new Fortress('tiny');
|
---|
237 | var wallPart = ['entry', 'wall', 'cornerIn', 'wall'];
|
---|
238 | fortressTypes['tiny'].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
239 | // Add fortress type 'small'
|
---|
240 | fortressTypes['small'] = new Fortress('small');
|
---|
241 | var wallPart = ['entry', 'endLeft', 'wall', 'cornerIn', 'wall', 'endRight'];
|
---|
242 | fortressTypes['small'].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
243 | // Add fortress type 'medium'
|
---|
244 | fortressTypes['medium'] = new Fortress('medium');
|
---|
245 | var wallPart = ['entry', 'endLeft', 'wall', 'outpost', 'wall',
|
---|
246 | 'cornerIn', 'wall', 'outpost', 'wall', 'endRight'];
|
---|
247 | fortressTypes['medium'].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
248 | // Add fortress type 'normal'
|
---|
249 | fortressTypes['normal'] = new Fortress('normal');
|
---|
250 | var wallPart = ['entry', 'endLeft', 'wall', 'tower', 'wall',
|
---|
251 | 'cornerIn', 'wall', 'tower', 'wall', 'endRight'];
|
---|
252 | fortressTypes['normal'].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
253 | // Add fortress type 'large'
|
---|
254 | fortressTypes['large'] = new Fortress('large');
|
---|
255 | var wallPart = ['entry', 'endLeft', 'wall', 'outpost', 'wall', 'cornerIn', 'wall',
|
---|
256 | 'cornerOut', 'wall', 'cornerIn', 'wall', 'outpost', 'wall', 'endRight'];
|
---|
257 | fortressTypes['large'].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
258 | // Add fortress type 'veryLarge'
|
---|
259 | fortressTypes['veryLarge'] = new Fortress('veryLarge');
|
---|
260 | var wallPart = ['entry', 'endLeft', 'wall', 'tower', 'wall', 'cornerIn', 'wall',
|
---|
261 | 'cornerOut', 'wall', 'cornerIn', 'wall', 'tower', 'wall', 'endRight'];
|
---|
262 | fortressTypes['veryLarge'].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
263 | // Add fortress type 'giant'
|
---|
264 | fortressTypes['giant'] = new Fortress('giant');
|
---|
265 | var wallPart = ['entry', 'endLeft', 'wall', 'outpost', 'wall', 'cornerIn', 'wall', 'outpost', 'wall',
|
---|
266 | 'cornerOut', 'wall', 'outpost', 'wall', 'cornerIn', 'wall', 'outpost', 'wall', 'endRight'];
|
---|
267 | fortressTypes['giant'].wall = wallPart.concat(wallPart, wallPart, wallPart);
|
---|
268 |
|
---|
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 |
|
---|
286 | // Add (some) iberian civ bonus fortress (The civ can still be set, just an uncommon default fortress)
|
---|
287 | var wall = ['gate', 'tower', 'wall', 'cornerIn', 'wallLong', 'tower',
|
---|
288 | 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower',
|
---|
289 | 'gate', 'wall', 'cornerIn', 'wall', 'cornerOut', 'wall', 'cornerIn', 'wallLong', 'tower',
|
---|
290 | 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower', 'wall', 'cornerIn', 'wall'];
|
---|
291 | fortressTypes['iberCivBonus'] = new Fortress('iberCivBonus', wall);
|
---|
292 | var wall = ['gate', 'tower', 'wall', 'cornerIn', 'wall', 'cornerOut', 'wall', 'cornerIn', 'wallLong', 'tower',
|
---|
293 | 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower', 'wall', 'cornerIn', 'wall', 'cornerOut',
|
---|
294 | 'gate', 'tower', 'wall', 'cornerIn', 'wallLong', 'tower',
|
---|
295 | 'gate', 'tower', 'wallLong', 'cornerIn', 'wall', 'tower'];
|
---|
296 | fortressTypes['iberCivBonus2'] = new Fortress('iberCivBonus2', wall);
|
---|
297 | var wall = ['gate', 'tower', 'wall', 'cornerOut', 'wallShort', 'cornerIn', 'wall', 'cornerIn', 'wallLong', 'cornerIn', 'wallShort', 'cornerOut', 'wall', 'tower',
|
---|
298 | 'gate', 'tower', 'wallLong', 'cornerIn', 'wallLong', 'cornerIn', 'wallShort', 'cornerOut',
|
---|
299 | 'gate', 'tower', 'wall', 'cornerIn', 'wall', 'cornerOut', 'wallShort', 'cornerIn', 'wall', 'tower',
|
---|
300 | 'gate', 'tower', 'wallShort', 'cornerIn', 'wall', 'tower', 'wallShort', 'tower'];
|
---|
301 | fortressTypes['iberCivBonus3'] = new Fortress('iberCivBonus3', wall);
|
---|
302 |
|
---|
303 |
|
---|
304 | // Setup some semi default fortresses for 'palisades' style
|
---|
305 | var fortressTypeKeys = ['tiny', 'small', 'medium', 'normal', 'large', 'veryLarge', 'giant'];
|
---|
306 | for (var i = 0; i < fortressTypeKeys.length; i++)
|
---|
307 | {
|
---|
308 | var newKey = fortressTypeKeys[i] + 'Palisades';
|
---|
309 | var oldWall = fortressTypes[fortressTypeKeys[i]].wall;
|
---|
310 | fortressTypes[newKey] = new Fortress(newKey, []); // [] just to make sure it's an array though it's an array by default
|
---|
311 | var fillTowersBetween = ['wall', 'endLeft', 'endRight', 'cornerIn', 'cornerOut'];
|
---|
312 | for (var j = 0; j < oldWall.length; j++)
|
---|
313 | {
|
---|
314 | fortressTypes[newKey].wall.push(oldWall[j]); // Only works if the first element is an entry or gate (not in fillTowersBetween)
|
---|
315 | if (j+1 < oldWall.length)
|
---|
316 | if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means 'exists' here
|
---|
317 | fortressTypes[newKey].wall.push('tower');
|
---|
318 | }
|
---|
319 | }
|
---|
320 |
|
---|
321 |
|
---|
322 | ///////////////////////////////////////////////////////////////////////////////
|
---|
323 | // Define some helper functions: getWallAlignment, getWallCenter, getWallLength
|
---|
324 | ///////////////////////////////////////////////////////////////////////////////
|
---|
325 |
|
---|
326 | // Get alignment of a wall
|
---|
327 | // Returns a list of lists of most arguments needed to place the different wall elements for a given wall
|
---|
328 | // Placing the first wall element at startX/startY placed with angle given by orientation
|
---|
329 | // An alignement can be used to get the center of a 'wall' (more likely used for closed walls like fortresses) with the getWallCenter function
|
---|
330 | function getWallAlignment(startX, startY, wall, style, orientation)
|
---|
331 | {
|
---|
332 | orientation = (orientation || 0*PI);
|
---|
333 | var alignment = [];
|
---|
334 | var wallX = startX;
|
---|
335 | var wallY = startY;
|
---|
336 | for (var i = 0; i < wall.length; i++)
|
---|
337 | {
|
---|
338 | if (wallStyles[style][wall[i]] === undefined)
|
---|
339 | warn('No valid wall element: ' + wall[i]);
|
---|
340 | var element = wallStyles[style][wall[i]]
|
---|
341 | // Indentation
|
---|
342 | var placeX = wallX - element.indent * cos(orientation);
|
---|
343 | var placeY = wallY - element.indent * sin(orientation);
|
---|
344 | // Add element alignment
|
---|
345 | alignment.push([placeX, placeY, element.entity, orientation + element.angle]);
|
---|
346 | // Preset vars for the next wall element
|
---|
347 | if (i+1 < wall.length)
|
---|
348 | {
|
---|
349 | orientation += element.bending;
|
---|
350 | if (wallStyles[style][wall[i+1]] === undefined)
|
---|
351 | warn('No valid wall element: ' + wall[i+1]);
|
---|
352 | var nextElement = wallStyles[style][wall[i+1]];
|
---|
353 | var distance = (element.width + nextElement.width)/2;
|
---|
354 | // Corrections for elements with indent AND bending
|
---|
355 | if (element.bending !== 0 && element.indent !== 0)
|
---|
356 | {
|
---|
357 | // Indent correction to adjust distance
|
---|
358 | distance += element.indent*sin(element.bending);
|
---|
359 | // Indent correction to normalize indentation
|
---|
360 | wallX += element.indent * cos(orientation);
|
---|
361 | wallY += element.indent * sin(orientation);
|
---|
362 | }
|
---|
363 | // Set the next coordinates of the next element in the wall without indentation adjustment
|
---|
364 | wallX -= distance * sin(orientation);
|
---|
365 | wallY += distance * cos(orientation);
|
---|
366 | }
|
---|
367 | }
|
---|
368 | return alignment;
|
---|
369 | }
|
---|
370 |
|
---|
371 | // Get the center of a wall (mainly usefull for closed walls like fortresses)
|
---|
372 | // Center calculation works like getting the center of mass assuming all wall elements have the same 'waight'
|
---|
373 | // It returns the vector (array [x, y]) from the first wall element to the center
|
---|
374 | function getWallCenter(alignment)
|
---|
375 | {
|
---|
376 | var x = 0;
|
---|
377 | var y = 0;
|
---|
378 | for (var i = 0; i < alignment.length; i++)
|
---|
379 | {
|
---|
380 | x += alignment[i][0]/alignment.length;
|
---|
381 | y += alignment[i][1]/alignment.length;
|
---|
382 | }
|
---|
383 | var center = [x, y];
|
---|
384 | return center;
|
---|
385 | }
|
---|
386 |
|
---|
387 | // Get the length of a wall used by placeIrregularPolygonalWall
|
---|
388 | // NOTE: Does not support bending wall elements like corners!
|
---|
389 | function getWallLength(wall, style)
|
---|
390 | {
|
---|
391 | var length = 0;
|
---|
392 | for (var i = 0; i < wall.length; i++)
|
---|
393 | {
|
---|
394 | length += wallStyles[style][wall[i]].width;
|
---|
395 | }
|
---|
396 | return length;
|
---|
397 | }
|
---|
398 |
|
---|
399 |
|
---|
400 | /////////////////////////////////////////////
|
---|
401 | // Define the different wall placer functions
|
---|
402 | /////////////////////////////////////////////
|
---|
403 |
|
---|
404 | /////////////////////////////////////////////////////////////////////////////////
|
---|
405 | // Place simple wall starting with the first wall element placed at startX/startY
|
---|
406 | /////////////////////////////////////////////////////////////////////////////////
|
---|
407 | // orientation: 0 means 'outside' or 'front' of the wall is right (positive X) like placeObject
|
---|
408 | // It will then be build towards top (positive Y) if no bending wall elements like corners are used
|
---|
409 | // Raising orientation means the wall is rotated counter-clockwise like placeObject
|
---|
410 | function placeWall(startX, startY, wall, style, playerId, orientation)
|
---|
411 | {
|
---|
412 | var AM = getWallAlignment(startX, startY, wall, style, orientation);
|
---|
413 | for (var iWall = 0; iWall < wall.length; iWall++)
|
---|
414 | {
|
---|
415 | if (AM[iWall][2] !== undefined)
|
---|
416 | placeObject(AM[iWall][0], AM[iWall][1], AM[iWall][2], playerId, AM[iWall][3]);
|
---|
417 | }
|
---|
418 | }
|
---|
419 |
|
---|
420 | //////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
421 | // Place a fortress (mainly a closed wall build like placeWall) with the center at centerX/centerY
|
---|
422 | //////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
423 | // Should always start with the main entrance (like 'entry' or 'gate') to get the orientation right (like placeObject)
|
---|
424 | function placeCustomFortress(centerX, centerY, fortress, style, playerId, orientation, scipGetCenter)
|
---|
425 | {
|
---|
426 | if (!scipGetCenter)
|
---|
427 | {
|
---|
428 | var alignment = getWallAlignment(0, 0, fortress.wall, style);
|
---|
429 | var center = getWallCenter(alignment);
|
---|
430 | var startX = centerX - center[0] * cos(orientation) + center[1] * sin(orientation);
|
---|
431 | var startY = centerY - center[1] * cos(orientation) - center[0] * sin(orientation);
|
---|
432 | }
|
---|
433 | else
|
---|
434 | {
|
---|
435 | var startX = centerX + fortress.center[0];
|
---|
436 | var startY = centerY + fortress.center[1];
|
---|
437 | }
|
---|
438 | placeWall(startX, startY, fortress.wall, style, playerId, orientation)
|
---|
439 | }
|
---|
440 |
|
---|
441 | function placeFortress(centerX, centerY, type, style, playerId, orientation, scipGetCenter)
|
---|
442 | {
|
---|
443 | placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation, scipGetCenter);
|
---|
444 | }
|
---|
445 |
|
---|
446 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
447 | // Place a linear wall of repeatant wall elements given in the argument wallPart from startX/startY to targetX/targetY
|
---|
448 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
449 | // startX: x coordinate of the beginning of the wall
|
---|
450 | // startY: y coordinate of the beginning of the wall
|
---|
451 | // targetX: x coordinate of the ending of the wall
|
---|
452 | // targetY: y coordinate of the ending of the wall
|
---|
453 | // 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)
|
---|
454 | // wallPart: Optional. An array of wall element type strings (see WallElement.type). Default is ['wall']
|
---|
455 | // NOTE: Don't use wall elements with bending like corners!
|
---|
456 | // style: Optional. An wall style string (like defined in the 'wallStyles' dictionary). Default is 'palisades'
|
---|
457 | // 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)
|
---|
458 | // endWithFirst: Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true
|
---|
459 | // TODO: Maybe add angle offset for more generic looking?
|
---|
460 | function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId, endWithFirst)
|
---|
461 | {
|
---|
462 | // Setup optional arguments to the default
|
---|
463 | wallPart = (wallPart || ['wall']);
|
---|
464 | style = (style || 'palisades');
|
---|
465 | playerId = (playerId || 0);
|
---|
466 | // endWithFirst = (endWithFirst || true);
|
---|
467 | endWithFirst = typeof endWithFirst == 'undefined' ? true : endWithFirst;
|
---|
468 | // Check arguments
|
---|
469 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
470 | if (wallStyles[style][wallPart[elementIndex]].bending != 0)
|
---|
471 | warn("Bending is not supported by placeLinearWall but a bending wall element is used: " + wallPart[elementIndex] + " -> wallStyles[style][wallPart[elementIndex]].entity");
|
---|
472 | // Setup number of wall parts
|
---|
473 | var totalLength = getDistance(startX, startY, targetX, targetY);
|
---|
474 | var wallPartLength = 0;
|
---|
475 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
476 | wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
|
---|
477 | var numParts = 0;
|
---|
478 | if (endWithFirst == true)
|
---|
479 | numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength)
|
---|
480 | else
|
---|
481 | numParts = ceil(totalLength / wallPartLength);
|
---|
482 | // Setup scale factor
|
---|
483 | var scaleFactor = 1;
|
---|
484 | if (endWithFirst == true)
|
---|
485 | scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width)
|
---|
486 | else
|
---|
487 | scaleFactor = totalLength / (numParts * wallPartLength);
|
---|
488 | // Setup angle
|
---|
489 | var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function 'getAngle()' is about to be changed...
|
---|
490 | var placeAngle = wallAngle - PI/2;
|
---|
491 | // Place wall entities
|
---|
492 | var x = startX;
|
---|
493 | var y = startY;
|
---|
494 | for (var partIndex = 0; partIndex < numParts; partIndex++)
|
---|
495 | {
|
---|
496 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
497 | {
|
---|
498 | var wallEle = wallStyles[style][wallPart[elementIndex]];
|
---|
499 | // Width correction
|
---|
500 | x += scaleFactor * wallEle.width/2 * cos(wallAngle);
|
---|
501 | y += scaleFactor * wallEle.width/2 * sin(wallAngle);
|
---|
502 | // Indent correction
|
---|
503 | var placeX = x - wallEle.indent * sin(wallAngle);
|
---|
504 | var placeY = y + wallEle.indent * cos(wallAngle);
|
---|
505 | // Placement
|
---|
506 | if (wallEle.entity !== undefined)
|
---|
507 | placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle);
|
---|
508 | x += scaleFactor * wallEle.width/2 * cos(wallAngle);
|
---|
509 | y += scaleFactor * wallEle.width/2 * sin(wallAngle);
|
---|
510 | }
|
---|
511 | }
|
---|
512 | if (endWithFirst == true)
|
---|
513 | {
|
---|
514 | var wallEle = wallStyles[style][wallPart[0]];
|
---|
515 | x += scaleFactor * wallEle.width/2 * cos(wallAngle);
|
---|
516 | y += scaleFactor * wallEle.width/2 * sin(wallAngle);
|
---|
517 | if (wallEle.entity !== undefined)
|
---|
518 | placeObject(x, y, wallEle.entity, playerId, placeAngle + wallEle.angle);
|
---|
519 | }
|
---|
520 | }
|
---|
521 |
|
---|
522 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
523 | // Place a circular wall of repeatant wall elements given in the argument wallPart arround centerX/centerY with the given radius
|
---|
524 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
525 | // The wall is not necessarily closed depending on the optional argument maxAngle (better name?)
|
---|
526 | // NOTE: Don't use wall elements with bending like corners!
|
---|
527 | // TODO: Add eccentricity and maxBendOff functionality (untill now an unused argument)
|
---|
528 | function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff)
|
---|
529 | {
|
---|
530 | // Setup optional arguments to the default
|
---|
531 | wallPart = (wallPart || ['wall']);
|
---|
532 | style = (style || 'palisades');
|
---|
533 | playerId = (playerId || 0);
|
---|
534 | orientation = (orientation || 0);
|
---|
535 | maxAngle = (maxAngle || 2*PI);
|
---|
536 | if (endWithFirst === undefined)
|
---|
537 | {
|
---|
538 | if (maxAngle >= 2*PI - 0.001) // Can this be done better?
|
---|
539 | {
|
---|
540 | endWithFirst = false;
|
---|
541 | }
|
---|
542 | else
|
---|
543 | {
|
---|
544 | endWithFirst = true;
|
---|
545 | }
|
---|
546 | }
|
---|
547 | maxBendOff = (maxBendOff || 0);
|
---|
548 | // Check arguments
|
---|
549 | if (maxBendOff > PI/2 || maxBendOff < 0)
|
---|
550 | warn('placeCircularWall maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: ' + maxBendOff);
|
---|
551 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
552 | if (wallStyles[style][wallPart[elementIndex]].bending != 0)
|
---|
553 | warn("Bending is not supported by placeCircularWall but a bending wall element is used: " + wallPart[elementIndex]);
|
---|
554 | // Setup number of wall parts
|
---|
555 | var totalLength = maxAngle * radius;
|
---|
556 | var wallPartLength = 0;
|
---|
557 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
558 | wallPartLength += wallStyles[style][wallPart[elementIndex]].width;
|
---|
559 | var numParts = 0;
|
---|
560 | if (endWithFirst == true)
|
---|
561 | {
|
---|
562 | numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);
|
---|
563 | }
|
---|
564 | else
|
---|
565 | {
|
---|
566 | numParts = ceil(totalLength / wallPartLength);
|
---|
567 | }
|
---|
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 | // Place wall entities
|
---|
575 | var actualAngle = orientation + (2*PI - maxAngle) / 2;
|
---|
576 | var x = centerX + radius*cos(actualAngle);
|
---|
577 | var y = centerY + radius*sin(actualAngle);
|
---|
578 | for (var partIndex = 0; partIndex < numParts; partIndex++)
|
---|
579 | {
|
---|
580 | for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)
|
---|
581 | {
|
---|
582 | var wallEle = wallStyles[style][wallPart[elementIndex]];
|
---|
583 | // Width correction
|
---|
584 | var addAngle = scaleFactor * wallEle.width / radius;
|
---|
585 | var targetX = centerX + radius * cos(actualAngle + addAngle);
|
---|
586 | var targetY = centerY + radius * sin(actualAngle + addAngle);
|
---|
587 | var placeX = x + (targetX - x)/2;
|
---|
588 | var placeY = y + (targetY - y)/2;
|
---|
589 | var placeAngle = actualAngle + addAngle/2;
|
---|
590 | // Indent correction
|
---|
591 | placeX -= wallEle.indent * cos(placeAngle);
|
---|
592 | placeY -= wallEle.indent * sin(placeAngle);
|
---|
593 | // Placement
|
---|
594 | if (wallEle.entity !== undefined)
|
---|
595 | placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle);
|
---|
596 | // Prepare for the next wall element
|
---|
597 | actualAngle += addAngle;
|
---|
598 | x = centerX + radius*cos(actualAngle);
|
---|
599 | y = centerY + radius*sin(actualAngle);
|
---|
600 | }
|
---|
601 | }
|
---|
602 | if (endWithFirst == true)
|
---|
603 | {
|
---|
604 | var wallEle = wallStyles[style][wallPart[0]];
|
---|
605 | var addAngle = scaleFactor * wallEle.width / radius;
|
---|
606 | var targetX = centerX + radius * cos(actualAngle + addAngle);
|
---|
607 | var targetY = centerY + radius * sin(actualAngle + addAngle);
|
---|
608 | var placeX = x + (targetX - x)/2;
|
---|
609 | var placeY = y + (targetY - y)/2;
|
---|
610 | var placeAngle = actualAngle + addAngle/2;
|
---|
611 | placeObject(placeX, placeY, wallEle.entity, playerId, placeAngle + wallEle.angle);
|
---|
612 | }
|
---|
613 | }
|
---|
614 |
|
---|
615 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
616 | // Place a polygonal wall of repeatant wall elements given in the argument wallPart arround centerX/centerY with the given radius
|
---|
617 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
618 | // NOTE: Don't use wall elements with bending like corners!
|
---|
619 | // TODO: Check some arguments
|
---|
620 | // TODO: Add eccentricity and perhaps make it call placeIrregularPolygonalWall with irregularity = 0
|
---|
621 | function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId, orientation, numCorners, skipFirstWall)
|
---|
622 | {
|
---|
623 | // Setup optional arguments to the default
|
---|
624 | wallPart = (wallPart || ['wall']);
|
---|
625 | cornerWallElement = (cornerWallElement || 'tower'); // Don't use wide elements for this. Not supported well...
|
---|
626 | style = (style || 'palisades');
|
---|
627 | playerId = (playerId || 0);
|
---|
628 | orientation = (orientation || 0);
|
---|
629 | numCorners = (numCorners || 8);
|
---|
630 | skipFirstWall = (skipFirstWall || false);
|
---|
631 | // Setup angles
|
---|
632 | var angleAdd = 2*PI/numCorners;
|
---|
633 | var angleStart = orientation - angleAdd/2;
|
---|
634 | // Setup corners
|
---|
635 | var corners = [];
|
---|
636 | for (var i = 0; i < numCorners; i++)
|
---|
637 | corners.push([centerX + radius*cos(angleStart + i*angleAdd), centerY + radius*sin(angleStart + i*angleAdd)]);
|
---|
638 | // Place Corners and walls
|
---|
639 | for (var i = 0; i < numCorners; i++)
|
---|
640 | {
|
---|
641 | var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
|
---|
642 | placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);
|
---|
643 | if (!(skipFirstWall && i == 0))
|
---|
644 | {
|
---|
645 | placeLinearWall(
|
---|
646 | // Adjustment to the corner element width (approximately)
|
---|
647 | corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // startX
|
---|
648 | corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // startY
|
---|
649 | corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // targetX
|
---|
650 | corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // targetY
|
---|
651 | wallPart, style, playerId);
|
---|
652 | }
|
---|
653 | }
|
---|
654 | }
|
---|
655 |
|
---|
656 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
657 | // Place an irregular polygonal wall of some wall parts to choose from arround centerX/centerY with the given radius
|
---|
658 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
659 | // NOTE: wallPartList is put to the end because it's hardest to set
|
---|
660 | // NOTE: Don't use wall elements with bending like corners!
|
---|
661 | // TODO: Check some arguments
|
---|
662 | // TODO: Add eccentricity
|
---|
663 | function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment)
|
---|
664 | {
|
---|
665 | // Generating a generic wall part assortment with each wall part including 1 gate enlengthend by walls and towers
|
---|
666 | // NOTE: It might be a good idea to write an own function for that...
|
---|
667 | var defaultWallPartsAssortment = [['wallShort'], ['wall'], ['wallLong'], ['gate', 'tower', 'wallShort']];
|
---|
668 | var centeredWallPart = ['gate']; // NOTE: Since gates are not functional yet entrys are used instead...
|
---|
669 | var extandingWallPartAssortment = [['tower', 'wallLong'], ['tower', 'wall']];
|
---|
670 | defaultWallPartsAssortment.push(centeredWallPart)
|
---|
671 | for (var i = 0; i < extandingWallPartAssortment.length; i++)
|
---|
672 | {
|
---|
673 | var wallPart = centeredWallPart;
|
---|
674 | for (var j = 0; j < radius; j++)
|
---|
675 | {
|
---|
676 | if (j%2 == 0)
|
---|
677 | wallPart = wallPart.concat(extandingWallPartAssortment[i]);
|
---|
678 | else
|
---|
679 | {
|
---|
680 | extandingWallPartAssortment[i].reverse();
|
---|
681 | wallPart = extandingWallPartAssortment[i].concat(wallPart);
|
---|
682 | extandingWallPartAssortment[i].reverse();
|
---|
683 | }
|
---|
684 | defaultWallPartsAssortment.push(wallPart);
|
---|
685 | }
|
---|
686 | }
|
---|
687 | // Setup optional arguments to the default
|
---|
688 | wallPartsAssortment = (wallPartsAssortment || defaultWallPartsAssortment);
|
---|
689 | cornerWallElement = (cornerWallElement || 'tower'); // Don't use wide elements for this. Not supported well...
|
---|
690 | style = (style || 'palisades');
|
---|
691 | playerId = (playerId || 0);
|
---|
692 | orientation = (orientation || 0);
|
---|
693 | numCorners = (numCorners || randInt(5, 7));
|
---|
694 | irregularity = (irregularity || 0.5);
|
---|
695 | skipFirstWall = (skipFirstWall || false);
|
---|
696 | // Setup angles
|
---|
697 | var angleToCover = 2*PI;
|
---|
698 | var angleAddList = [];
|
---|
699 | for (var i = 0; i < numCorners; i++)
|
---|
700 | {
|
---|
701 | // Randomize covered angles. Variety scales down with raising angle though...
|
---|
702 | angleAddList.push(angleToCover/(numCorners-i) * (1 + randFloat(-irregularity, irregularity)));
|
---|
703 | angleToCover -= angleAddList[angleAddList.length - 1];
|
---|
704 | }
|
---|
705 | // Setup corners
|
---|
706 | var corners = [];
|
---|
707 | var angleActual = orientation - angleAddList[0]/2;
|
---|
708 | for (var i = 0; i < numCorners; i++)
|
---|
709 | {
|
---|
710 | corners.push([centerX + radius*cos(angleActual), centerY + radius*sin(angleActual)]);
|
---|
711 | if (i < numCorners - 1)
|
---|
712 | angleActual += angleAddList[i+1]
|
---|
713 | }
|
---|
714 | // Setup best wall parts for the different walls (a bit confusing naming...)
|
---|
715 | var wallPartLengths = [];
|
---|
716 | var maxWallPartLength = 0;
|
---|
717 | for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)
|
---|
718 | {
|
---|
719 | wallPartLengths.push(getWallLength(wallPartsAssortment[partIndex], style));
|
---|
720 | if (wallPartLengths[partIndex] > maxWallPartLength)
|
---|
721 | maxWallPartLength = wallPartLengths[partIndex];
|
---|
722 | }
|
---|
723 | var wallPartList = []; // This is the list of the wall parts to use for the walls between the corners, not to confuse with wallPartsAssortment!
|
---|
724 | for (var i = 0; i < numCorners; i++)
|
---|
725 | {
|
---|
726 | var bestWallPart = []; // This is a simpel wall part not a wallPartsAssortment!
|
---|
727 | var bestWallLength = 99999999;
|
---|
728 | // NOTE: This is not exsactly like the length the wall will be in the end. Has to be tweeked...
|
---|
729 | var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1])
|
---|
730 | var numWallParts = ceil(wallLength/maxWallPartLength);
|
---|
731 | for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)
|
---|
732 | {
|
---|
733 | if (numWallParts*wallPartLengths[partIndex] < bestWallLength && numWallParts*wallPartLengths[partIndex] > wallLength)
|
---|
734 | {
|
---|
735 | bestWallPart = wallPartsAssortment[partIndex];
|
---|
736 | bestWallLength = numWallParts*wallPartLengths[partIndex];
|
---|
737 | }
|
---|
738 | }
|
---|
739 | wallPartList.push(bestWallPart)
|
---|
740 | }
|
---|
741 | // Place Corners and walls
|
---|
742 | for (var i = 0; i < numCorners; i++)
|
---|
743 | {
|
---|
744 | var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
|
---|
745 | placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);
|
---|
746 | if (!(skipFirstWall && i == 0))
|
---|
747 | {
|
---|
748 | placeLinearWall(
|
---|
749 | // Adjustment to the corner element width (approximately)
|
---|
750 | corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[i]/2), // startX
|
---|
751 | corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[i]/2), // startY
|
---|
752 | corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX
|
---|
753 | corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY
|
---|
754 | wallPartList[i], style, playerId, false);
|
---|
755 | }
|
---|
756 | }
|
---|
757 | }
|
---|
758 |
|
---|
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 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
---|
852 | // radius: A float seting the aproximate radius of the fortress
|
---|
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)
|
---|
858 | {
|
---|
859 | // Setup optional arguments to the default
|
---|
860 | if (wallPart === undefined)
|
---|
861 | wallPart = ['tower', 'wall', 'tower', 'entry', 'tower', 'wall'];
|
---|
862 | if (maxBendOff === undefined)
|
---|
863 | maxBendOff = 0;
|
---|
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
|
---|
872 | var x = radius;
|
---|
873 | var y = 0;
|
---|
874 | var angle = 0;
|
---|
875 | var targetX = radius;
|
---|
876 | var targetY = 0;
|
---|
877 | var targetReached = false;
|
---|
878 | var eleIndex = 0;
|
---|
879 | // Start the evil while loope ^^
|
---|
880 | while (targetReached == false)
|
---|
881 | {
|
---|
882 | var wallElement = wallStyles[style][wallPart[eleIndex % wallPart.length]];
|
---|
883 | var eleWidth = wallElement.width; // Reducing this a bit to avoid gaps might be good
|
---|
884 | // Stabalized bendOff. TODO: Ensure positive eleAngleWidth!!!
|
---|
885 | var actualRadius = getDistance(centerX, centerY, centerX + x, centerY + y);
|
---|
886 | var bendOff = randFloat(-maxBendOff*radius/actualRadius, maxBendOff*actualRadius/radius);
|
---|
887 | // Element width in radians
|
---|
888 | var eleAngleWidth = eleWidth*cos(bendOff) / radius; // A/L = da/dl -> da = A * dl / L -> da = 2*PI * eleWidth / (2*PI * radius) -> da = eleWidth/radius
|
---|
889 | var eleAngle = angle + eleAngleWidth/2 + bendOff;
|
---|
890 | var placeX = x - eleWidth/2 * sin(eleAngle);
|
---|
891 | var placeY = y + eleWidth/2 * cos(eleAngle);
|
---|
892 | if (wallElement.entity)
|
---|
893 | placeObject(centerX + placeX, centerY + placeY, wallElement.entity, playerId, eleAngle + wallElement.angle);
|
---|
894 | x = placeX - eleWidth/2 * sin(eleAngle);
|
---|
895 | y = placeY + eleWidth/2 * cos(eleAngle);
|
---|
896 | angle += eleAngleWidth;
|
---|
897 | if (eleIndex % wallPart.length == 0 && eleIndex > wallPart.length && (getDistance(x, y, targetX, targetY) < wallPartLength || angle > 2*PI))
|
---|
898 | targetReached = true;
|
---|
899 | eleIndex++;
|
---|
900 | }
|
---|
901 | // Close wall with simple linear wall
|
---|
902 | if (getDistance(centerX + x, centerY + y, centerX + targetX, centerY + targetY) > wallStyles[style]['wallLong'].width)
|
---|
903 | placeLinearWall(centerX + x, centerY + y, centerX + targetX, centerY + targetY, ['wall', 'tower'], style, playerId, true);
|
---|
904 | }
|
---|