Line data Source code
1 0 : var g_Amounts = {
2 : "scarce": 0.2,
3 : "few": 0.5,
4 : "normal": 1,
5 : "many": 1.75,
6 : "tons": 3
7 : };
8 :
9 0 : var g_Mixes = {
10 : "same": 0,
11 : "similar": 0.1,
12 : "normal": 0.25,
13 : "varied": 0.5,
14 : "unique": 0.75
15 : };
16 :
17 0 : var g_Sizes = {
18 : "tiny": 0.5,
19 : "small": 0.75,
20 : "normal": 1,
21 : "big": 1.25,
22 : "huge": 1.5,
23 : };
24 :
25 0 : var g_AllAmounts = Object.keys(g_Amounts);
26 0 : var g_AllMixes = Object.keys(g_Mixes);
27 0 : var g_AllSizes = Object.keys(g_Sizes);
28 :
29 0 : var g_DefaultTileClasses = [
30 : "animals",
31 : "baseResource",
32 : "berries",
33 : "bluff",
34 : "bluffIgnore", // performance improvement
35 : "dirt",
36 : "fish",
37 : "food",
38 : "forest",
39 : "hill",
40 : "land",
41 : "map",
42 : "metal",
43 : "mountain",
44 : "plateau",
45 : "player",
46 : "prop",
47 : "ramp",
48 : "rock",
49 : "settlement",
50 : "spine",
51 : "valley",
52 : "water"
53 : ];
54 :
55 : var g_TileClasses;
56 :
57 0 : var g_PlayerbaseTypes = {
58 : "line": {
59 0 : "getPosition": (distance, groupedDistance, startAngle) => placeLine(getTeamsArray(), distance, groupedDistance, startAngle),
60 : "distance": fractionToTiles(randFloat(0.2, 0.35)),
61 : "groupedDistance": fractionToTiles(randFloat(0.08, 0.1)),
62 : "walls": false
63 : },
64 : "radial": {
65 0 : "getPosition": (distance, groupedDistance, startAngle) => playerPlacementCircle(distance, startAngle),
66 : "distance": fractionToTiles(randFloat(0.25, 0.35)),
67 : "groupedDistance": fractionToTiles(randFloat(0.08, 0.1)),
68 : "walls": true
69 : },
70 : "randomGroup": {
71 0 : "getPosition": (distance, groupedDistance, startAngle) => playerPlacementRandom(sortAllPlayers()) || playerPlacementCircle(distance, startAngle),
72 : "distance": fractionToTiles(randFloat(0.25, 0.35)),
73 : "groupedDistance": fractionToTiles(randFloat(0.08, 0.1)),
74 : "walls": true
75 : },
76 : "stronghold": {
77 0 : "getPosition": (distance, groupedDistance, startAngle) => placeStronghold(getTeamsArray(), distance, groupedDistance, startAngle),
78 : "distance": fractionToTiles(randFloat(0.2, 0.35)),
79 : "groupedDistance": fractionToTiles(randFloat(0.08, 0.1)),
80 : "walls": false
81 : }
82 : };
83 :
84 : /**
85 : * Adds an array of elements to the map.
86 : */
87 : function addElements(elements)
88 : {
89 0 : for (let element of elements)
90 0 : element.func(
91 : [
92 : avoidClasses.apply(null, element.avoid),
93 : stayClasses.apply(null, element.stay || null)
94 : ],
95 : pickSize(element.sizes),
96 : pickMix(element.mixes),
97 : pickAmount(element.amounts),
98 : element.baseHeight || 0);
99 : }
100 :
101 : /**
102 : * Converts "amount" terms to numbers.
103 : */
104 : function pickAmount(amounts)
105 : {
106 0 : let amount = pickRandom(amounts);
107 :
108 0 : if (amount in g_Amounts)
109 0 : return g_Amounts[amount];
110 :
111 0 : return g_Amounts.normal;
112 : }
113 :
114 : /**
115 : * Converts "mix" terms to numbers.
116 : */
117 : function pickMix(mixes)
118 : {
119 0 : let mix = pickRandom(mixes);
120 :
121 0 : if (mix in g_Mixes)
122 0 : return g_Mixes[mix];
123 :
124 0 : return g_Mixes.normal;
125 : }
126 :
127 : /**
128 : * Converts "size" terms to numbers.
129 : */
130 : function pickSize(sizes)
131 : {
132 0 : let size = pickRandom(sizes);
133 :
134 0 : if (size in g_Sizes)
135 0 : return g_Sizes[size];
136 :
137 0 : return g_Sizes.normal;
138 : }
139 :
140 : /**
141 : * Choose starting locations for all players.
142 : *
143 : * @param {string} type - "radial", "line", "stronghold", "randomGroup"
144 : * @param {number} distance - radial distance from the center of the map
145 : * @param {number} groupedDistance - space between players within a team
146 : * @param {number} startAngle - determined by the map that might want to place something between players
147 : * @returns {Array|undefined} - If successful, each element is an object that contains id, angle, x, z for each player
148 : */
149 : function createBasesByPattern(type, distance, groupedDistance, startAngle)
150 : {
151 0 : return createBases(...g_PlayerbaseTypes[type].getPosition(distance, groupedDistance, startAngle), g_PlayerbaseTypes[type].walls);
152 : }
153 :
154 : function createBases(playerIDs, playerPosition, walls)
155 : {
156 0 : g_Map.log("Creating bases");
157 :
158 0 : for (let i = 0; i < getNumPlayers(); ++i)
159 0 : createBase(playerIDs[i], playerPosition[i], walls);
160 :
161 0 : return [playerIDs, playerPosition];
162 : }
163 :
164 : /**
165 : * Create the base for a single player.
166 : *
167 : * @param {Object} player - contains id, angle, x, z
168 : * @param {boolean} walls - Whether or not iberian gets starting walls
169 : */
170 : function createBase(playerID, playerPosition, walls)
171 : {
172 0 : placePlayerBase({
173 : "playerID": playerID,
174 : "playerPosition": playerPosition,
175 : "PlayerTileClass": g_TileClasses.player,
176 : "BaseResourceClass": g_TileClasses.baseResource,
177 : "baseResourceConstraint": avoidClasses(g_TileClasses.water, 0, g_TileClasses.mountain, 0),
178 : "Walls": g_Map.getSize() > 192 && walls,
179 : "CityPatch": {
180 : "outerTerrain": g_Terrains.roadWild,
181 : "innerTerrain": g_Terrains.road,
182 : "painters": [
183 : new TileClassPainter(g_TileClasses.player)
184 : ]
185 : },
186 : "StartingAnimal": {
187 : "template": g_Gaia.startingAnimal
188 : },
189 : "Berries": {
190 : "template": g_Gaia.fruitBush
191 : },
192 : "Mines": {
193 : "types": [
194 : { "template": g_Gaia.metalLarge },
195 : { "template": g_Gaia.stoneLarge }
196 : ]
197 : },
198 : "Trees": {
199 : "template": g_Gaia.tree1,
200 : "count": currentBiome() == "generic/savanna" ? 5 : 15
201 : },
202 : "Decoratives": {
203 : "template": g_Decoratives.grassShort
204 : }
205 : });
206 : }
207 :
208 : /**
209 : * Return an array where each element is an array of playerIndices of a team.
210 : */
211 : function getTeamsArray()
212 : {
213 0 : var playerIDs = sortAllPlayers();
214 0 : var numPlayers = getNumPlayers();
215 :
216 : // Group players by team
217 0 : var teams = [];
218 0 : for (let i = 0; i < numPlayers; ++i)
219 : {
220 0 : let team = getPlayerTeam(playerIDs[i]);
221 0 : if (team == -1)
222 0 : continue;
223 :
224 0 : if (!teams[team])
225 0 : teams[team] = [];
226 :
227 0 : teams[team].push(playerIDs[i]);
228 : }
229 :
230 : // Players without a team get a custom index
231 0 : for (let i = 0; i < numPlayers; ++i)
232 0 : if (getPlayerTeam(playerIDs[i]) == -1)
233 0 : teams.push([playerIDs[i]]);
234 :
235 : // Remove unused indices
236 0 : return teams.filter(team => true);
237 : }
238 :
239 : /**
240 : * Place teams in a line-pattern.
241 : *
242 : * @param {Array} playerIDs - typically randomized indices of players of a single team
243 : * @param {number} distance - radial distance from the center of the map
244 : * @param {number} groupedDistance - distance between players
245 : * @param {number} startAngle - determined by the map that might want to place something between players.
246 : *
247 : * @returns {Array} - contains id, angle, x, z for every player
248 : */
249 : function placeLine(teamsArray, distance, groupedDistance, startAngle)
250 : {
251 0 : let playerIDs = [];
252 0 : let playerPosition = [];
253 :
254 0 : let mapCenter = g_Map.getCenter();
255 0 : let dist = fractionToTiles(0.45);
256 :
257 0 : for (let i = 0; i < teamsArray.length; ++i)
258 : {
259 0 : var safeDist = distance;
260 0 : if (distance + teamsArray[i].length * groupedDistance > dist)
261 0 : safeDist = dist - teamsArray[i].length * groupedDistance;
262 :
263 0 : var teamAngle = startAngle + (i + 1) * 2 * Math.PI / teamsArray.length;
264 :
265 0 : for (let p = 0; p < teamsArray[i].length; ++p)
266 : {
267 0 : playerIDs.push(teamsArray[i][p]);
268 0 : playerPosition.push(Vector2D.add(mapCenter, new Vector2D(safeDist + p * groupedDistance, 0).rotate(-teamAngle)).round());
269 : }
270 : }
271 :
272 0 : return [playerIDs, playerPosition];
273 : }
274 :
275 : /**
276 : * Place given players in a stronghold-pattern.
277 : *
278 : * @param teamsArray - each item is an array of playerIDs placed per stronghold
279 : * @param distance - radial distance from the center of the map
280 : * @param groupedDistance - distance between neighboring players
281 : * @param {number} startAngle - determined by the map that might want to place something between players
282 : */
283 : function placeStronghold(teamsArray, distance, groupedDistance, startAngle)
284 : {
285 0 : var mapCenter = g_Map.getCenter();
286 :
287 0 : let playerIDs = [];
288 0 : let playerPosition = [];
289 :
290 0 : for (let i = 0; i < teamsArray.length; ++i)
291 : {
292 0 : var teamAngle = startAngle + (i + 1) * 2 * Math.PI / teamsArray.length;
293 0 : var teamPosition = Vector2D.add(mapCenter, new Vector2D(distance, 0).rotate(-teamAngle));
294 0 : var teamGroupDistance = groupedDistance;
295 :
296 : // If we have a team of above average size, make sure they're spread out
297 0 : if (teamsArray[i].length > 4)
298 0 : teamGroupDistance = Math.max(fractionToTiles(0.08), groupedDistance);
299 :
300 : // If we have a solo player, place them on the center of the team's location
301 0 : if (teamsArray[i].length == 1)
302 0 : teamGroupDistance = fractionToTiles(0);
303 :
304 : // TODO: Ensure players are not placed outside of the map area, similar to placeLine
305 :
306 : // Create player base
307 0 : for (var p = 0; p < teamsArray[i].length; ++p)
308 : {
309 0 : var angle = startAngle + (p + 1) * 2 * Math.PI / teamsArray[i].length;
310 0 : playerIDs.push(teamsArray[i][p]);
311 0 : playerPosition.push(Vector2D.add(teamPosition, new Vector2D(teamGroupDistance, 0).rotate(-angle)).round());
312 : }
313 : }
314 :
315 0 : return [playerIDs, playerPosition];
316 : }
317 :
318 : /**
319 : * Creates tileClass for the default classes and every class given.
320 : *
321 : * @param {Array} newClasses
322 : * @returns {Object} - maps from classname to ID
323 : */
324 : function initTileClasses(newClasses)
325 : {
326 0 : var classNames = g_DefaultTileClasses;
327 :
328 0 : if (newClasses)
329 0 : classNames = classNames.concat(newClasses);
330 :
331 0 : g_TileClasses = {};
332 0 : for (var className of classNames)
333 0 : g_TileClasses[className] = g_Map.createTileClass();
334 : }
|