1 | var startTime = dateNow();
|
---|
2 |
|
---|
3 | function log(msg)
|
---|
4 | {
|
---|
5 | println(msg);
|
---|
6 | }
|
---|
7 |
|
---|
8 | function error(msg)
|
---|
9 | {
|
---|
10 | println("Error: "+msg);
|
---|
11 | }
|
---|
12 |
|
---|
13 | function warning(msg)
|
---|
14 | {
|
---|
15 | println("Warning: "+msg);
|
---|
16 | }
|
---|
17 |
|
---|
18 | function Area(points)
|
---|
19 | {
|
---|
20 | this.points = (points !== undefined ? points : []);
|
---|
21 | }
|
---|
22 |
|
---|
23 | ///////////////////////////////////////////////////////////////////////////
|
---|
24 | // NullConstraints: No constraint - always return true
|
---|
25 | ///////////////////////////////////////////////////////////////////////////
|
---|
26 | function NullConstraint() {}
|
---|
27 |
|
---|
28 | NullConstraint.prototype.allows = function(x, y)
|
---|
29 | {
|
---|
30 | return true;
|
---|
31 | };
|
---|
32 |
|
---|
33 | ///////////////////////////////////////////////////////////////////////////
|
---|
34 | // AndConstraints: Check multiple constraints
|
---|
35 | ///////////////////////////////////////////////////////////////////////////
|
---|
36 | function AndConstraint(constraints)
|
---|
37 | {
|
---|
38 | this.constraints = constraints;
|
---|
39 | }
|
---|
40 |
|
---|
41 | AndConstraint.prototype.allows = function(x, y)
|
---|
42 | {
|
---|
43 | for (var i=0; i < this.constraints.length; ++i)
|
---|
44 | {
|
---|
45 | if (!this.constraints[i].allows(x, y))
|
---|
46 | return false;
|
---|
47 | }
|
---|
48 |
|
---|
49 | return true;
|
---|
50 | };
|
---|
51 |
|
---|
52 | ///////////////////////////////////////////////////////////////////////////
|
---|
53 | // AvoidAreaConstraint
|
---|
54 | ///////////////////////////////////////////////////////////////////////////
|
---|
55 | function AvoidAreaConstraint(area)
|
---|
56 | {
|
---|
57 | this.area = area;
|
---|
58 | }
|
---|
59 |
|
---|
60 | AvoidAreaConstraint.prototype.allows = function(x, y)
|
---|
61 | {
|
---|
62 | return g_Map.area[x][y] != this.area;
|
---|
63 | };
|
---|
64 |
|
---|
65 | ///////////////////////////////////////////////////////////////////////////
|
---|
66 | // AvoidTextureConstraint
|
---|
67 | ///////////////////////////////////////////////////////////////////////////
|
---|
68 | function AvoidTextureConstraint(textureID)
|
---|
69 | {
|
---|
70 | this.textureID = textureID;
|
---|
71 | }
|
---|
72 |
|
---|
73 | AvoidTextureConstraint.prototype.allows = function(x, y)
|
---|
74 | {
|
---|
75 | return g_Map.texture[x][y] != this.textureID;
|
---|
76 | };
|
---|
77 |
|
---|
78 | ///////////////////////////////////////////////////////////////////////////
|
---|
79 | // AvoidTileClassConstraint
|
---|
80 | ///////////////////////////////////////////////////////////////////////////
|
---|
81 | function AvoidTileClassConstraint(tileClassID, distance)
|
---|
82 | {
|
---|
83 | this.tileClass = getTileClass(tileClassID);
|
---|
84 | this.distance = distance;
|
---|
85 | }
|
---|
86 |
|
---|
87 | AvoidTileClassConstraint.prototype.allows = function(x, y)
|
---|
88 | {
|
---|
89 | return this.tileClass.countMembersInRadius(x, y, this.distance) == 0;
|
---|
90 | };
|
---|
91 |
|
---|
92 | ///////////////////////////////////////////////////////////////////////////
|
---|
93 | // StayInTileClassConstraint
|
---|
94 | ///////////////////////////////////////////////////////////////////////////
|
---|
95 | function StayInTileClassConstraint(tileClassID, distance)
|
---|
96 | {
|
---|
97 | this.tileClass = getTileClass(tileClassID);
|
---|
98 | this.distance = distance;
|
---|
99 | }
|
---|
100 |
|
---|
101 | StayInTileClassConstraint.prototype.allows = function(x, y)
|
---|
102 | {
|
---|
103 | return this.tileClass.countNonMembersInRadius(x, y, this.distance) == 0;
|
---|
104 | };
|
---|
105 |
|
---|
106 | ///////////////////////////////////////////////////////////////////////////
|
---|
107 | // BorderTileClassConstraint
|
---|
108 | ///////////////////////////////////////////////////////////////////////////
|
---|
109 | function BorderTileClassConstraint(tileClassID, distanceInside, distanceOutside)
|
---|
110 | {
|
---|
111 | this.tileClass = getTileClass(tileClassID);
|
---|
112 | this.distanceInside = distanceInside;
|
---|
113 | this.distanceOutside = distanceOutside;
|
---|
114 | }
|
---|
115 |
|
---|
116 | BorderTileClassConstraint.prototype.allows = function(x, y)
|
---|
117 | {
|
---|
118 | return (this.tileClass.countMembersInRadius(x, y, this.distanceOutside) > 0
|
---|
119 | && this.tileClass.countNonMembersInRadius(x, y, this.distanceInside) > 0);
|
---|
120 | };
|
---|
121 | function Entity(name, player, x, y, angle)
|
---|
122 | {
|
---|
123 | // Get unique ID
|
---|
124 | this.id = g_Map.getEntityID();
|
---|
125 | this.name = name;
|
---|
126 |
|
---|
127 | // Convert from tile coords to map coords
|
---|
128 | this.x = x;
|
---|
129 | this.y = y;
|
---|
130 |
|
---|
131 | if (player !== undefined)
|
---|
132 | {
|
---|
133 | this.player = player;
|
---|
134 | this.isActor = false;
|
---|
135 | }
|
---|
136 | else
|
---|
137 | { // Actors have no player ID
|
---|
138 | this.isActor = true;
|
---|
139 | }
|
---|
140 |
|
---|
141 | this.orientation = (angle !== undefined ? angle : 0);
|
---|
142 | }
|
---|
143 |
|
---|
144 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
145 | // Constant definitions
|
---|
146 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
147 |
|
---|
148 | const PI = Math.PI;
|
---|
149 |
|
---|
150 | const SEA_LEVEL = 20.0;
|
---|
151 |
|
---|
152 | const TERRAIN_SEPARATOR = "|";
|
---|
153 |
|
---|
154 | const TILES_PER_PATCH = 16;
|
---|
155 |
|
---|
156 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
157 | // Utility functions
|
---|
158 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
159 |
|
---|
160 | function fractionToTiles(f) {
|
---|
161 | return getMapSize() * f;
|
---|
162 | }
|
---|
163 |
|
---|
164 | function tilesToFraction(t) {
|
---|
165 | return t / getMapSize();
|
---|
166 | }
|
---|
167 |
|
---|
168 | function fractionToSize(f) {
|
---|
169 | return getMapSizeSqr() * f;
|
---|
170 | }
|
---|
171 |
|
---|
172 | function sizeToFraction(s) {
|
---|
173 | return s / getMapSizeSqr();
|
---|
174 | }
|
---|
175 |
|
---|
176 | function cos(x) {
|
---|
177 | return Math.cos(x);
|
---|
178 | }
|
---|
179 |
|
---|
180 | function sin(x) {
|
---|
181 | return Math.sin(x);
|
---|
182 | }
|
---|
183 |
|
---|
184 | function tan(x) {
|
---|
185 | return Math.tan(x);
|
---|
186 | }
|
---|
187 |
|
---|
188 | function abs(x) {
|
---|
189 | return Math.abs(x);
|
---|
190 | }
|
---|
191 |
|
---|
192 | function round(x) {
|
---|
193 | return Math.round(x);
|
---|
194 | }
|
---|
195 |
|
---|
196 | function lerp(a, b, t) {
|
---|
197 | return a + (b-a) * t;
|
---|
198 | }
|
---|
199 |
|
---|
200 | function sqrt(x) {
|
---|
201 | return Math.sqrt(x);
|
---|
202 | }
|
---|
203 |
|
---|
204 | function ceil(x) {
|
---|
205 | return Math.ceil(x);
|
---|
206 | }
|
---|
207 |
|
---|
208 | function floor(x) {
|
---|
209 | return Math.floor(x);
|
---|
210 | }
|
---|
211 |
|
---|
212 | function max(x, y) {
|
---|
213 | return x > y ? x : y;
|
---|
214 | }
|
---|
215 |
|
---|
216 | function min(x, y) {
|
---|
217 | return x < y ? x : y;
|
---|
218 | }
|
---|
219 |
|
---|
220 | function println(x) {
|
---|
221 | print(x);
|
---|
222 | print("\n");
|
---|
223 | }
|
---|
224 |
|
---|
225 | function argsToArray(x)
|
---|
226 | {
|
---|
227 | var numArgs = x.length;
|
---|
228 | if (numArgs != 1)
|
---|
229 | {
|
---|
230 | var ret = new Array(numArgs);
|
---|
231 | for (var i=0; i < numArgs; i++)
|
---|
232 | {
|
---|
233 | ret[i] = x[i];
|
---|
234 | }
|
---|
235 | return ret;
|
---|
236 | }
|
---|
237 | else
|
---|
238 | {
|
---|
239 | return x[0];
|
---|
240 | }
|
---|
241 | }
|
---|
242 |
|
---|
243 | function chooseRand()
|
---|
244 | {
|
---|
245 | if (arguments.length==0)
|
---|
246 | {
|
---|
247 | error("chooseRand: requires at least 1 argument");
|
---|
248 | }
|
---|
249 | var ar = argsToArray(arguments);
|
---|
250 | return ar[randInt(ar.length)];
|
---|
251 | }
|
---|
252 |
|
---|
253 | function createAreas(centeredPlacer, painter, constraint, num, retryFactor)
|
---|
254 | {
|
---|
255 | if (retryFactor === undefined)
|
---|
256 | retryFactor = 10;
|
---|
257 |
|
---|
258 | var maxFail = num * retryFactor;
|
---|
259 | var good = 0;
|
---|
260 | var bad = 0;
|
---|
261 | var ret = [];
|
---|
262 | while(good < num && bad <= maxFail)
|
---|
263 | {
|
---|
264 | centeredPlacer.x = randInt(getMapSize());
|
---|
265 | centeredPlacer.y = randInt(getMapSize());
|
---|
266 | var r = g_Map.createArea(centeredPlacer, painter, constraint);
|
---|
267 | if (r !== undefined)
|
---|
268 | {
|
---|
269 | good++;
|
---|
270 | ret.push(r);
|
---|
271 | }
|
---|
272 | else
|
---|
273 | {
|
---|
274 | bad++;
|
---|
275 | }
|
---|
276 | }
|
---|
277 |
|
---|
278 | return ret;
|
---|
279 | }
|
---|
280 |
|
---|
281 | function createObjectGroups(placer, player, constraint, num, retryFactor)
|
---|
282 | {
|
---|
283 | if (retryFactor === undefined)
|
---|
284 | retryFactor = 10;
|
---|
285 |
|
---|
286 | var maxFail = num * retryFactor;
|
---|
287 | var good = 0;
|
---|
288 | var bad = 0;
|
---|
289 | while(good < num && bad <= maxFail)
|
---|
290 | {
|
---|
291 | placer.x = randInt(getMapSize());
|
---|
292 | placer.y = randInt(getMapSize());
|
---|
293 | var r = createObjectGroup(placer, player, constraint);
|
---|
294 |
|
---|
295 | if (r !== undefined)
|
---|
296 | {
|
---|
297 | good++;
|
---|
298 | }
|
---|
299 | else
|
---|
300 | {
|
---|
301 | bad++;
|
---|
302 | }
|
---|
303 | }
|
---|
304 | return good;
|
---|
305 | }
|
---|
306 |
|
---|
307 | function createTerrain(terrain)
|
---|
308 | {
|
---|
309 | if (terrain instanceof Array)
|
---|
310 | {
|
---|
311 | var terrainList = [];
|
---|
312 |
|
---|
313 | for (var i = 0; i < terrain.length; ++i)
|
---|
314 | terrainList.push(createTerrain(terrain[i]));
|
---|
315 |
|
---|
316 | return new RandomTerrain(terrainList);
|
---|
317 | }
|
---|
318 | else
|
---|
319 | {
|
---|
320 | return createSimpleTerrain(terrain);
|
---|
321 | }
|
---|
322 | }
|
---|
323 |
|
---|
324 | function createSimpleTerrain(terrain)
|
---|
325 | {
|
---|
326 | if (typeof(terrain) == "string")
|
---|
327 | { // Split string by pipe | character, this allows specifying terrain + tree type in single string
|
---|
328 | var params = terrain.split(TERRAIN_SEPARATOR, 2);
|
---|
329 |
|
---|
330 | if (params.length != 2)
|
---|
331 | {
|
---|
332 | return new SimpleTerrain(terrain);
|
---|
333 | }
|
---|
334 | else
|
---|
335 | {
|
---|
336 | return new SimpleTerrain(params[0], params[1]);
|
---|
337 | }
|
---|
338 | }
|
---|
339 | else
|
---|
340 | {
|
---|
341 | error("createSimpleTerrain expects string as input, received "+terrain);
|
---|
342 | return undefined;
|
---|
343 | }
|
---|
344 | }
|
---|
345 |
|
---|
346 | function placeObject(type, player, x, y, angle)
|
---|
347 | {
|
---|
348 | g_Map.addObjects(new Entity(type, player, x, y, angle));
|
---|
349 | }
|
---|
350 |
|
---|
351 | function placeTerrain(x, y, terrain)
|
---|
352 | {
|
---|
353 | // convert terrain param into terrain object
|
---|
354 | g_Map.placeTerrain(x, y, createTerrain(terrain));
|
---|
355 |
|
---|
356 | }
|
---|
357 |
|
---|
358 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
359 | // Access global map variable
|
---|
360 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
361 |
|
---|
362 | function createTileClass()
|
---|
363 | {
|
---|
364 | return g_Map.createTileClass();
|
---|
365 | }
|
---|
366 |
|
---|
367 | function getTileClass(id)
|
---|
368 | {
|
---|
369 | // Check for valid class id
|
---|
370 | if (id < 1 || id > g_Map.tileClasses.length)
|
---|
371 | {
|
---|
372 | //error("Invalid tile class id: "+id);
|
---|
373 | return null;
|
---|
374 | }
|
---|
375 |
|
---|
376 | return g_Map.tileClasses[id - 1];
|
---|
377 | }
|
---|
378 |
|
---|
379 | function createArea(placer, painter, constraint)
|
---|
380 | {
|
---|
381 | return g_Map.createArea(placer, painter, constraint);
|
---|
382 | }
|
---|
383 |
|
---|
384 | function createObjectGroup(placer, player, constraint)
|
---|
385 | {
|
---|
386 | return g_Map.createObjectGroup(placer, player, constraint);
|
---|
387 | }
|
---|
388 |
|
---|
389 | function getMapSize()
|
---|
390 | {
|
---|
391 | return g_Map.size;
|
---|
392 | }
|
---|
393 |
|
---|
394 | function getMapSizeSqr()
|
---|
395 | {
|
---|
396 | return g_Map.size*g_Map.size;
|
---|
397 | }
|
---|
398 |
|
---|
399 | function getNumPlayers()
|
---|
400 | {
|
---|
401 | return g_MapSettings.PlayerData.length;
|
---|
402 | }
|
---|
403 |
|
---|
404 | function getCivCode(player)
|
---|
405 | {
|
---|
406 | return g_MapSettings.PlayerData[player].Civ;
|
---|
407 | }
|
---|
408 |
|
---|
409 | function getHeight(x, y)
|
---|
410 | {
|
---|
411 | g_Map.getHeight(x, y);
|
---|
412 | }
|
---|
413 |
|
---|
414 | function setHeight(x, y, height)
|
---|
415 | {
|
---|
416 | g_Map.setHeight(x, y, height);
|
---|
417 | }
|
---|
418 |
|
---|
419 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
420 | // Utility functions for classes
|
---|
421 | /////////////////////////////////////////////////////////////////////////////////////////////
|
---|
422 |
|
---|
423 |
|
---|
424 | // Add point to given class by id
|
---|
425 | function addToClass(x, y, id)
|
---|
426 | {
|
---|
427 | var tileClass = getTileClass(id);
|
---|
428 |
|
---|
429 | if (tileClass !== null)
|
---|
430 | tileClass.add(x, y);
|
---|
431 | }
|
---|
432 |
|
---|
433 | // Create a painter for the given class
|
---|
434 | function paintClass(id)
|
---|
435 | {
|
---|
436 | return new TileClassPainter(getTileClass(id));
|
---|
437 | }
|
---|
438 |
|
---|
439 | // Create an avoid constraint for the given classes by the given distances
|
---|
440 | function avoidClasses(/*class1, dist1, class2, dist2, etc*/)
|
---|
441 | {
|
---|
442 | var ar = new Array(arguments.length/2);
|
---|
443 | for (var i=0; i < arguments.length/2; i++)
|
---|
444 | {
|
---|
445 | ar[i] = new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1]);
|
---|
446 | }
|
---|
447 | // Return single constraint
|
---|
448 | return new AndConstraint(ar);
|
---|
449 | }
|
---|
450 | //////////////////////////////////////////////////////////////////////
|
---|
451 | // Map
|
---|
452 | //////////////////////////////////////////////////////////////////////
|
---|
453 |
|
---|
454 | function Map(size, baseHeight)
|
---|
455 | {
|
---|
456 | // Size must be 0 to 1024, divisible by 16
|
---|
457 | this.size = size;
|
---|
458 |
|
---|
459 | // Create 2D arrays for texture, object, and area maps
|
---|
460 | this.texture = new Array(size);
|
---|
461 | this.terrainObjects = new Array(size);
|
---|
462 | this.area = new Array(size);
|
---|
463 |
|
---|
464 | for (var i=0; i < size; i++)
|
---|
465 | {
|
---|
466 | this.texture[i] = new Uint16Array(size); // uint16
|
---|
467 | this.terrainObjects[i] = new Array(size); // entity
|
---|
468 | this.area[i] = new Array(size); // area
|
---|
469 |
|
---|
470 | for (var j = 0; j < size; j++)
|
---|
471 | {
|
---|
472 | this.terrainObjects[i][j] = [];
|
---|
473 | }
|
---|
474 | }
|
---|
475 |
|
---|
476 | var mapSize = size+1;
|
---|
477 |
|
---|
478 | // Create 2D array for heightmap
|
---|
479 | this.height = new Array(mapSize);
|
---|
480 | for (var i=0; i < mapSize; i++)
|
---|
481 | {
|
---|
482 | this.height[i] = new Float32Array(mapSize); //float32
|
---|
483 | for (var j=0; j < mapSize; j++)
|
---|
484 | { // Initialize height map to baseHeight
|
---|
485 | this.height[i][j] = baseHeight;
|
---|
486 | }
|
---|
487 | }
|
---|
488 |
|
---|
489 | // Create name <-> id maps for textures
|
---|
490 | this.nameToID = {};
|
---|
491 | this.IDToName = []; //string
|
---|
492 |
|
---|
493 | // Other arrays
|
---|
494 | this.objects = []; //object
|
---|
495 | this.areas = []; //area
|
---|
496 | this.tileClasses = []; //int
|
---|
497 |
|
---|
498 | // Starting entity ID
|
---|
499 | this.entityCount = 150;
|
---|
500 | }
|
---|
501 |
|
---|
502 | Map.prototype.initTerrain = function(baseTerrain)
|
---|
503 | {
|
---|
504 | // Initialize base terrain
|
---|
505 | var size = this.size;
|
---|
506 | for (var i=0; i < size; i++)
|
---|
507 | {
|
---|
508 | for (var j=0; j < size; j++)
|
---|
509 | {
|
---|
510 | baseTerrain.place(i, j);
|
---|
511 | }
|
---|
512 | }
|
---|
513 | };
|
---|
514 |
|
---|
515 | // Return ID of texture (by name)
|
---|
516 | Map.prototype.getID = function(texture)
|
---|
517 | {
|
---|
518 | if (texture in (this.nameToID))
|
---|
519 | {
|
---|
520 | return this.nameToID[texture];
|
---|
521 | }
|
---|
522 |
|
---|
523 | // Add new texture
|
---|
524 | var id = this.IDToName.length;
|
---|
525 | this.nameToID[texture] = id;
|
---|
526 | this.IDToName[id] = texture;
|
---|
527 |
|
---|
528 | return id;
|
---|
529 | };
|
---|
530 |
|
---|
531 | // Return next free entity ID
|
---|
532 | Map.prototype.getEntityID = function()
|
---|
533 | {
|
---|
534 | return this.entityCount++;
|
---|
535 | }
|
---|
536 |
|
---|
537 | // Check bounds
|
---|
538 | Map.prototype.validT = function(x, y)
|
---|
539 | {
|
---|
540 | return x >= 0 && y >= 0 && x < this.size && y < this.size;
|
---|
541 | };
|
---|
542 |
|
---|
543 | // Check bounds on height map (size + 1 by size + 1)
|
---|
544 | Map.prototype.validH = function(x, y)
|
---|
545 | {
|
---|
546 | return x >= 0 && y >= 0 && x <= this.size && y <= this.size;
|
---|
547 | };
|
---|
548 |
|
---|
549 | // Check bounds on tile class
|
---|
550 | Map.prototype.validClass = function(c)
|
---|
551 | {
|
---|
552 | return c >= 0 && c < this.tileClasses.length;
|
---|
553 | };
|
---|
554 |
|
---|
555 | Map.prototype.getTexture = function(x, y)
|
---|
556 | {
|
---|
557 | if (!this.validT(x, y))
|
---|
558 | error("getTexture: invalid tile position ("+x+", "+y+")");
|
---|
559 |
|
---|
560 | return this.IDToName[this.texture[x][y]];
|
---|
561 | };
|
---|
562 |
|
---|
563 | Map.prototype.setTexture = function(x, y, texture)
|
---|
564 | {
|
---|
565 | if (!this.validT(x, y))
|
---|
566 | error("setTexture: invalid tile position ("+x+", "+y+")");
|
---|
567 |
|
---|
568 | this.texture[x][y] = this.getID(texture);
|
---|
569 | };
|
---|
570 |
|
---|
571 | Map.prototype.getHeight = function(x, y)
|
---|
572 | {
|
---|
573 | if (!this.validH(x, y))
|
---|
574 | error("getHeight: invalid vertex position ("+x+", "+y+")");
|
---|
575 |
|
---|
576 | return this.height[x][y];
|
---|
577 | };
|
---|
578 |
|
---|
579 | Map.prototype.setHeight = function(x, y, height)
|
---|
580 | {
|
---|
581 | if (!this.validH(x, y))
|
---|
582 | error("setHeight: invalid vertex position ("+x+", "+y+")");
|
---|
583 |
|
---|
584 | this.height[x][y] = height;
|
---|
585 | };
|
---|
586 |
|
---|
587 | Map.prototype.getTerrainObjects = function(x, y)
|
---|
588 | {
|
---|
589 | if (!this.validT(x, y))
|
---|
590 | error("getTerrainObjects: invalid tile position ("+x+", "+y+")");
|
---|
591 |
|
---|
592 | return this.terrainObjects[x][y];
|
---|
593 | };
|
---|
594 |
|
---|
595 | Map.prototype.setTerrainObjects = function(x, y, objects)
|
---|
596 | {
|
---|
597 | if (!this.validT(x, y))
|
---|
598 | error("setTerrainObjects: invalid tile position ("+x+", "+y+")");
|
---|
599 |
|
---|
600 | this.terrainObjects[x][y] = objects;
|
---|
601 | };
|
---|
602 |
|
---|
603 | Map.prototype.placeTerrain = function(x, y, terrain)
|
---|
604 | {
|
---|
605 | terrain.place(x, y);
|
---|
606 | };
|
---|
607 |
|
---|
608 | Map.prototype.addObjects = function(obj)
|
---|
609 | {
|
---|
610 | this.objects = this.objects.concat(obj);
|
---|
611 | };
|
---|
612 |
|
---|
613 | Map.prototype.createArea = function(placer, painter, constraint)
|
---|
614 | {
|
---|
615 | // Check for multiple painters
|
---|
616 | if (painter instanceof Array)
|
---|
617 | {
|
---|
618 | var painterArray = painter;
|
---|
619 | painter = new MultiPainter(painterArray);
|
---|
620 | }
|
---|
621 |
|
---|
622 | // Check for null constraint
|
---|
623 | if (constraint === undefined || constraint === null)
|
---|
624 | {
|
---|
625 | constraint = new NullConstraint();
|
---|
626 | }
|
---|
627 | else if (constraint instanceof Array)
|
---|
628 | { // Check for multiple constraints
|
---|
629 | var constraintArray = constraint;
|
---|
630 | constraint = new AndConstraint(constraintArray);
|
---|
631 | }
|
---|
632 |
|
---|
633 | var points = placer.place(constraint);
|
---|
634 | if (!points)
|
---|
635 | return undefined;
|
---|
636 |
|
---|
637 | var a = new Area(points);
|
---|
638 | for (var i=0; i < points.length; i++)
|
---|
639 | {
|
---|
640 | this.area[points[i].x][points[i].y] = a;
|
---|
641 | }
|
---|
642 |
|
---|
643 | painter.paint(a);
|
---|
644 | this.areas.push(a);
|
---|
645 |
|
---|
646 | return a;
|
---|
647 | };
|
---|
648 |
|
---|
649 | Map.prototype.createObjectGroup = function(placer, player, constraint)
|
---|
650 | {
|
---|
651 | // Check for null constraint
|
---|
652 | if (constraint === undefined || constraint === null)
|
---|
653 | {
|
---|
654 | constraint = new NullConstraint();
|
---|
655 | }
|
---|
656 | else if (constraint instanceof Array)
|
---|
657 | { // Check for multiple constraints
|
---|
658 | var constraintArray = constraint;
|
---|
659 | constraint = new AndConstraint(constraintArray);
|
---|
660 | }
|
---|
661 |
|
---|
662 | return placer.place(player, constraint);
|
---|
663 | };
|
---|
664 |
|
---|
665 | Map.prototype.createTileClass = function()
|
---|
666 | {
|
---|
667 | this.tileClasses.push(new TileClass(this.size));
|
---|
668 |
|
---|
669 | return this.tileClasses.length;
|
---|
670 | };
|
---|
671 |
|
---|
672 | // Get height taking into account terrain curvature
|
---|
673 | Map.prototype.getExactHeight = function(x, y)
|
---|
674 | {
|
---|
675 | var xi = min(Math.floor(x), this.size);
|
---|
676 | var yi = min(Math.floor(y), this.size);
|
---|
677 | var xf = x - xi;
|
---|
678 | var yf = y - yi;
|
---|
679 |
|
---|
680 | var h00 = this.height[xi][yi];
|
---|
681 | var h01 = this.height[xi][yi+1];
|
---|
682 | var h10 = this.height[xi+1][yi];
|
---|
683 | var h11 = this.height[xi+1][yi+1];
|
---|
684 |
|
---|
685 | return ( 1 - yf ) * ( ( 1 - xf ) * h00 + xf * h10 ) + yf * ( ( 1 - xf ) * h01 + xf * h11 ) ;
|
---|
686 | };
|
---|
687 |
|
---|
688 | Map.prototype.getMapData = function()
|
---|
689 | {
|
---|
690 | var data = {};
|
---|
691 |
|
---|
692 | // Build entity array
|
---|
693 | var entities = [];
|
---|
694 |
|
---|
695 | // Terrain objects first (trees)
|
---|
696 | var size = this.size;
|
---|
697 | for (var x=0; x < size; ++x)
|
---|
698 | {
|
---|
699 | for (var y=0; y < size; ++y)
|
---|
700 | {
|
---|
701 | if (this.terrainObjects[x][y].length)
|
---|
702 | entities = entities.concat(this.terrainObjects[x][y]);
|
---|
703 | }
|
---|
704 | }
|
---|
705 |
|
---|
706 | // Now other entities
|
---|
707 | for (var n in this.objects)
|
---|
708 | {
|
---|
709 | entities = entities.concat(this.objects[n]);
|
---|
710 | }
|
---|
711 |
|
---|
712 | // Convert from tiles to map coordinates
|
---|
713 | for (var n in entities)
|
---|
714 | {
|
---|
715 | var e = entities[n];
|
---|
716 | e.x *= 4;
|
---|
717 | e.y *= 4;
|
---|
718 |
|
---|
719 | entities[n] = e;
|
---|
720 | }
|
---|
721 | data["entities"] = entities;
|
---|
722 |
|
---|
723 | // Terrain
|
---|
724 | data["size"] = this.size;
|
---|
725 |
|
---|
726 | // Convert 2D heightmap array to flat array
|
---|
727 | // Flat because it's easier to handle by the engine
|
---|
728 | var mapSize = size+1;
|
---|
729 | var height16 = new Array(mapSize*mapSize); // uint16
|
---|
730 | for (var x=0; x < mapSize; x++)
|
---|
731 | {
|
---|
732 | for (var y=0; y < mapSize; y++)
|
---|
733 | {
|
---|
734 | var intHeight = Math.floor((this.height[x][y] + SEA_LEVEL) * 256.0 / 0.35); // floor
|
---|
735 |
|
---|
736 | if (intHeight > 65000)
|
---|
737 | intHeight = 65000;
|
---|
738 | else if (intHeight < 0)
|
---|
739 | intHeight = 0;
|
---|
740 |
|
---|
741 | height16[y*mapSize + x] = intHeight;
|
---|
742 | }
|
---|
743 | }
|
---|
744 | data["height"] = height16;
|
---|
745 | data["seaLevel"] = SEA_LEVEL;
|
---|
746 |
|
---|
747 | // Get array of textures used in this map
|
---|
748 | var textureNames = [];
|
---|
749 | for (var name in this.nameToID)
|
---|
750 | textureNames.push(name);
|
---|
751 |
|
---|
752 | data["textureNames"] = textureNames;
|
---|
753 | data["numTextures"] = textureNames.length;
|
---|
754 |
|
---|
755 | // Convert 2D tile data to flat array, reodering into patches as expected by MapReader
|
---|
756 | var tiles = new Array(size*size);
|
---|
757 | var patches = size/16;
|
---|
758 | for (var x=0; x < size; x++)
|
---|
759 | {
|
---|
760 | var patchX = Math.floor(x/16);
|
---|
761 | var offX = x%16;
|
---|
762 | for (var y=0; y < size; y++)
|
---|
763 | {
|
---|
764 | var patchY = Math.floor(y/16);
|
---|
765 | var offY = y%16;
|
---|
766 | tiles[(patchY*patches + patchX)*256 + (offY*16 + offX)] = this.texture[x][y];
|
---|
767 | }
|
---|
768 | }
|
---|
769 | data["tileData"] = tiles;
|
---|
770 |
|
---|
771 | return data;
|
---|
772 | };
|
---|
773 | // TODO: Since there's only one map anyway, just use this global variable
|
---|
774 | var g_Map;
|
---|
775 |
|
---|
776 | // Map settings - once initialized, has all the game setup data, including player array
|
---|
777 | var g_MapSettings = {
|
---|
778 | Size : 13,
|
---|
779 | BaseTerrain: "grass1_spring",
|
---|
780 | BaseHeight: 0,
|
---|
781 | PlayerData : [ {}, {} ]
|
---|
782 | };
|
---|
783 |
|
---|
784 | var g_Environment = {
|
---|
785 | SkySet: "cirrus",
|
---|
786 | SunColour: {r: 1.47461, g: 1.47461, b: 1.47461},
|
---|
787 | SunElevation: 0.951868,
|
---|
788 | SunRotation: -0.532844,
|
---|
789 | TerrainAmbientColour: {r: 0.337255, g: 0.403922, b: 0.466667},
|
---|
790 | UnitsAmbientColour: {r: 0.501961, g: 0.501961, b: 0.501961},
|
---|
791 | Water: {
|
---|
792 | WaterBody: {
|
---|
793 | Type: "default",
|
---|
794 | Colour: {r: 0.294118, g: 0.34902, b: 0.694118},
|
---|
795 | Height: 17.6262,
|
---|
796 | Shininess: 150,
|
---|
797 | Waviness: 8,
|
---|
798 | Murkiness: 0.458008,
|
---|
799 | Tint: {r: 0.447059, g: 0.411765, b: 0.321569},
|
---|
800 | ReflectionTint: {r: 0.619608, g: 0.584314, b: 0.47451},
|
---|
801 | ReflectionTintStrength: 0.298828
|
---|
802 | }
|
---|
803 | }
|
---|
804 | };
|
---|
805 |
|
---|
806 | var g_Camera = {
|
---|
807 | Position: {x: 100, y: 150, z: -100},
|
---|
808 | Rotation: 0,
|
---|
809 | Declination: 0.523599
|
---|
810 | };
|
---|
811 |
|
---|
812 | function InitMapGen(settings)
|
---|
813 | {
|
---|
814 | if (settings === undefined || settings == {})
|
---|
815 | {
|
---|
816 | warn("InitMapGen: settings missing");
|
---|
817 | }
|
---|
818 | else
|
---|
819 | {
|
---|
820 | g_MapSettings = settings;
|
---|
821 | }
|
---|
822 |
|
---|
823 | // Create new map
|
---|
824 | log("Creating new map...");
|
---|
825 | var terrain = createTerrain(g_MapSettings.BaseTerrain);
|
---|
826 |
|
---|
827 | g_Map = new Map(g_MapSettings.Size * TILES_PER_PATCH, g_MapSettings.BaseHeight);
|
---|
828 | g_Map.initTerrain(terrain);
|
---|
829 | }
|
---|
830 |
|
---|
831 | function SaveMap()
|
---|
832 | {
|
---|
833 | log("Saving map...");
|
---|
834 |
|
---|
835 | // Get necessary data from map
|
---|
836 | var data = g_Map.getMapData();
|
---|
837 |
|
---|
838 | // Add environment and camera settings
|
---|
839 | g_Environment.Water.WaterBody.Height = SEA_LEVEL - 0.1;
|
---|
840 | data.Environment = g_Environment;
|
---|
841 | data.Camera = g_Camera;
|
---|
842 |
|
---|
843 | return data;
|
---|
844 | }
|
---|
845 | // Utility function used in both noises as an ease curve
|
---|
846 | function easeCurve(t)
|
---|
847 | {
|
---|
848 | return t*t*t*(t*(t*6-15)+10);
|
---|
849 | }
|
---|
850 |
|
---|
851 | // Find mod of number but only positive values
|
---|
852 | function modPos(num, m)
|
---|
853 | {
|
---|
854 | var p = num % m;
|
---|
855 | if (p < 0)
|
---|
856 | p += m;
|
---|
857 |
|
---|
858 | return p;
|
---|
859 | }
|
---|
860 |
|
---|
861 | /////////////////////////////////////////////////////////////////////
|
---|
862 | // Noise2D
|
---|
863 | /////////////////////////////////////////////////////////////////////
|
---|
864 |
|
---|
865 | function Noise2D(freq)
|
---|
866 | {
|
---|
867 | freq = Math.floor(freq);
|
---|
868 | this.freq = freq;
|
---|
869 | this.grads = new Array(freq);
|
---|
870 |
|
---|
871 | for (var i=0; i < freq; ++i)
|
---|
872 | {
|
---|
873 | this.grads[i] = new Array(freq);
|
---|
874 | for (var j=0; j < freq; ++j)
|
---|
875 | {
|
---|
876 | var a = randFloat() * 2 * PI;
|
---|
877 |
|
---|
878 | this.grads[i][j] = new Vector2D(Math.cos(a), Math.sin(a));
|
---|
879 | }
|
---|
880 | }
|
---|
881 | }
|
---|
882 |
|
---|
883 | Noise2D.prototype.get = function(x, y)
|
---|
884 | {
|
---|
885 | x *= this.freq;
|
---|
886 | y *= this.freq;
|
---|
887 |
|
---|
888 | var ix = modPos(Math.floor(x), this.freq);
|
---|
889 | var iy = modPos(Math.floor(y), this.freq);
|
---|
890 |
|
---|
891 | var fx = x - ix;
|
---|
892 | var fy = y - iy;
|
---|
893 |
|
---|
894 | var ix1 = (ix+1) % this.freq;
|
---|
895 | var iy1 = (iy+1) % this.freq;
|
---|
896 |
|
---|
897 | var s = this.grads[ix][iy].dot(new Vector2D(fx, fy));
|
---|
898 | var t = this.grads[ix1][iy].dot(new Vector2D(fx-1, fy));
|
---|
899 | var u = this.grads[ix][iy1].dot(new Vector2D(fx, fy-1));
|
---|
900 | var v = this.grads[ix1][iy1].dot(new Vector2D(fx-1, fy-1));
|
---|
901 |
|
---|
902 | var ex = easeCurve(fx);
|
---|
903 | var ey = easeCurve(fy);
|
---|
904 | var a = s + ex*(t-s);
|
---|
905 | var b = u + ex*(v-u);
|
---|
906 | return (a + ey*(b-a)) * 0.5 + 0.5;
|
---|
907 | };
|
---|
908 |
|
---|
909 | /////////////////////////////////////////////////////////////////////
|
---|
910 | // Noise3D
|
---|
911 | /////////////////////////////////////////////////////////////////////
|
---|
912 |
|
---|
913 | function Noise3D(freq, vfreq)
|
---|
914 | {
|
---|
915 | freq = Math.floor(freq);
|
---|
916 | vfreq = Math.floor(vfreq);
|
---|
917 | this.freq = freq;
|
---|
918 | this.vfreq = vfreq;
|
---|
919 | this.grads = new Array(freq);
|
---|
920 |
|
---|
921 | for (var i=0; i < freq; ++i)
|
---|
922 | {
|
---|
923 | this.grads[i] = new Array(freq);
|
---|
924 | for (var j=0; j < freq; ++j)
|
---|
925 | {
|
---|
926 | this.grads[i][j] = new Array(vfreq);
|
---|
927 | for(var k=0; k < vfreq; ++k)
|
---|
928 | {
|
---|
929 | var v = new Vector3D();
|
---|
930 | do
|
---|
931 | {
|
---|
932 | v.set(2*randFloat()-1, 2*randFloat()-1, 2*randFloat()-1);
|
---|
933 | }
|
---|
934 | while(v.lengthSquared() > 1 || v.lengthSquared() < 0.1);
|
---|
935 |
|
---|
936 | v.normalize();
|
---|
937 |
|
---|
938 | this.grads[i][j][k] = v;
|
---|
939 | }
|
---|
940 | }
|
---|
941 | }
|
---|
942 | }
|
---|
943 |
|
---|
944 | Noise3D.prototype.get = function(x, y, z)
|
---|
945 | {
|
---|
946 | x *= this.freq;
|
---|
947 | y *= this.freq;
|
---|
948 | z *= this.vfreq;
|
---|
949 |
|
---|
950 | var ix =modPos(Math.floor(x), this.freq);
|
---|
951 | var iy = modPos(Math.floor(y), this.freq);
|
---|
952 | var iz = modPos(Math.floor(z), this.vfreq);
|
---|
953 |
|
---|
954 | var fx = x - ix;
|
---|
955 | var fy = y - iy;
|
---|
956 | var fz = z - iz;
|
---|
957 |
|
---|
958 | var ix1 = (ix+1) % this.freq;
|
---|
959 | var iy1 = (iy+1) % this.freq;
|
---|
960 | var iz1 = (iz+1) % this.vfreq;
|
---|
961 |
|
---|
962 | var s0 = this.grads[ix][iy][iz].dot(new Vector3D(fx, fy, fz));
|
---|
963 | var t0 = this.grads[ix1][iy][iz].dot(new Vector3D(fx-1, fy, fz));
|
---|
964 | var u0 = this.grads[ix][iy1][iz].dot(new Vector3D(fx, fy-1, fz));
|
---|
965 | var v0 = this.grads[ix1][iy1][iz].dot(new Vector3D(fx-1, fy-1, fz));
|
---|
966 |
|
---|
967 | var s1 = this.grads[ix][iy][iz1].dot(new Vector3D(fx, fy, fz-1));
|
---|
968 | var t1 = this.grads[ix1][iy][iz1].dot(new Vector3D(fx-1, fy, fz-1));
|
---|
969 | var u1 = this.grads[ix][iy1][iz1].dot(new Vector3D(fx, fy-1, fz-1));
|
---|
970 | var v1 = this.grads[ix1][iy1][iz1].dot(new Vector3D(fx-1, fy-1, fz-1));
|
---|
971 |
|
---|
972 | var ex = easeCurve(fx);
|
---|
973 | var ey = easeCurve(fy);
|
---|
974 | var ez = easeCurve(fz);
|
---|
975 |
|
---|
976 | var a0 = s0 + ex*(t0-s0);
|
---|
977 | var b0 = u0 + ex*(v0-u0);
|
---|
978 | var c0 = a0 + ey*(b0-a0);
|
---|
979 |
|
---|
980 | var a1 = s1 + ex*(t1-s1);
|
---|
981 | var b1 = u1 + ex*(v1-u1);
|
---|
982 | var c1 = a1 + ey*(b1-a1);
|
---|
983 |
|
---|
984 | return (c0 + ez*(c1-c0)) * 0.5 + 0.5;
|
---|
985 | };
|
---|
986 | const ELEVATION_SET = 0;
|
---|
987 | const ELEVATION_MODIFY = 1;
|
---|
988 |
|
---|
989 | /////////////////////////////////////////////////////////////////////////////
|
---|
990 | // ElevationPainter
|
---|
991 | /////////////////////////////////////////////////////////////////////////////
|
---|
992 |
|
---|
993 | function ElevationPainter(elevation)
|
---|
994 | {
|
---|
995 | this.elevation = elevation;
|
---|
996 | this.DX = [0, 1, 1, 0];
|
---|
997 | this.DY = [0, 0, 1, 1];
|
---|
998 | }
|
---|
999 |
|
---|
1000 | ElevationPainter.prototype.paint = function(area)
|
---|
1001 | {
|
---|
1002 | var length = area.points.length;
|
---|
1003 | var elevation = this.elevation;
|
---|
1004 |
|
---|
1005 | for (var i=0; i < length; i++)
|
---|
1006 | {
|
---|
1007 | var pt = area.points[i];
|
---|
1008 |
|
---|
1009 | for (var j=0; j < 4; j++)
|
---|
1010 | {
|
---|
1011 | g_Map.height[pt.x+this.DX[j]][pt.y+this.DY[j]] = elevation;
|
---|
1012 | }
|
---|
1013 | }
|
---|
1014 | };
|
---|
1015 |
|
---|
1016 | /////////////////////////////////////////////////////////////////////////////
|
---|
1017 | // LayeredPainter
|
---|
1018 | /////////////////////////////////////////////////////////////////////////////
|
---|
1019 |
|
---|
1020 | function LayeredPainter(terrainArray, widths)
|
---|
1021 | {
|
---|
1022 | if (!(terrainArray instanceof Array))
|
---|
1023 | error("terrains must be an array!");
|
---|
1024 |
|
---|
1025 | this.terrains = [];
|
---|
1026 | for (var i = 0; i < terrainArray.length; ++i)
|
---|
1027 | this.terrains.push(createTerrain(terrainArray[i]));
|
---|
1028 |
|
---|
1029 | this.widths = widths;
|
---|
1030 | }
|
---|
1031 |
|
---|
1032 | LayeredPainter.prototype.paint = function(area)
|
---|
1033 | {
|
---|
1034 | var size = getMapSize();
|
---|
1035 | var saw = new Array(size);
|
---|
1036 | var dist = new Array(size);
|
---|
1037 |
|
---|
1038 | // init typed arrays
|
---|
1039 | for (var i = 0; i < size; ++i)
|
---|
1040 | {
|
---|
1041 | saw[i] = new Array(size); // bool / uint8
|
---|
1042 | dist[i] = new Uint16Array(size); // uint16
|
---|
1043 | }
|
---|
1044 |
|
---|
1045 | // Point queue (implemented with array)
|
---|
1046 | var pointQ = [];
|
---|
1047 |
|
---|
1048 | // push edge points
|
---|
1049 | var pts = area.points;
|
---|
1050 | var length = pts.length;
|
---|
1051 |
|
---|
1052 | for (var i=0; i < length; i++)
|
---|
1053 | {
|
---|
1054 | var x = pts[i].x;
|
---|
1055 | var y = pts[i].y;
|
---|
1056 |
|
---|
1057 | for (var dx=-1; dx <= 1; dx++)
|
---|
1058 | {
|
---|
1059 | var nx = x+dx;
|
---|
1060 | for (var dy=-1; dy <= 1; dy++)
|
---|
1061 | {
|
---|
1062 | var ny = y+dy;
|
---|
1063 |
|
---|
1064 | if (g_Map.validT(nx, ny) && g_Map.area[nx][ny] && g_Map.area[nx][ny] != area && !saw[nx][ny])
|
---|
1065 | {
|
---|
1066 | saw[nx][ny] = 1;
|
---|
1067 | dist[nx][ny] = 0;
|
---|
1068 | pointQ.push(new Point(nx, ny));
|
---|
1069 | }
|
---|
1070 | }
|
---|
1071 | }
|
---|
1072 | }
|
---|
1073 |
|
---|
1074 | // do BFS inwards to find distances to edge
|
---|
1075 | while (pointQ.length)
|
---|
1076 | {
|
---|
1077 | var pt = pointQ.shift(); // Pop queue
|
---|
1078 | var px = pt.x;
|
---|
1079 | var py = pt.y;
|
---|
1080 | var d = dist[px][py];
|
---|
1081 |
|
---|
1082 | // paint if in area
|
---|
1083 | if (g_Map.area[px][py] == area)
|
---|
1084 | {
|
---|
1085 | var w=0;
|
---|
1086 | var i=0;
|
---|
1087 |
|
---|
1088 | for (; i < this.widths.length; i++)
|
---|
1089 | {
|
---|
1090 | w += this.widths[i];
|
---|
1091 | if (w >= d)
|
---|
1092 | {
|
---|
1093 | break;
|
---|
1094 | }
|
---|
1095 | }
|
---|
1096 | this.terrains[i].place(px, py);
|
---|
1097 | }
|
---|
1098 |
|
---|
1099 | // enqueue neighbours
|
---|
1100 | for (var dx=-1; dx<=1; dx++)
|
---|
1101 | {
|
---|
1102 | var nx = px+dx;
|
---|
1103 | for (var dy=-1; dy<=1; dy++)
|
---|
1104 | {
|
---|
1105 | var ny = py+dy;
|
---|
1106 |
|
---|
1107 | if (g_Map.validT(nx, ny) && g_Map.area[nx][ny] && g_Map.area[nx][ny] == area && !saw[nx][ny])
|
---|
1108 | {
|
---|
1109 | saw[nx][ny] = 1;
|
---|
1110 | dist[nx][ny] = d+1;
|
---|
1111 | pointQ.push(new Point(nx, ny));
|
---|
1112 | }
|
---|
1113 | }
|
---|
1114 | }
|
---|
1115 | }
|
---|
1116 | };
|
---|
1117 |
|
---|
1118 | /////////////////////////////////////////////////////////////////////////////
|
---|
1119 | // MultiPainter
|
---|
1120 | /////////////////////////////////////////////////////////////////////////////
|
---|
1121 |
|
---|
1122 | function MultiPainter(painters)
|
---|
1123 | {
|
---|
1124 | this.painters = painters;
|
---|
1125 | }
|
---|
1126 |
|
---|
1127 | MultiPainter.prototype.paint = function(area)
|
---|
1128 | {
|
---|
1129 | for (var i=0; i < this.painters.length; i++)
|
---|
1130 | {
|
---|
1131 | this.painters[i].paint(area);
|
---|
1132 | }
|
---|
1133 | };
|
---|
1134 |
|
---|
1135 | /////////////////////////////////////////////////////////////////////////////
|
---|
1136 | // SmoothElevationPainter
|
---|
1137 | /////////////////////////////////////////////////////////////////////////////
|
---|
1138 |
|
---|
1139 | function SmoothElevationPainter(type, elevation, blendRadius)
|
---|
1140 | {
|
---|
1141 | this.type = type;
|
---|
1142 | this.elevation = elevation;
|
---|
1143 | this.blendRadius = blendRadius;
|
---|
1144 |
|
---|
1145 | if (type != ELEVATION_SET && type != ELEVATION_MODIFY)
|
---|
1146 | error("SmoothElevationPainter: invalid type '"+type+"'");
|
---|
1147 | }
|
---|
1148 |
|
---|
1149 | SmoothElevationPainter.prototype.checkInArea = function(area, x, y)
|
---|
1150 | {
|
---|
1151 | if (g_Map.validT(x, y))
|
---|
1152 | {
|
---|
1153 | return (g_Map.area[x][y] && g_Map.area[x][y] == area);
|
---|
1154 | }
|
---|
1155 | else
|
---|
1156 | {
|
---|
1157 | return false;
|
---|
1158 | }
|
---|
1159 | };
|
---|
1160 | var mapSize;
|
---|
1161 | SmoothElevationPainter.prototype.paint = function(area)
|
---|
1162 | {
|
---|
1163 | var pointQ = [];
|
---|
1164 | var pts = area.points;
|
---|
1165 | var heightPts = [];
|
---|
1166 |
|
---|
1167 | mapSize = getMapSize()+1;
|
---|
1168 |
|
---|
1169 | var saw = new Array(mapSize);
|
---|
1170 | var dist = new Array(mapSize);
|
---|
1171 | var gotHeightPt = new Array(mapSize);
|
---|
1172 | var newHeight = new Array(mapSize);
|
---|
1173 |
|
---|
1174 | // init typed arrays
|
---|
1175 | for (var i = 0; i < mapSize; ++i)
|
---|
1176 | {
|
---|
1177 | saw[i] = new Array(mapSize); // bool / uint8
|
---|
1178 | dist[i] = new Uint16Array(mapSize); // uint16
|
---|
1179 | gotHeightPt[i] = new Array(mapSize); // bool / uint8
|
---|
1180 | newHeight[i] = new Float32Array(mapSize); // float32
|
---|
1181 | }
|
---|
1182 |
|
---|
1183 | var length = pts.length;
|
---|
1184 |
|
---|
1185 | // get a list of all points
|
---|
1186 | for (var i=0; i < length; i++)
|
---|
1187 | {
|
---|
1188 | var x = pts[i].x;
|
---|
1189 | var y = pts[i].y;
|
---|
1190 |
|
---|
1191 | for (var dx=-1; dx <= 2; dx++)
|
---|
1192 | {
|
---|
1193 | var nx = x+dx;
|
---|
1194 | for (var dy=-1; dy <= 2; dy++)
|
---|
1195 | {
|
---|
1196 | var ny = y+dy;
|
---|
1197 |
|
---|
1198 | if (g_Map.validH(nx, ny) && !gotHeightPt[nx][ny])
|
---|
1199 | {
|
---|
1200 | gotHeightPt[nx][ny] = 1;
|
---|
1201 | heightPts.push(new Point(nx, ny));
|
---|
1202 | newHeight[nx][ny] = g_Map.height[nx][ny];
|
---|
1203 | }
|
---|
1204 | }
|
---|
1205 | }
|
---|
1206 | }
|
---|
1207 |
|
---|
1208 | // push edge points
|
---|
1209 | for (var i=0; i < length; i++)
|
---|
1210 | {
|
---|
1211 | var x = pts[i].x, y = pts[i].y;
|
---|
1212 | for (var dx=-1; dx <= 2; dx++)
|
---|
1213 | {
|
---|
1214 | var nx = x+dx;
|
---|
1215 | for (var dy=-1; dy <= 2; dy++)
|
---|
1216 | {
|
---|
1217 | var ny = y+dy;
|
---|
1218 |
|
---|
1219 | if (g_Map.validH(nx, ny)
|
---|
1220 | && !this.checkInArea(area, nx, ny)
|
---|
1221 | && !this.checkInArea(area, nx-1, ny)
|
---|
1222 | && !this.checkInArea(area, nx, ny-1)
|
---|
1223 | && !this.checkInArea(area, nx-1, ny-1)
|
---|
1224 | && !saw[nx][ny])
|
---|
1225 | {
|
---|
1226 | saw[nx][ny]= 1;
|
---|
1227 | dist[nx][ny] = 0;
|
---|
1228 | pointQ.push(new Point(nx, ny));
|
---|
1229 | }
|
---|
1230 | }
|
---|
1231 | }
|
---|
1232 | }
|
---|
1233 |
|
---|
1234 | // do BFS inwards to find distances to edge
|
---|
1235 | while(pointQ.length)
|
---|
1236 | {
|
---|
1237 | var pt = pointQ.shift();
|
---|
1238 | var px = pt.x;
|
---|
1239 | var py = pt.y;
|
---|
1240 | var d = dist[px][py];
|
---|
1241 |
|
---|
1242 | // paint if in area
|
---|
1243 | if (g_Map.validH(px, py)
|
---|
1244 | && (this.checkInArea(area, px, py) || this.checkInArea(area, px-1, py)
|
---|
1245 | || this.checkInArea(area, px, py-1) || this.checkInArea(area, px-1, py-1)))
|
---|
1246 | {
|
---|
1247 | if (d <= this.blendRadius)
|
---|
1248 | {
|
---|
1249 | var a = (d-1) / this.blendRadius;
|
---|
1250 | if (this.type == ELEVATION_SET)
|
---|
1251 | {
|
---|
1252 | newHeight[px][py] = a*this.elevation + (1-a)*g_Map.height[px][py];
|
---|
1253 | }
|
---|
1254 | else
|
---|
1255 | { // type == MODIFY
|
---|
1256 | newHeight[px][py] += a*this.elevation;
|
---|
1257 | }
|
---|
1258 | }
|
---|
1259 | else
|
---|
1260 | { // also happens when blendRadius == 0
|
---|
1261 | if (this.type == ELEVATION_SET)
|
---|
1262 | {
|
---|
1263 | newHeight[px][py] = this.elevation;
|
---|
1264 | }
|
---|
1265 | else
|
---|
1266 | { // type == MODIFY
|
---|
1267 | newHeight[px][py] += this.elevation;
|
---|
1268 | }
|
---|
1269 | }
|
---|
1270 | }
|
---|
1271 |
|
---|
1272 | // enqueue neighbours
|
---|
1273 | for (var dx=-1; dx <= 1; dx++)
|
---|
1274 | {
|
---|
1275 | var nx = px+dx;
|
---|
1276 | for (var dy=-1; dy <= 1; dy++)
|
---|
1277 | {
|
---|
1278 | var ny = py+dy;
|
---|
1279 |
|
---|
1280 | if (g_Map.validH(nx, ny)
|
---|
1281 | && (this.checkInArea(area, nx, ny) || this.checkInArea(area, nx-1, ny)
|
---|
1282 | || this.checkInArea(area, nx, ny-1) || this.checkInArea(area, nx-1, ny-1))
|
---|
1283 | && !saw[nx][ny])
|
---|
1284 | {
|
---|
1285 | saw[nx][ny] = 1;
|
---|
1286 | dist[nx][ny] = d+1;
|
---|
1287 | pointQ.push(new Point(nx, ny));
|
---|
1288 | }
|
---|
1289 | }
|
---|
1290 | }
|
---|
1291 | }
|
---|
1292 |
|
---|
1293 | length = heightPts.length;
|
---|
1294 |
|
---|
1295 | // smooth everything out
|
---|
1296 | for (var i = 0; i < length; ++i)
|
---|
1297 | {
|
---|
1298 | var pt = heightPts[i];
|
---|
1299 | var px = pt.x;
|
---|
1300 | var py = pt.y;
|
---|
1301 |
|
---|
1302 | if ((this.checkInArea(area, px, py) || this.checkInArea(area, px-1, py)
|
---|
1303 | || this.checkInArea(area, px, py-1) || this.checkInArea(area, px-1, py-1)))
|
---|
1304 | {
|
---|
1305 | var sum = 8 * newHeight[px][py];
|
---|
1306 | var count = 8;
|
---|
1307 |
|
---|
1308 | for (var dx=-1; dx <= 1; dx++)
|
---|
1309 | {
|
---|
1310 | var nx = px+dx;
|
---|
1311 | for (var dy=-1; dy <= 1; dy++)
|
---|
1312 | {
|
---|
1313 | var ny = py+dy;
|
---|
1314 |
|
---|
1315 | if (g_Map.validH(nx, ny))
|
---|
1316 | {
|
---|
1317 | sum += newHeight[nx][ny];
|
---|
1318 | count++;
|
---|
1319 | }
|
---|
1320 | }
|
---|
1321 | }
|
---|
1322 |
|
---|
1323 | g_Map.height[px][py] = sum/count;
|
---|
1324 | }
|
---|
1325 | }
|
---|
1326 | };
|
---|
1327 |
|
---|
1328 | /////////////////////////////////////////////////////////////////////////////
|
---|
1329 | // TerrainPainter
|
---|
1330 | /////////////////////////////////////////////////////////////////////////////
|
---|
1331 |
|
---|
1332 | function TerrainPainter(terrain)
|
---|
1333 | {
|
---|
1334 | this.terrain = createTerrain(terrain);
|
---|
1335 | }
|
---|
1336 |
|
---|
1337 | TerrainPainter.prototype.paint = function(area)
|
---|
1338 | {
|
---|
1339 | var length = area.points.length;
|
---|
1340 | for (var i=0; i < length; i++)
|
---|
1341 | {
|
---|
1342 | var pt = area.points[i];
|
---|
1343 | this.terrain.place(pt.x, pt.y);
|
---|
1344 | }
|
---|
1345 | };
|
---|
1346 |
|
---|
1347 | /////////////////////////////////////////////////////////////////////////////
|
---|
1348 | // TileClassPainter
|
---|
1349 | /////////////////////////////////////////////////////////////////////////////
|
---|
1350 |
|
---|
1351 | function TileClassPainter(tileClass)
|
---|
1352 | {
|
---|
1353 | this.tileClass = tileClass;
|
---|
1354 | }
|
---|
1355 |
|
---|
1356 | TileClassPainter.prototype.paint = function(area)
|
---|
1357 | {
|
---|
1358 | var length = area.points.length;
|
---|
1359 | for (var i=0; i < length; i++)
|
---|
1360 | {
|
---|
1361 | var pt = area.points[i];
|
---|
1362 | this.tileClass.add(pt.x, pt.y);
|
---|
1363 | }
|
---|
1364 | };
|
---|
1365 |
|
---|
1366 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1367 | // ClumpPlacer
|
---|
1368 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1369 |
|
---|
1370 | function ClumpPlacer(size, coherence, smoothness, failFraction, x, y)
|
---|
1371 | {
|
---|
1372 | this.size = size;
|
---|
1373 | this.coherence = coherence;
|
---|
1374 | this.smoothness = smoothness;
|
---|
1375 | this.failFraction = (failFraction !== undefined ? failFraction : 0);
|
---|
1376 | this.x = (x !== undefined ? x : -1);
|
---|
1377 | this.y = (y !== undefined ? y : -1);
|
---|
1378 | }
|
---|
1379 |
|
---|
1380 | ClumpPlacer.prototype.place = function(constraint)
|
---|
1381 | {
|
---|
1382 | if (!g_Map.validT(this.x, this.y) || !constraint.allows(this.x, this.y))
|
---|
1383 | {
|
---|
1384 | return false;
|
---|
1385 | }
|
---|
1386 |
|
---|
1387 | var retVec = [];
|
---|
1388 |
|
---|
1389 | var size = getMapSize();
|
---|
1390 | var gotRet = new Array(size);
|
---|
1391 | for (var i = 0; i < size; ++i)
|
---|
1392 | {
|
---|
1393 | gotRet[i] = new Array(size); // bool / uint8
|
---|
1394 | }
|
---|
1395 |
|
---|
1396 | var radius = Math.sqrt(this.size / PI);
|
---|
1397 | var perim = 4 * radius * 2 * PI;
|
---|
1398 | var intPerim = Math.ceil(perim);
|
---|
1399 |
|
---|
1400 | var ctrlPts = 1 + Math.floor(1.0/Math.max(this.smoothness,1.0/intPerim));
|
---|
1401 |
|
---|
1402 | if (ctrlPts > radius * 2 * PI)
|
---|
1403 | ctrlPts = Math.floor(radius * 2 * PI) + 1;
|
---|
1404 |
|
---|
1405 | var noise = new Float32Array(intPerim); //float32
|
---|
1406 | var ctrlCoords = new Float32Array(ctrlPts+1); //float32
|
---|
1407 | var ctrlVals = new Float32Array(ctrlPts+1); //float32
|
---|
1408 |
|
---|
1409 | for (var i=0; i < ctrlPts; i++)
|
---|
1410 | {
|
---|
1411 | ctrlCoords[i] = i * perim / ctrlPts;
|
---|
1412 | ctrlVals[i] = 2.0*randFloat();
|
---|
1413 | }
|
---|
1414 |
|
---|
1415 | var c = 0;
|
---|
1416 | var looped = 0;
|
---|
1417 | for (var i=0; i < intPerim; i++)
|
---|
1418 | {
|
---|
1419 | if (ctrlCoords[(c+1) % ctrlPts] < i && !looped)
|
---|
1420 | {
|
---|
1421 | c = (c+1) % ctrlPts;
|
---|
1422 | if (c == ctrlPts-1)
|
---|
1423 | looped = 1;
|
---|
1424 | }
|
---|
1425 |
|
---|
1426 | var t = (i - ctrlCoords[c]) / ((looped ? perim : ctrlCoords[(c+1)%ctrlPts]) - ctrlCoords[c]);
|
---|
1427 | var v0 = ctrlVals[(c+ctrlPts-1)%ctrlPts];
|
---|
1428 | var v1 = ctrlVals[c];
|
---|
1429 | var v2 = ctrlVals[(c+1)%ctrlPts];
|
---|
1430 | var v3 = ctrlVals[(c+2)%ctrlPts];
|
---|
1431 | var P = (v3 - v2) - (v0 - v1);
|
---|
1432 | var Q = (v0 - v1) - P;
|
---|
1433 | var R = v2 - v0;
|
---|
1434 | var S = v1;
|
---|
1435 |
|
---|
1436 | noise[i] = P*t*t*t + Q*t*t + R*t + S;
|
---|
1437 | }
|
---|
1438 |
|
---|
1439 | var failed = 0;
|
---|
1440 | for (var p=0; p < intPerim; p++)
|
---|
1441 | {
|
---|
1442 | var th = 2 * PI * p / perim;
|
---|
1443 | var r = radius * (1 + (1-this.coherence)*noise[p]);
|
---|
1444 | var s = Math.sin(th);
|
---|
1445 | var c = Math.cos(th);
|
---|
1446 | var xx=this.x;
|
---|
1447 | var yy=this.y;
|
---|
1448 |
|
---|
1449 | for (var k=0; k < Math.ceil(r); k++)
|
---|
1450 | {
|
---|
1451 | var i = Math.floor(xx);
|
---|
1452 | var j = Math.floor(yy);
|
---|
1453 | if (g_Map.validT(i, j) && constraint.allows(i, j))
|
---|
1454 | {
|
---|
1455 | if (!gotRet[i][j])
|
---|
1456 | { // Only include each point once
|
---|
1457 | gotRet[i][j] = 1;
|
---|
1458 | retVec.push(new Point(i, j));
|
---|
1459 | }
|
---|
1460 | }
|
---|
1461 | else
|
---|
1462 | {
|
---|
1463 | failed++;
|
---|
1464 | }
|
---|
1465 | xx += s;
|
---|
1466 | yy += c;
|
---|
1467 | }
|
---|
1468 | }
|
---|
1469 |
|
---|
1470 | return ((failed > this.size*this.failFraction) ? undefined : retVec);
|
---|
1471 | };
|
---|
1472 |
|
---|
1473 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1474 | // RectPlacer
|
---|
1475 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1476 |
|
---|
1477 | function RectPlacer(x1, y1, x2, y2)
|
---|
1478 | {
|
---|
1479 | this.x1 = x1;
|
---|
1480 | this.y1 = y1;
|
---|
1481 | this.x2 = x2;
|
---|
1482 | this.y2 = y2;
|
---|
1483 |
|
---|
1484 | if (x1 > x2 || y1 > y2)
|
---|
1485 | error("RectPlacer: incorrect bounds on rect");
|
---|
1486 | }
|
---|
1487 |
|
---|
1488 | RectPlacer.prototype.place = function(constraint)
|
---|
1489 | {
|
---|
1490 | var ret = [];
|
---|
1491 |
|
---|
1492 | var x2 = this.x2;
|
---|
1493 | var y2 = this.y2;
|
---|
1494 |
|
---|
1495 | for (var x=this.x1; x < x2; x++)
|
---|
1496 | {
|
---|
1497 | for (var y=this.y1; y < y2; y++)
|
---|
1498 | {
|
---|
1499 | if (g_Map.validT(x, y) && constraint.allows(x, y))
|
---|
1500 | {
|
---|
1501 | ret.push(new Point(x, y));
|
---|
1502 | }
|
---|
1503 | else
|
---|
1504 | {
|
---|
1505 | return undefined;
|
---|
1506 | }
|
---|
1507 | }
|
---|
1508 | }
|
---|
1509 |
|
---|
1510 | return ret;
|
---|
1511 |
|
---|
1512 | };
|
---|
1513 |
|
---|
1514 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1515 | // ObjectGroupPlacer
|
---|
1516 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1517 |
|
---|
1518 | function ObjectGroupPlacer() {}
|
---|
1519 |
|
---|
1520 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1521 | // SimpleGroup
|
---|
1522 | /////////////////////////////////////////////////////////////////////////////////////////
|
---|
1523 |
|
---|
1524 | function SimpleObject(type, minCount, maxCount, minDistance, maxDistance, minAngle, maxAngle)
|
---|
1525 | {
|
---|
1526 | this.type = type;
|
---|
1527 | this.minCount = minCount;
|
---|
1528 | this.maxCount = maxCount;
|
---|
1529 | this.minDistance = minDistance;
|
---|
1530 | this.maxDistance = maxDistance;
|
---|
1531 | this.minAngle = (minAngle !== undefined ? minAngle : 0);
|
---|
1532 | this.maxAngle = (maxAngle !== undefined ? maxAngle : 2*PI);
|
---|
1533 |
|
---|
1534 | if (minCount > maxCount)
|
---|
1535 | error("SimpleObject: minCount must be less than or equal to maxCount");
|
---|
1536 |
|
---|
1537 | if (minDistance > maxDistance)
|
---|
1538 | error("SimpleObject: minDistance must be less than or equal to maxDistance");
|
---|
1539 |
|
---|
1540 | if (minAngle > maxAngle)
|
---|
1541 | error("SimpleObject: minAngle must be less than or equal to maxAngle");
|
---|
1542 | }
|
---|
1543 |
|
---|
1544 | SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
|
---|
1545 | {
|
---|
1546 | var failCount = 0;
|
---|
1547 | var count = randInt(this.minCount, this.maxCount);
|
---|
1548 | var resultObjs = [];
|
---|
1549 |
|
---|
1550 | for (var i=0; i < count; i++)
|
---|
1551 | {
|
---|
1552 | while(true)
|
---|
1553 | {
|
---|
1554 | var distance = randFloat(this.minDistance, this.maxDistance);
|
---|
1555 | var direction = randFloat(0, 2*PI);
|
---|
1556 |
|
---|
1557 | var x = cx + 0.5 + distance * Math.cos(direction);
|
---|
1558 | var y = cy + 0.5 + distance * Math.sin(direction);
|
---|
1559 | var fail = false; // reset place failure flag
|
---|
1560 |
|
---|
1561 | if (x < 0 || y < 0 || x > g_Map.size || y > g_Map.size)
|
---|
1562 | {
|
---|
1563 | fail = true;
|
---|
1564 | }
|
---|
1565 | else
|
---|
1566 | {
|
---|
1567 | if (avoidSelf)
|
---|
1568 | {
|
---|
1569 | var length = resultObjs.length;
|
---|
1570 | for (var i = 0; (i < length) && !fail; i++)
|
---|
1571 | {
|
---|
1572 | var dx = x - resultObjs[i].x;
|
---|
1573 | var dy = y - resultObjs[i].y;
|
---|
1574 |
|
---|
1575 | if ((dx*dx + dy*dy) < 1)
|
---|
1576 | {
|
---|
1577 | fail = true;
|
---|
1578 | }
|
---|
1579 | }
|
---|
1580 | }
|
---|
1581 |
|
---|
1582 | if (!fail)
|
---|
1583 | {
|
---|
1584 | if (!constraint.allows(Math.floor(x), Math.floor(y)))
|
---|
1585 | {
|
---|
1586 | fail = true;
|
---|
1587 | }
|
---|
1588 | else
|
---|
1589 | { // if we got here, we're good
|
---|
1590 | var angle = randFloat(this.minAngle, this.maxAngle);
|
---|
1591 | resultObjs.push(new Entity(this.type, player, x, y, angle));
|
---|
1592 | break;
|
---|
1593 | }
|
---|
1594 | }
|
---|
1595 | }
|
---|
1596 |
|
---|
1597 | if (fail)
|
---|
1598 | {
|
---|
1599 | failCount++;
|
---|
1600 | if (failCount > 20) // TODO: Make this adjustable
|
---|
1601 | {
|
---|
1602 | return undefined;
|
---|
1603 | }
|
---|
1604 | }
|
---|
1605 | }
|
---|
1606 | }
|
---|
1607 |
|
---|
1608 | return resultObjs;
|
---|
1609 | };
|
---|
1610 |
|
---|
1611 | function SimpleGroup(elements, avoidSelf, tileClass, x, y)
|
---|
1612 | {
|
---|
1613 | this.elements = elements;
|
---|
1614 | this.tileClass = (tileClass !== undefined ? getTileClass(tileClass) : null);
|
---|
1615 | this.avoidSelf = (avoidSelf !== undefined ? avoidSelf : false);
|
---|
1616 | this.x = (x !== undefined ? x : -1);
|
---|
1617 | this.y = (y !== undefined ? y : -1);
|
---|
1618 | }
|
---|
1619 |
|
---|
1620 | SimpleGroup.prototype.place = function(player, constraint)
|
---|
1621 | {
|
---|
1622 | var resultObjs = [];
|
---|
1623 |
|
---|
1624 | // Try placement of objects
|
---|
1625 | var length = this.elements.length;
|
---|
1626 | for (var i=0; i < length; i++)
|
---|
1627 | {
|
---|
1628 | var objs = this.elements[i].place(this.x, this.y, player, this.avoidSelf, constraint);
|
---|
1629 | if (objs === undefined)
|
---|
1630 | { // Failure
|
---|
1631 | return false;
|
---|
1632 | }
|
---|
1633 | else
|
---|
1634 | {
|
---|
1635 | resultObjs = resultObjs.concat(objs);
|
---|
1636 | }
|
---|
1637 | }
|
---|
1638 |
|
---|
1639 | // Add placed objects to map
|
---|
1640 | length = resultObjs.length;
|
---|
1641 | for (var i=0; i < length; i++)
|
---|
1642 | {
|
---|
1643 | g_Map.addObjects(resultObjs[i]);
|
---|
1644 |
|
---|
1645 | if (this.tileClass !== null)
|
---|
1646 | { // Round object position to integer
|
---|
1647 | this.tileClass.add(Math.floor(resultObjs[i].x), Math.floor(resultObjs[i].y));
|
---|
1648 | }
|
---|
1649 | }
|
---|
1650 |
|
---|
1651 | return true;
|
---|
1652 | };
|
---|
1653 |
|
---|
1654 | function Point(x, y)
|
---|
1655 | {
|
---|
1656 | this.x = (x !== undefined ? x : 0);
|
---|
1657 | this.y = (y !== undefined ? y : 0);
|
---|
1658 | }
|
---|
1659 |
|
---|
1660 | /*
|
---|
1661 | * Return a random floating point number using Math.random library
|
---|
1662 | *
|
---|
1663 | * If no parameter given, the returned float is in the interval [0, 1)
|
---|
1664 | * If two parameters are given, they are minval and maxval, and the returned float is in the interval [minval, maxval)
|
---|
1665 | */
|
---|
1666 | function randFloat()
|
---|
1667 | {
|
---|
1668 | if (arguments.length == 0)
|
---|
1669 | {
|
---|
1670 | return Math.random();
|
---|
1671 | }
|
---|
1672 | else if (arguments.length == 2)
|
---|
1673 | {
|
---|
1674 | var minVal = arguments[0];
|
---|
1675 | var maxVal = arguments[1];
|
---|
1676 |
|
---|
1677 | return minVal + randFloat() * (maxVal - minVal);
|
---|
1678 | }
|
---|
1679 | else
|
---|
1680 | {
|
---|
1681 | error("randFloat() received invalid number of arguments: "+arguments.length);
|
---|
1682 | return undefined;
|
---|
1683 | }
|
---|
1684 | }
|
---|
1685 |
|
---|
1686 | /*
|
---|
1687 | * Return a random integer using Math.random library
|
---|
1688 | *
|
---|
1689 | * If one parameter given, it's maxval, and the returned integer is in the interval [0, maxval)
|
---|
1690 | * If two parameters are given, they are minval and maxval, and the returned integer is in the interval [minval, maxval]
|
---|
1691 | */
|
---|
1692 | function randInt()
|
---|
1693 | {
|
---|
1694 | if (arguments.length == 1)
|
---|
1695 | {
|
---|
1696 | var maxVal = arguments[0];
|
---|
1697 | return Math.floor(Math.random() * maxVal);
|
---|
1698 | }
|
---|
1699 | else if (arguments.length == 2)
|
---|
1700 | {
|
---|
1701 | var minVal = arguments[0];
|
---|
1702 | var maxVal = arguments[1];
|
---|
1703 |
|
---|
1704 | return minVal + randInt(maxVal - minVal + 1);
|
---|
1705 | }
|
---|
1706 | else
|
---|
1707 | {
|
---|
1708 | error("randInt() received invalid number of arguments: "+arguments.length);
|
---|
1709 | return undefined;
|
---|
1710 | }
|
---|
1711 | }
|
---|
1712 | //////////////////////////////////////////////////////////////////////
|
---|
1713 | // Terrain
|
---|
1714 | //////////////////////////////////////////////////////////////////////
|
---|
1715 |
|
---|
1716 | function Terrain() {}
|
---|
1717 |
|
---|
1718 | Terrain.prototype.place = function(x, y)
|
---|
1719 | {
|
---|
1720 | // Clear old array
|
---|
1721 | g_Map.terrainObjects[x][y] = [];
|
---|
1722 |
|
---|
1723 | this.placeNew(x, y);
|
---|
1724 | };
|
---|
1725 |
|
---|
1726 | Terrain.prototype.placeNew = function() {};
|
---|
1727 |
|
---|
1728 | //////////////////////////////////////////////////////////////////////
|
---|
1729 | // SimpleTerrain
|
---|
1730 | //////////////////////////////////////////////////////////////////////
|
---|
1731 |
|
---|
1732 | function SimpleTerrain(texture, treeType)
|
---|
1733 | {
|
---|
1734 | if (texture === undefined)
|
---|
1735 | error("SimpleTerrain: texture not defined");
|
---|
1736 |
|
---|
1737 | this.texture = texture;
|
---|
1738 | this.treeType = treeType;
|
---|
1739 | }
|
---|
1740 |
|
---|
1741 | SimpleTerrain.prototype = new Terrain();
|
---|
1742 | SimpleTerrain.prototype.constructor = SimpleTerrain;
|
---|
1743 | SimpleTerrain.prototype.placeNew = function(x, y)
|
---|
1744 | {
|
---|
1745 | if (this.treeType !== undefined)
|
---|
1746 | g_Map.terrainObjects[x][y].push(new Entity(this.treeType, 0, x+0.5, y+0.5, randFloat()*PI));
|
---|
1747 |
|
---|
1748 | g_Map.texture[x][y] = g_Map.getID(this.texture);
|
---|
1749 | };
|
---|
1750 |
|
---|
1751 | //////////////////////////////////////////////////////////////////////
|
---|
1752 | // RandomTerrain
|
---|
1753 | //////////////////////////////////////////////////////////////////////
|
---|
1754 |
|
---|
1755 | function RandomTerrain(terrains)
|
---|
1756 | {
|
---|
1757 | if (!(terrains instanceof Array) || !terrains.length)
|
---|
1758 | error("Invalid terrains array");
|
---|
1759 |
|
---|
1760 | this.terrains = terrains;
|
---|
1761 | }
|
---|
1762 |
|
---|
1763 | RandomTerrain.prototype = new Terrain();
|
---|
1764 | RandomTerrain.prototype.constructor = RandomTerrain;
|
---|
1765 | RandomTerrain.prototype.placeNew = function(x, y)
|
---|
1766 | {
|
---|
1767 | this.terrains[randInt(this.terrains.length)].placeNew(x, y);
|
---|
1768 | };
|
---|
1769 | //////////////////////////////////////////////////////////////////////
|
---|
1770 | // RangeOp
|
---|
1771 | //////////////////////////////////////////////////////////////////////
|
---|
1772 |
|
---|
1773 | function RangeOp(size)
|
---|
1774 | {
|
---|
1775 | // Get smallest power of 2 which is greater than or equal to size
|
---|
1776 | this.nn = 1;
|
---|
1777 | while (this.nn < size) {
|
---|
1778 | this.nn *= 2;
|
---|
1779 | }
|
---|
1780 |
|
---|
1781 | this.vals = new Int16Array(2*this.nn); // int16
|
---|
1782 | }
|
---|
1783 |
|
---|
1784 | RangeOp.prototype.set = function(pos, amt)
|
---|
1785 | {
|
---|
1786 | this.add(pos, amt - this.vals[this.nn + pos]);
|
---|
1787 | };
|
---|
1788 |
|
---|
1789 | RangeOp.prototype.add = function(pos, amt)
|
---|
1790 | {
|
---|
1791 | for(var s = this.nn; s >= 1; s /= 2)
|
---|
1792 | {
|
---|
1793 | this.vals[s + pos] += amt;
|
---|
1794 | pos = Math.floor(pos/2);
|
---|
1795 | }
|
---|
1796 | };
|
---|
1797 |
|
---|
1798 | RangeOp.prototype.get = function(start, end)
|
---|
1799 | {
|
---|
1800 | var ret = 0;
|
---|
1801 | var i;
|
---|
1802 | var nn = this.nn;
|
---|
1803 |
|
---|
1804 | // Count from start to end by powers of 2
|
---|
1805 | for (i = 1; start+i <= end; i *= 2)
|
---|
1806 | {
|
---|
1807 | if (start & i)
|
---|
1808 | { // For each bit in start
|
---|
1809 | ret += this.vals[nn/i + Math.floor(start/i)];
|
---|
1810 | start += i;
|
---|
1811 | }
|
---|
1812 | }
|
---|
1813 |
|
---|
1814 | //
|
---|
1815 | while(i >= 1)
|
---|
1816 | {
|
---|
1817 | if(start+i <= end)
|
---|
1818 | {
|
---|
1819 | ret += this.vals[nn/i + Math.floor(start/i)];
|
---|
1820 | start += i;
|
---|
1821 | }
|
---|
1822 | i /= 2;
|
---|
1823 | }
|
---|
1824 |
|
---|
1825 | return ret;
|
---|
1826 | };
|
---|
1827 |
|
---|
1828 |
|
---|
1829 | //////////////////////////////////////////////////////////////////////
|
---|
1830 | // TileClass
|
---|
1831 | //////////////////////////////////////////////////////////////////////
|
---|
1832 |
|
---|
1833 | function TileClass(size)
|
---|
1834 | {
|
---|
1835 | this.size = size;
|
---|
1836 | this.inclusionCount = new Array(size);
|
---|
1837 | this.rangeCount = new Array(size);
|
---|
1838 |
|
---|
1839 | for (var i=0; i < size; ++i)
|
---|
1840 | {
|
---|
1841 | this.inclusionCount[i] = new Int16Array(size); //int16
|
---|
1842 | this.rangeCount[i] = new RangeOp(size);
|
---|
1843 | }
|
---|
1844 | }
|
---|
1845 |
|
---|
1846 | TileClass.prototype.add = function(x, y)
|
---|
1847 | {
|
---|
1848 | if (!this.inclusionCount[x][y])
|
---|
1849 | {
|
---|
1850 | this.rangeCount[y].add(x, 1);
|
---|
1851 | }
|
---|
1852 |
|
---|
1853 | this.inclusionCount[x][y]++;
|
---|
1854 | };
|
---|
1855 |
|
---|
1856 | TileClass.prototype.remove = function(x, y)
|
---|
1857 | {
|
---|
1858 | this.inclusionCount[x][y]--;
|
---|
1859 | if(!this.inclusionCount[x][y])
|
---|
1860 | {
|
---|
1861 | this.rangeCount[y].add(x, -1);
|
---|
1862 | }
|
---|
1863 | };
|
---|
1864 |
|
---|
1865 | TileClass.prototype.countInRadius = function(cx, cy, radius, returnMembers)
|
---|
1866 | {
|
---|
1867 | var members = 0;
|
---|
1868 | var nonMembers = 0;
|
---|
1869 | var size = this.size;
|
---|
1870 |
|
---|
1871 | var ymax = cy+radius;
|
---|
1872 |
|
---|
1873 | for (var y = cy-radius; y <= ymax; y++)
|
---|
1874 | {
|
---|
1875 | var iy = Math.floor(y);
|
---|
1876 | if(iy >= 0 && iy < size)
|
---|
1877 | {
|
---|
1878 | var dy = y - cy;
|
---|
1879 | var dx = Math.sqrt(radius*radius - dy*dy);
|
---|
1880 |
|
---|
1881 | var lowerX = Math.floor(cx - dx);
|
---|
1882 | var upperX = Math.floor(cx + dx);
|
---|
1883 |
|
---|
1884 | var minX = (lowerX > 0 ? lowerX : 0);
|
---|
1885 | var maxX = (upperX < size ? upperX+1 : size);
|
---|
1886 |
|
---|
1887 | var total = maxX - minX;
|
---|
1888 | var mem = this.rangeCount[iy].get(minX, maxX);
|
---|
1889 |
|
---|
1890 | members += mem;
|
---|
1891 | nonMembers += total - mem;
|
---|
1892 | }
|
---|
1893 | }
|
---|
1894 |
|
---|
1895 | if (returnMembers)
|
---|
1896 | return members;
|
---|
1897 | else
|
---|
1898 | return nonMembers;
|
---|
1899 | };
|
---|
1900 |
|
---|
1901 | TileClass.prototype.countMembersInRadius = function(cx, cy, radius)
|
---|
1902 | {
|
---|
1903 | return this.countInRadius(cx, cy, radius, true);
|
---|
1904 | };
|
---|
1905 |
|
---|
1906 | TileClass.prototype.countNonMembersInRadius = function(cx, cy, radius)
|
---|
1907 | {
|
---|
1908 | return this.countInRadius(cx, cy, radius, false);
|
---|
1909 | };
|
---|
1910 | /////////////////////////////////////////////////////////////////////
|
---|
1911 | // Vector2D
|
---|
1912 | /////////////////////////////////////////////////////////////////////
|
---|
1913 |
|
---|
1914 | // TODO: Type errors if v not instanceof Vector classes
|
---|
1915 | // TODO: Possible implement in C++
|
---|
1916 |
|
---|
1917 | function Vector2D(x, y)
|
---|
1918 | {
|
---|
1919 | if (arguments.length == 2)
|
---|
1920 | {
|
---|
1921 | this.set(x, y);
|
---|
1922 | }
|
---|
1923 | else
|
---|
1924 | {
|
---|
1925 | this.set(0, 0);
|
---|
1926 | }
|
---|
1927 | }
|
---|
1928 |
|
---|
1929 | Vector2D.prototype.set = function(x, y)
|
---|
1930 | {
|
---|
1931 | this.x = x;
|
---|
1932 | this.y = y;
|
---|
1933 | };
|
---|
1934 |
|
---|
1935 | Vector2D.prototype.add = function(v)
|
---|
1936 | {
|
---|
1937 | return new Vector2D(this.x + v.x, this.y + v.y);
|
---|
1938 | };
|
---|
1939 |
|
---|
1940 | Vector2D.prototype.sub = function(v)
|
---|
1941 | {
|
---|
1942 | return new Vector2D(this.x - v.x, this.y - v.y);
|
---|
1943 | };
|
---|
1944 |
|
---|
1945 | Vector2D.prototype.mult = function(f)
|
---|
1946 | {
|
---|
1947 | return new Vector2D(this.x * f, this.y * f);
|
---|
1948 | };
|
---|
1949 |
|
---|
1950 | Vector2D.prototype.div = function(f)
|
---|
1951 | {
|
---|
1952 | return new Vector2D(this.x / f, this.y / f);
|
---|
1953 | };
|
---|
1954 |
|
---|
1955 | Vector2D.prototype.dot = function(v)
|
---|
1956 | {
|
---|
1957 | return this.x * v.x + this.y * v.y;
|
---|
1958 | };
|
---|
1959 |
|
---|
1960 | Vector2D.prototype.lengthSquared = function()
|
---|
1961 | {
|
---|
1962 | return this.dot(this);
|
---|
1963 | };
|
---|
1964 |
|
---|
1965 | Vector2D.prototype.length = function()
|
---|
1966 | {
|
---|
1967 | return Math.sqrt(this.lengthSquared());
|
---|
1968 | };
|
---|
1969 |
|
---|
1970 | Vector2D.prototype.normalize = function()
|
---|
1971 | {
|
---|
1972 | var mag = this.length();
|
---|
1973 |
|
---|
1974 | this.x /= mag;
|
---|
1975 | this.y /= mag;
|
---|
1976 | };
|
---|
1977 |
|
---|
1978 | /////////////////////////////////////////////////////////////////////
|
---|
1979 | // Vector3D
|
---|
1980 | /////////////////////////////////////////////////////////////////////
|
---|
1981 |
|
---|
1982 | function Vector3D(x, y, z)
|
---|
1983 | {
|
---|
1984 | if (arguments.length == 3)
|
---|
1985 | {
|
---|
1986 | this.set(x, y, z);
|
---|
1987 | }
|
---|
1988 | else
|
---|
1989 | {
|
---|
1990 | this.set(0, 0, 0);
|
---|
1991 | }
|
---|
1992 | }
|
---|
1993 |
|
---|
1994 | Vector3D.prototype.set = function(x, y, z)
|
---|
1995 | {
|
---|
1996 | this.x = x;
|
---|
1997 | this.y = y;
|
---|
1998 | this.z = z;
|
---|
1999 | };
|
---|
2000 |
|
---|
2001 | Vector3D.prototype.add = function(v)
|
---|
2002 | {
|
---|
2003 | return new Vector3D(this.x + v.x, this.y + v.y, this.z + v.z);
|
---|
2004 | };
|
---|
2005 |
|
---|
2006 | Vector3D.prototype.sub = function(v)
|
---|
2007 | {
|
---|
2008 | return new Vector3D(this.x - v.x, this.y - v.y, this.z - v.z);
|
---|
2009 | };
|
---|
2010 |
|
---|
2011 | Vector3D.prototype.mult = function(f)
|
---|
2012 | {
|
---|
2013 | return new Vector3D(this.x * f, this.y * f, this.z * f);
|
---|
2014 | };
|
---|
2015 |
|
---|
2016 | Vector3D.prototype.div = function(f)
|
---|
2017 | {
|
---|
2018 | return new Vector3D(this.x / f, this.y / f, this.z / f);
|
---|
2019 | };
|
---|
2020 |
|
---|
2021 | Vector3D.prototype.dot = function(v)
|
---|
2022 | {
|
---|
2023 | return this.x * v.x + this.y * v.y + this.z * v.z;
|
---|
2024 | };
|
---|
2025 |
|
---|
2026 | Vector3D.prototype.lengthSquared = function()
|
---|
2027 | {
|
---|
2028 | return this.dot(this);
|
---|
2029 | };
|
---|
2030 |
|
---|
2031 | Vector3D.prototype.length = function()
|
---|
2032 | {
|
---|
2033 | return Math.sqrt(this.lengthSquared());
|
---|
2034 | };
|
---|
2035 |
|
---|
2036 | Vector3D.prototype.normalize = function()
|
---|
2037 | {
|
---|
2038 | var mag = this.length();
|
---|
2039 |
|
---|
2040 | this.x /= mag;
|
---|
2041 | this.y /= mag;
|
---|
2042 | this.z /= mag;
|
---|
2043 | };
|
---|
2044 |
|
---|
2045 | var settings = {
|
---|
2046 | Size : 13,
|
---|
2047 | BaseTerrain: "grass1_spring",
|
---|
2048 | BaseHeight: 0,
|
---|
2049 | PlayerData : [ {Civ: "hele"}, {Civ: "hele"}, {Civ: "hele"}, {Civ: "hele"}]
|
---|
2050 | };
|
---|
2051 | InitMapGen(settings);
|
---|
2052 |
|
---|
2053 | // terrain textures
|
---|
2054 | const tSand = "desert_dirt_rough";
|
---|
2055 | const tDunes = "desert_sand_dunes_100";
|
---|
2056 | const tFineSand = "desert_sand_smooth";
|
---|
2057 | const tCliff = "desert_cliff_badlands";
|
---|
2058 | const tGrassSand75 = "desert_grass_a";
|
---|
2059 | const tGrassSand50 = "desert_grass_a_sand";
|
---|
2060 | const tGrassSand25 = "desert_grass_a_stones";
|
---|
2061 | const tDirt = "desert_dirt_rough";
|
---|
2062 | const tDirtCracks = "desert_dirt_cracks";
|
---|
2063 | const tShore = "desert_sand_wet";
|
---|
2064 | const tWater = "desert_shore_stones";
|
---|
2065 | const tWaterDeep = "desert_shore_stones_wet";
|
---|
2066 |
|
---|
2067 | // gaia entities
|
---|
2068 | const oBerryBush = "gaia/flora_bush_berry";
|
---|
2069 | const oSheep = "gaia/fauna_sheep";
|
---|
2070 | const oDeer = "gaia/fauna_deer";
|
---|
2071 | const oMine = "gaia/geology_stone_desert_small";
|
---|
2072 | const oTree = "gaia/flora_tree_medit_fan_palm";
|
---|
2073 |
|
---|
2074 | // decorative props
|
---|
2075 | const aBush = "actor|props/flora/bush_dry_a.xml";
|
---|
2076 | const aDecorativeRock = "actor|geology/gray1.xml";
|
---|
2077 |
|
---|
2078 | var tForest = tGrassSand75 + TERRAIN_SEPARATOR + oTree;
|
---|
2079 |
|
---|
2080 | // initialize map
|
---|
2081 |
|
---|
2082 | log("Initializing map...");
|
---|
2083 |
|
---|
2084 | var numPlayers = getNumPlayers();
|
---|
2085 | var mapSize = getMapSize();
|
---|
2086 |
|
---|
2087 | // create tile classes
|
---|
2088 |
|
---|
2089 | var clPlayer = createTileClass();
|
---|
2090 | var clHill1 = createTileClass();
|
---|
2091 | var clHill2 = createTileClass();
|
---|
2092 | var clHill3 = createTileClass();
|
---|
2093 | var clForest = createTileClass();
|
---|
2094 | var clWater = createTileClass();
|
---|
2095 | var clPatch = createTileClass();
|
---|
2096 | var clRock = createTileClass();
|
---|
2097 | var clFood = createTileClass();
|
---|
2098 | var clBaseResource = createTileClass();
|
---|
2099 |
|
---|
2100 | // place players
|
---|
2101 |
|
---|
2102 | var playerX = new Array(numPlayers);
|
---|
2103 | var playerY = new Array(numPlayers);
|
---|
2104 | var playerAngle = new Array(numPlayers);
|
---|
2105 |
|
---|
2106 | var startAngle = randFloat() * 2 * PI;
|
---|
2107 | for (var i=0; i < numPlayers; i++)
|
---|
2108 | {
|
---|
2109 | playerAngle[i] = startAngle + i*2*PI/numPlayers;
|
---|
2110 | playerX[i] = 0.5 + 0.39*cos(playerAngle[i]);
|
---|
2111 | playerY[i] = 0.5 + 0.39*sin(playerAngle[i]);
|
---|
2112 | }
|
---|
2113 |
|
---|
2114 | for (var i=0; i < numPlayers; i++)
|
---|
2115 | {
|
---|
2116 | log("Creating base for player " + (i + 1) + "...");
|
---|
2117 |
|
---|
2118 | // some constants
|
---|
2119 | var radius = 20;
|
---|
2120 |
|
---|
2121 | // get the x and y in tiles
|
---|
2122 | var fx = fractionToTiles(playerX[i]);
|
---|
2123 | var fy = fractionToTiles(playerY[i]);
|
---|
2124 | var ix = round(fx);
|
---|
2125 | var iy = round(fy);
|
---|
2126 |
|
---|
2127 | // calculate size based on the radius
|
---|
2128 | var size = PI * radius * radius;
|
---|
2129 |
|
---|
2130 | // create the hill
|
---|
2131 | var placer = new ClumpPlacer(size, 0.9, 0.5, 0, ix, iy);
|
---|
2132 | createArea(placer, paintClass(clPlayer), null);
|
---|
2133 |
|
---|
2134 | // create the central road patch
|
---|
2135 | placer = new ClumpPlacer(PI*2*2, 0.6, 0.3, 0.5, ix, iy);
|
---|
2136 | var painter = new TerrainPainter(tDirt);
|
---|
2137 | createArea(placer, painter, null);
|
---|
2138 |
|
---|
2139 | // create the TC and citizens
|
---|
2140 | var civ = getCivCode(i);
|
---|
2141 | var group = new SimpleGroup(
|
---|
2142 | [ // elements (type, count, distance)
|
---|
2143 | new SimpleObject("structures/"+civ+"_civil_centre", 1,1, 0,0),
|
---|
2144 | new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5)
|
---|
2145 | ],
|
---|
2146 | true, null, ix, iy
|
---|
2147 | );
|
---|
2148 | createObjectGroup(group, i+1);
|
---|
2149 |
|
---|
2150 | // create berry bushes
|
---|
2151 | var bbAngle = randFloat()*2*PI;
|
---|
2152 | var bbDist = 10;
|
---|
2153 | var bbX = round(fx + bbDist * cos(bbAngle));
|
---|
2154 | var bbY = round(fy + bbDist * sin(bbAngle));
|
---|
2155 | group = new SimpleGroup(
|
---|
2156 | [new SimpleObject(oSheep, 5,5, 0,2)],
|
---|
2157 | true, clBaseResource, bbX, bbY
|
---|
2158 | );
|
---|
2159 | createObjectGroup(group, 0);
|
---|
2160 |
|
---|
2161 | // create mines
|
---|
2162 | var mAngle = bbAngle;
|
---|
2163 | while(abs(mAngle - bbAngle) < PI/3) {
|
---|
2164 | mAngle = randFloat()*2*PI;
|
---|
2165 | }
|
---|
2166 | var mDist = 12;
|
---|
2167 | var mX = round(fx + mDist * cos(mAngle));
|
---|
2168 | var mY = round(fy + mDist * sin(mAngle));
|
---|
2169 | group = new SimpleGroup(
|
---|
2170 | [new SimpleObject(oMine, 3,3, 0,2)],
|
---|
2171 | true, clBaseResource, mX, mY
|
---|
2172 | );
|
---|
2173 | createObjectGroup(group, 0);
|
---|
2174 |
|
---|
2175 | // create starting straggler trees
|
---|
2176 | group = new SimpleGroup(
|
---|
2177 | [new SimpleObject(oTree, 2,2, 6,12)],
|
---|
2178 | true, null, ix, iy
|
---|
2179 | );
|
---|
2180 | createObjectGroup(group, 0, avoidClasses(clBaseResource,1));
|
---|
2181 | }
|
---|
2182 |
|
---|
2183 | // create patches
|
---|
2184 | log("Creating sand patches...");
|
---|
2185 | var placer = new ClumpPlacer(30, 0.2, 0.1, 0);
|
---|
2186 | var painter = new LayeredPainter([[tSand, tFineSand], tFineSand], [1]);
|
---|
2187 | createAreas(placer, [painter, paintClass(clPatch)],
|
---|
2188 | avoidClasses(clPatch, 5),
|
---|
2189 | (mapSize*mapSize)/600
|
---|
2190 | );
|
---|
2191 |
|
---|
2192 | log("Creating dirt patches...");
|
---|
2193 | placer = new ClumpPlacer(10, 0.2, 0.1, 0);
|
---|
2194 | painter = new TerrainPainter([tSand, tDirt]);
|
---|
2195 | createAreas(placer, [painter, paintClass(clPatch)],
|
---|
2196 | avoidClasses(clPatch, 5),
|
---|
2197 | (mapSize*mapSize)/600
|
---|
2198 | );
|
---|
2199 |
|
---|
2200 | // create the oasis
|
---|
2201 | log("Creating water...");
|
---|
2202 | placer = new ClumpPlacer(1200, 0.6, 0.1, 0, mapSize/2, mapSize/2);
|
---|
2203 | painter = new LayeredPainter([[tSand, tForest], tShore, tWaterDeep], [6,1]);
|
---|
2204 | elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, -10, 5);
|
---|
2205 | createArea(placer, [painter, elevationPainter, paintClass(clForest)], null);
|
---|
2206 |
|
---|
2207 | // create hills
|
---|
2208 | log("Creating level 1 hills...");
|
---|
2209 | placer = new ClumpPlacer(150, 0.25, 0.1, 0.3);
|
---|
2210 | var terrainPainter = new LayeredPainter(
|
---|
2211 | [tCliff, tSand], // terrains
|
---|
2212 | [1] // widths
|
---|
2213 | );
|
---|
2214 | var elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, 16, 1);
|
---|
2215 | createAreas(placer, [terrainPainter, elevationPainter, paintClass(clHill1)],
|
---|
2216 | avoidClasses(clForest, 2, clPlayer, 0, clHill1, 16),
|
---|
2217 | (mapSize*mapSize)/3800, 100
|
---|
2218 | );
|
---|
2219 |
|
---|
2220 | log("Creating small level 1 hills...");
|
---|
2221 | placer = new ClumpPlacer(60, 0.25, 0.1, 0.3);
|
---|
2222 | terrainPainter = new LayeredPainter(
|
---|
2223 | [tCliff, tSand], // terrains
|
---|
2224 | [1] // widths
|
---|
2225 | );
|
---|
2226 | elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, 16, 1);
|
---|
2227 | createAreas(placer, [terrainPainter, elevationPainter, paintClass(clHill1)],
|
---|
2228 | avoidClasses(clForest, 2, clPlayer, 0, clHill1, 3),
|
---|
2229 | (mapSize*mapSize)/2800, 100
|
---|
2230 | );
|
---|
2231 |
|
---|
2232 | log("Creating level 2 hills...");
|
---|
2233 | placer = new ClumpPlacer(60, 0.2, 0.1, 0.9);
|
---|
2234 | terrainPainter = new LayeredPainter(
|
---|
2235 | [tCliff, tSand], // terrains
|
---|
2236 | [1] // widths
|
---|
2237 | );
|
---|
2238 | elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, 16, 1);
|
---|
2239 | createAreas(placer, [terrainPainter, elevationPainter, paintClass(clHill2)],
|
---|
2240 | [avoidClasses(clHill2, 1), new StayInTileClassConstraint(clHill1, 0)],
|
---|
2241 | (mapSize*mapSize)/2800, 200
|
---|
2242 | );
|
---|
2243 |
|
---|
2244 | log("Creating level 3 hills...");
|
---|
2245 | placer = new ClumpPlacer(25, 0.2, 0.1, 0.9);
|
---|
2246 | terrainPainter = new LayeredPainter(
|
---|
2247 | [tCliff, tSand], // terrains
|
---|
2248 | [1] // widths
|
---|
2249 | );
|
---|
2250 | elevationPainter = new SmoothElevationPainter(ELEVATION_MODIFY, 16, 1);
|
---|
2251 | createAreas(placer, [terrainPainter, elevationPainter, paintClass(clHill3)],
|
---|
2252 | [avoidClasses(clHill3, 1), new StayInTileClassConstraint(clHill2, 0)],
|
---|
2253 | (mapSize*mapSize)/9000, 300
|
---|
2254 | );
|
---|
2255 |
|
---|
2256 | // create forests
|
---|
2257 | log("Creating forests...");
|
---|
2258 | placer = new ClumpPlacer(25, 0.15, 0.1, 0.3);
|
---|
2259 | painter = new TerrainPainter([tSand, tForest]);
|
---|
2260 | createAreas(placer, [painter, paintClass(clForest)],
|
---|
2261 | avoidClasses(clWater, 0, clPlayer, 1, clForest, 20, clHill1, 0),
|
---|
2262 | (mapSize*mapSize)/4000, 50
|
---|
2263 | );
|
---|
2264 |
|
---|
2265 | // create mines
|
---|
2266 | log("Creating mines...");
|
---|
2267 | group = new SimpleGroup([new SimpleObject(oMine, 4,6, 0,2)], true, clRock);
|
---|
2268 | createObjectGroups(group, 0,
|
---|
2269 | [avoidClasses(clWater, 2, clForest, 2, clPlayer, 0, clRock, 13),
|
---|
2270 | new BorderTileClassConstraint(clHill1, 0, 4)],
|
---|
2271 | (mapSize*mapSize)/4000, 100
|
---|
2272 | );
|
---|
2273 |
|
---|
2274 | // create decorative rocks for hills
|
---|
2275 | log("Creating decorative rocks...");
|
---|
2276 | group = new SimpleGroup([new SimpleObject(aDecorativeRock, 1,1, 0,0)], true);
|
---|
2277 | createObjectGroups(group, undefined,
|
---|
2278 | new BorderTileClassConstraint(clHill1, 0, 3),
|
---|
2279 | (mapSize*mapSize)/2000, 100
|
---|
2280 | );
|
---|
2281 |
|
---|
2282 | // create deer
|
---|
2283 | log("Creating deer...");
|
---|
2284 | group = new SimpleGroup([new SimpleObject(oDeer, 5,7, 0,4)], true, clFood);
|
---|
2285 | createObjectGroups(group, 0,
|
---|
2286 | avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill1, 0, clFood, 25),
|
---|
2287 | (mapSize*mapSize)/5000, 50
|
---|
2288 | );
|
---|
2289 |
|
---|
2290 | // create sheep
|
---|
2291 | log("Creating sheep...");
|
---|
2292 | group = new SimpleGroup([new SimpleObject(oSheep, 1,3, 0,2)], true, clFood);
|
---|
2293 | createObjectGroups(group, 0,
|
---|
2294 | avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill1, 0, clFood, 15),
|
---|
2295 | (mapSize*mapSize)/5000, 50
|
---|
2296 | );
|
---|
2297 |
|
---|
2298 | // create straggler trees
|
---|
2299 | log("Creating straggler trees...");
|
---|
2300 | group = new SimpleGroup([new SimpleObject(oTree, 1,1, 0,0)], true);
|
---|
2301 | createObjectGroups(group, 0,
|
---|
2302 | avoidClasses(clWater, 0, clForest, 0, clHill1, 0, clPlayer, 0),
|
---|
2303 | mapSize*mapSize/1500
|
---|
2304 | );
|
---|
2305 |
|
---|
2306 | // create bushes
|
---|
2307 | log("Creating bushes...");
|
---|
2308 | group = new SimpleGroup([new SimpleObject(aBush, 2,3, 0,2)]);
|
---|
2309 | createObjectGroups(group, undefined,
|
---|
2310 | avoidClasses(clWater, 3, clHill1, 0, clPlayer, 0, clForest, 0),
|
---|
2311 | mapSize*mapSize/1000
|
---|
2312 | );
|
---|
2313 |
|
---|
2314 | // create bushes
|
---|
2315 | log("Creating more decorative rocks...");
|
---|
2316 | group = new SimpleGroup([new SimpleObject(aDecorativeRock, 1,2, 0,2)]);
|
---|
2317 | createObjectGroups(group, undefined,
|
---|
2318 | avoidClasses(clWater, 3, clHill1, 0, clPlayer, 0, clForest, 0),
|
---|
2319 | mapSize*mapSize/1000
|
---|
2320 | );
|
---|
2321 |
|
---|
2322 | var output = SaveMap();
|
---|
2323 |
|
---|
2324 | var endTime = dateNow();
|
---|
2325 |
|
---|
2326 | log("Processing time: "+(endTime-startTime)/1000.0+" seconds");
|
---|