152 |
153 |
154 |
155 |
169 |
182 |
183 |
--------------------------------------------------------------------------------
/arrasio/src/server/lib/hshg.js:
--------------------------------------------------------------------------------
1 | // Hierarchical Spatial Hash Grid: HSHG
2 | // https://gist.github.com/kirbysayshi/1760774
3 |
4 | (function(root, undefined){
5 |
6 | //---------------------------------------------------------------------
7 | // GLOBAL FUNCTIONS
8 | //---------------------------------------------------------------------
9 |
10 | /**
11 | * Updates every object's position in the grid, but only if
12 | * the hash value for that object has changed.
13 | * This method DOES NOT take into account object expansion or
14 | * contraction, just position, and does not attempt to change
15 | * the grid the object is currently in; it only (possibly) changes
16 | * the cell.
17 | *
18 | * If the object has significantly changed in size, the best bet is to
19 | * call removeObject() and addObject() sequentially, outside of the
20 | * normal update cycle of HSHG.
21 | *
22 | * @return void desc
23 | */
24 | function update_RECOMPUTE(){
25 |
26 | var i
27 | ,obj
28 | ,grid
29 | ,meta
30 | ,objAABB
31 | ,newObjHash;
32 |
33 | // for each object
34 | for(i = 0; i < this._globalObjects.length; i++){
35 | obj = this._globalObjects[i];
36 | meta = obj.HSHG;
37 | grid = meta.grid;
38 |
39 | // recompute hash
40 | objAABB = obj.getAABB();
41 | newObjHash = grid.toHash(objAABB.min[0], objAABB.min[1]);
42 |
43 | if(newObjHash !== meta.hash){
44 | // grid position has changed, update!
45 | grid.removeObject(obj);
46 | grid.addObject(obj, newObjHash);
47 | }
48 | }
49 | }
50 |
51 | // not implemented yet :)
52 | function update_REMOVEALL(){
53 |
54 | }
55 |
56 | function testAABBOverlap(objA, objB){
57 | var a = objA.getAABB()
58 | ,b = objB.getAABB();
59 |
60 | //if(a.min[0] > b.max[0] || a.min[1] > b.max[1] || a.min[2] > b.max[2]
61 | //|| a.max[0] < b.min[0] || a.max[1] < b.min[1] || a.max[2] < b.min[2]){
62 | if (!a.active && !b.active) return false;
63 |
64 | if(a.min[0] > b.max[0] || a.min[1] > b.max[1]
65 | || a.max[0] < b.min[0] || a.max[1] < b.min[1]){
66 | return false;
67 | } else {
68 | return true;
69 | }
70 | }
71 |
72 | function getLongestAABBEdge(min, max){
73 | return Math.max(
74 | Math.abs(max[0] - min[0])
75 | ,Math.abs(max[1] - min[1])
76 | //,Math.abs(max[2] - min[2])
77 | );
78 | }
79 |
80 | //---------------------------------------------------------------------
81 | // ENTITIES
82 | //---------------------------------------------------------------------
83 |
84 | function HSHG(){
85 |
86 | this.MAX_OBJECT_CELL_DENSITY = 1/8 // objects / cells
87 | this.INITIAL_GRID_LENGTH = 256 // 16x16
88 | this.HIERARCHY_FACTOR = 2
89 | this.HIERARCHY_FACTOR_SQRT = Math.SQRT2
90 | this.UPDATE_METHOD = update_RECOMPUTE // or update_REMOVEALL
91 |
92 | this._grids = [];
93 | this._globalObjects = [];
94 | }
95 |
96 | //HSHG.prototype.init = function(){
97 | // this._grids = [];
98 | // this._globalObjects = [];
99 | //}
100 |
101 | HSHG.prototype.addObject = function(obj){
102 | var x ,i
103 | ,cellSize
104 | ,objAABB = obj.getAABB()
105 | ,objSize = getLongestAABBEdge(objAABB.min, objAABB.max)
106 | ,oneGrid, newGrid;
107 |
108 | // for HSHG metadata
109 | obj.HSHG = {
110 | globalObjectsIndex: this._globalObjects.length
111 | };
112 |
113 | // add to global object array
114 | this._globalObjects.push(obj);
115 |
116 | if(this._grids.length == 0) {
117 | // no grids exist yet
118 | cellSize = objSize * this.HIERARCHY_FACTOR_SQRT;
119 | newGrid = new Grid(cellSize, this.INITIAL_GRID_LENGTH, this);
120 | newGrid.initCells();
121 | newGrid.addObject(obj);
122 |
123 | this._grids.push(newGrid);
124 | } else {
125 | x = 0;
126 |
127 | // grids are sorted by cellSize, smallest to largest
128 | for(i = 0; i < this._grids.length; i++){
129 | oneGrid = this._grids[i];
130 | x = oneGrid.cellSize;
131 | if(objSize < x){
132 | x = x / this.HIERARCHY_FACTOR;
133 | if(objSize < x) {
134 | // find appropriate size
135 | while( objSize < x ) {
136 | x = x / this.HIERARCHY_FACTOR;
137 | }
138 | newGrid = new Grid(x * this.HIERARCHY_FACTOR, this.INITIAL_GRID_LENGTH, this);
139 | newGrid.initCells();
140 | // assign obj to grid
141 | newGrid.addObject(obj)
142 | // insert grid into list of grids directly before oneGrid
143 | this._grids.splice(i, 0, newGrid);
144 | } else {
145 | // insert obj into grid oneGrid
146 | oneGrid.addObject(obj);
147 | }
148 | return;
149 | }
150 | }
151 |
152 | while( objSize >= x ){
153 | x = x * this.HIERARCHY_FACTOR;
154 | }
155 |
156 | newGrid = new Grid(x, this.INITIAL_GRID_LENGTH, this);
157 | newGrid.initCells();
158 | // insert obj into grid
159 | newGrid.addObject(obj)
160 | // add newGrid as last element in grid list
161 | this._grids.push(newGrid);
162 | }
163 | }
164 |
165 | HSHG.prototype.checkIfInHSHG = function(obj){
166 | var meta = obj.HSHG
167 | ,globalObjectsIndex
168 | ,replacementObj;
169 |
170 | if(meta === undefined) return false;
171 | return true;
172 | }
173 |
174 | HSHG.prototype.removeObject = function(obj){
175 | var meta = obj.HSHG
176 | ,globalObjectsIndex
177 | ,replacementObj;
178 |
179 | if(meta === undefined){
180 | throw Error( obj + ' was not in the HSHG.' );
181 | return;
182 | }
183 |
184 | // remove object from global object list
185 | globalObjectsIndex = meta.globalObjectsIndex
186 | if(globalObjectsIndex === this._globalObjects.length - 1){
187 | this._globalObjects.pop();
188 | } else {
189 | replacementObj = this._globalObjects.pop();
190 | replacementObj.HSHG.globalObjectsIndex = globalObjectsIndex;
191 | this._globalObjects[ globalObjectsIndex ] = replacementObj;
192 | }
193 |
194 | meta.grid.removeObject(obj);
195 |
196 | // remove meta data
197 | delete obj.HSHG;
198 | }
199 |
200 | HSHG.prototype.update = function(){
201 | this.UPDATE_METHOD.call(this);
202 | }
203 |
204 | HSHG.prototype.queryForCollisionPairs = function(broadOverlapTestCallback){
205 |
206 | var i, j, k, l, c
207 | ,grid
208 | ,cell
209 | ,objA
210 | ,objB
211 | ,offset
212 | ,adjacentCell
213 | ,biggerGrid
214 | ,objAAABB
215 | ,objAHashInBiggerGrid
216 | ,possibleCollisions = []
217 |
218 | // default broad test to internal aabb overlap test
219 | broadOverlapTest = broadOverlapTestCallback || testAABBOverlap;
220 |
221 | // for all grids ordered by cell size ASC
222 | for(i = 0; i < this._grids.length; i++){
223 | grid = this._grids[i];
224 |
225 | // for each cell of the grid that is occupied
226 | for(j = 0; j < grid.occupiedCells.length; j++){
227 | cell = grid.occupiedCells[j];
228 |
229 | // collide all objects within the occupied cell
230 | for(k = 0; k < cell.objectContainer.length; k++){
231 | objA = cell.objectContainer[k];
232 | if (!objA.getAABB().active) continue;
233 | for(l = k+1; l < cell.objectContainer.length; l++){
234 | objB = cell.objectContainer[l];
235 | if (!objB.getAABB().active) continue;
236 | if(broadOverlapTest(objA, objB) === true){
237 | possibleCollisions.push( [ objA, objB ] );
238 | }
239 | }
240 | }
241 |
242 | // for the first half of all adjacent cells (offset 4 is the current cell)
243 | for(c = 0; c < 4; c++){
244 | offset = cell.neighborOffsetArray[c];
245 |
246 | //if(offset === null) { continue; }
247 |
248 | adjacentCell = grid.allCells[ cell.allCellsIndex + offset ];
249 |
250 | // collide all objects in cell with adjacent cell
251 | for(k = 0; k < cell.objectContainer.length; k++){
252 | objA = cell.objectContainer[k];
253 | if (!objA.getAABB().active) continue;
254 | for(l = 0; l < adjacentCell.objectContainer.length; l++){
255 | objB = adjacentCell.objectContainer[l];
256 | if (!objB.getAABB().active) continue;
257 | if(broadOverlapTest(objA, objB) === true){
258 | possibleCollisions.push( [ objA, objB ] );
259 | }
260 | }
261 | }
262 | }
263 | }
264 |
265 | // forall objects that are stored in this grid
266 | for(j = 0; j < grid.allObjects.length; j++){
267 | objA = grid.allObjects[j];
268 | objAAABB = objA.getAABB();
269 | if (!objAAABB.active) continue;
270 | // for all grids with cellsize larger than grid
271 | for(k = i + 1; k < this._grids.length; k++){
272 | biggerGrid = this._grids[k];
273 | objAHashInBiggerGrid = biggerGrid.toHash(objAAABB.min[0], objAAABB.min[1]);
274 | cell = biggerGrid.allCells[objAHashInBiggerGrid];
275 |
276 | // check objA against every object in all cells in offset array of cell
277 | // for all adjacent cells...
278 | for(c = 0; c < cell.neighborOffsetArray.length; c++){
279 | offset = cell.neighborOffsetArray[c];
280 |
281 | //if(offset === null) { continue; }
282 |
283 | adjacentCell = biggerGrid.allCells[ cell.allCellsIndex + offset ];
284 |
285 | // for all objects in the adjacent cell...
286 | for(l = 0; l < adjacentCell.objectContainer.length; l++){
287 | objB = adjacentCell.objectContainer[l];
288 | if (!objB.getAABB().active) continue;
289 | // test against object A
290 | if(broadOverlapTest(objA, objB) === true){
291 | possibleCollisions.push( [ objA, objB ] );
292 | }
293 | }
294 | }
295 | }
296 | }
297 | }
298 |
299 | // return list of object pairs
300 | return possibleCollisions;
301 | }
302 |
303 | HSHG.update_RECOMPUTE = update_RECOMPUTE;
304 | HSHG.update_REMOVEALL = update_REMOVEALL;
305 |
306 | /**
307 | * Grid
308 | *
309 | * @constructor
310 | * @param int cellSize the pixel size of each cell of the grid
311 | * @param int cellCount the total number of cells for the grid (width x height)
312 | * @param HSHG parentHierarchy the HSHG to which this grid belongs
313 | * @return void
314 | */
315 | function Grid(cellSize, cellCount, parentHierarchy){
316 | this.cellSize = cellSize;
317 | this.inverseCellSize = 1/cellSize;
318 | this.rowColumnCount = ~~Math.sqrt(cellCount);
319 | this.xyHashMask = this.rowColumnCount - 1;
320 | this.occupiedCells = [];
321 | this.allCells = Array(this.rowColumnCount*this.rowColumnCount);
322 | this.allObjects = [];
323 | this.sharedInnerOffsets = [];
324 |
325 | this._parentHierarchy = parentHierarchy || null;
326 | }
327 |
328 | Grid.prototype.initCells = function(){
329 |
330 | // TODO: inner/unique offset rows 0 and 2 may need to be
331 | // swapped due to +y being "down" vs "up"
332 |
333 | var i, gridLength = this.allCells.length
334 | ,x, y
335 | ,wh = this.rowColumnCount
336 | ,isOnRightEdge, isOnLeftEdge, isOnTopEdge, isOnBottomEdge
337 | ,innerOffsets = [
338 | // y+ down offsets
339 | //-1 + -wh, -wh, -wh + 1,
340 | //-1, 0, 1,
341 | //wh - 1, wh, wh + 1
342 |
343 | // y+ up offsets
344 | wh - 1, wh, wh + 1,
345 | -1, 0, 1,
346 | -1 + -wh, -wh, -wh + 1
347 | ]
348 | ,leftOffset, rightOffset, topOffset, bottomOffset
349 | ,uniqueOffsets = []
350 | ,cell;
351 |
352 | this.sharedInnerOffsets = innerOffsets;
353 |
354 | // init all cells, creating offset arrays as needed
355 |
356 | for(i = 0; i < gridLength; i++){
357 |
358 | cell = new Cell();
359 | // compute row (y) and column (x) for an index
360 | y = ~~(i / this.rowColumnCount);
361 | x = ~~(i - (y*this.rowColumnCount));
362 |
363 | // reset / init
364 | isOnRightEdge = false;
365 | isOnLeftEdge = false;
366 | isOnTopEdge = false;
367 | isOnBottomEdge = false;
368 |
369 | // right or left edge cell
370 | if((x+1) % this.rowColumnCount == 0){ isOnRightEdge = true; }
371 | else if(x % this.rowColumnCount == 0){ isOnLeftEdge = true; }
372 |
373 | // top or bottom edge cell
374 | if((y+1) % this.rowColumnCount == 0){ isOnTopEdge = true; }
375 | else if(y % this.rowColumnCount == 0){ isOnBottomEdge = true; }
376 |
377 | // if cell is edge cell, use unique offsets, otherwise use inner offsets
378 | if(isOnRightEdge || isOnLeftEdge || isOnTopEdge || isOnBottomEdge){
379 |
380 | // figure out cardinal offsets first
381 | rightOffset = isOnRightEdge === true ? -wh + 1 : 1;
382 | leftOffset = isOnLeftEdge === true ? wh - 1 : -1;
383 | topOffset = isOnTopEdge === true ? -gridLength + wh : wh;
384 | bottomOffset = isOnBottomEdge === true ? gridLength - wh : -wh;
385 |
386 | // diagonals are composites of the cardinals
387 | uniqueOffsets = [
388 | // y+ down offset
389 | //leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset,
390 | //leftOffset, 0, rightOffset,
391 | //leftOffset + topOffset, topOffset, rightOffset + topOffset
392 |
393 | // y+ up offset
394 | leftOffset + topOffset, topOffset, rightOffset + topOffset,
395 | leftOffset, 0, rightOffset,
396 | leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset
397 | ];
398 |
399 | cell.neighborOffsetArray = uniqueOffsets;
400 | } else {
401 | cell.neighborOffsetArray = this.sharedInnerOffsets;
402 | }
403 |
404 | cell.allCellsIndex = i;
405 | this.allCells[i] = cell;
406 | }
407 | }
408 |
409 | Grid.prototype.toHash = function(x, y, z){
410 | var i, xHash, yHash, zHash;
411 |
412 | if(x < 0){
413 | i = (-x) * this.inverseCellSize;
414 | xHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask );
415 | } else {
416 | i = x * this.inverseCellSize;
417 | xHash = ~~i & this.xyHashMask;
418 | }
419 |
420 | if(y < 0){
421 | i = (-y) * this.inverseCellSize;
422 | yHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask );
423 | } else {
424 | i = y * this.inverseCellSize;
425 | yHash = ~~i & this.xyHashMask;
426 | }
427 |
428 | //if(z < 0){
429 | // i = (-z) * this.inverseCellSize;
430 | // zHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask );
431 | //} else {
432 | // i = z * this.inverseCellSize;
433 | // zHash = ~~i & this.xyHashMask;
434 | //}
435 |
436 | return xHash + yHash * this.rowColumnCount
437 | //+ zHash * this.rowColumnCount * this.rowColumnCount;
438 | }
439 |
440 | Grid.prototype.addObject = function(obj, hash){
441 | var objAABB
442 | ,objHash
443 | ,targetCell;
444 |
445 | // technically, passing this in this should save some computational effort when updating objects
446 | if(hash !== undefined){
447 | objHash = hash;
448 | } else {
449 | objAABB = obj.getAABB()
450 | objHash = this.toHash(objAABB.min[0], objAABB.min[1])
451 | }
452 | targetCell = this.allCells[objHash];
453 |
454 | if(targetCell.objectContainer.length === 0){
455 | // insert this cell into occupied cells list
456 | targetCell.occupiedCellsIndex = this.occupiedCells.length;
457 | this.occupiedCells.push(targetCell);
458 | }
459 |
460 | // add meta data to obj, for fast update/removal
461 | obj.HSHG.objectContainerIndex = targetCell.objectContainer.length;
462 | obj.HSHG.hash = objHash;
463 | obj.HSHG.grid = this;
464 | obj.HSHG.allGridObjectsIndex = this.allObjects.length;
465 | // add obj to cell
466 | targetCell.objectContainer.push(obj);
467 |
468 | // we can assume that the targetCell is already a member of the occupied list
469 |
470 | // add to grid-global object list
471 | this.allObjects.push(obj);
472 |
473 | // do test for grid density
474 | if(this.allObjects.length / this.allCells.length > this._parentHierarchy.MAX_OBJECT_CELL_DENSITY){
475 | // grid must be increased in size
476 | this.expandGrid();
477 | }
478 | }
479 |
480 | Grid.prototype.removeObject = function(obj){
481 | var meta = obj.HSHG
482 | ,hash
483 | ,containerIndex
484 | ,allGridObjectsIndex
485 | ,cell
486 | ,replacementCell
487 | ,replacementObj;
488 |
489 | hash = meta.hash;
490 | containerIndex = meta.objectContainerIndex;
491 | allGridObjectsIndex = meta.allGridObjectsIndex;
492 | cell = this.allCells[hash];
493 |
494 | // remove object from cell object container
495 | if(cell.objectContainer.length === 1){
496 | // this is the last object in the cell, so reset it
497 | cell.objectContainer.length = 0;
498 |
499 | // remove cell from occupied list
500 | if(cell.occupiedCellsIndex === this.occupiedCells.length - 1){
501 | // special case if the cell is the newest in the list
502 | this.occupiedCells.pop();
503 | } else {
504 | replacementCell = this.occupiedCells.pop();
505 | replacementCell.occupiedCellsIndex = cell.occupiedCellsIndex;
506 | this.occupiedCells[ cell.occupiedCellsIndex ] = replacementCell;
507 | }
508 |
509 | cell.occupiedCellsIndex = null;
510 | } else {
511 | // there is more than one object in the container
512 | if(containerIndex === cell.objectContainer.length - 1){
513 | // special case if the obj is the newest in the container
514 | cell.objectContainer.pop();
515 | } else {
516 | replacementObj = cell.objectContainer.pop();
517 | replacementObj.HSHG.objectContainerIndex = containerIndex;
518 | cell.objectContainer[ containerIndex ] = replacementObj;
519 | }
520 | }
521 |
522 | // remove object from grid object list
523 | if(allGridObjectsIndex === this.allObjects.length - 1){
524 | this.allObjects.pop();
525 | } else {
526 | replacementObj = this.allObjects.pop();
527 | replacementObj.HSHG.allGridObjectsIndex = allGridObjectsIndex;
528 | this.allObjects[ allGridObjectsIndex ] = replacementObj;
529 | }
530 | }
531 |
532 | Grid.prototype.expandGrid = function(){
533 | var i, j
534 | ,currentCellCount = this.allCells.length
535 | ,currentRowColumnCount = this.rowColumnCount
536 | ,currentXYHashMask = this.xyHashMask
537 |
538 | ,newCellCount = currentCellCount * 4 // double each dimension
539 | ,newRowColumnCount = ~~Math.sqrt(newCellCount)
540 | ,newXYHashMask = newRowColumnCount - 1
541 | ,allObjects = this.allObjects.slice(0) // duplicate array, not objects contained
542 | ,aCell
543 | ,push = Array.prototype.push;
544 |
545 | // remove all objects
546 | for(i = 0; i < allObjects.length; i++){
547 | this.removeObject(allObjects[i]);
548 | }
549 |
550 | // reset grid values, set new grid to be 4x larger than last
551 | this.rowColumnCount = newRowColumnCount;
552 | this.allCells = Array(this.rowColumnCount*this.rowColumnCount);
553 | this.xyHashMask = newXYHashMask;
554 |
555 | // initialize new cells
556 | this.initCells();
557 |
558 | // re-add all objects to grid
559 | for(i = 0; i < allObjects.length; i++){
560 | this.addObject(allObjects[i]);
561 | }
562 | }
563 |
564 | /**
565 | * A cell of the grid
566 | *
567 | * @constructor
568 | * @return void desc
569 | */
570 | function Cell(){
571 | this.objectContainer = [];
572 | this.neighborOffsetArray;
573 | this.occupiedCellsIndex = null;
574 | this.allCellsIndex = null;
575 | }
576 |
577 | //---------------------------------------------------------------------
578 | // EXPORTS
579 | //---------------------------------------------------------------------
580 |
581 | root['HSHG'] = HSHG;
582 | HSHG._private = {
583 | Grid: Grid,
584 | Cell: Cell,
585 | testAABBOverlap: testAABBOverlap,
586 | getLongestAABBEdge: getLongestAABBEdge
587 | };
588 |
589 | })(this);
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/arrasio/src/server/newserver.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /* global goog */
3 | "use strict";
4 |
5 | // General requires
6 | require('google-closure-library');
7 | goog.require('goog.structs.PriorityQueue');
8 | goog.require('goog.structs.QuadTree');
9 |
10 | // Import game settings.
11 | const c = require('../../config.json');
12 |
13 | // Import utilities.
14 | const util = require('./lib/util');
15 | const ran = require('./lib/random');
16 | const hshg = require('./lib/hshg');
17 |
18 | // Let's get a cheaper array removal thing
19 | Array.prototype.remove = index => {
20 | if(index === this.length - 1){
21 | return this.pop();
22 | } else {
23 | let r = this[index];
24 | this[index] = this.pop();
25 | return r;
26 | }
27 | };
28 |
29 | // Define player keys
30 | const keys = [
31 | 'k', 'l', 'testk', 'testl',
32 | // Focus Group
33 | 'ZNr3GBQOhD2CDDYpZD3JZkZ6hmhoF4wGiTYTikZlSLr1Z66yWKuVMitRkpUbPy6s', // Mine
34 | 'HKib09Ep3hIcwFXpiCj5iEkpLBN88HQ22hiFqg5alcxn4AYl6VcsPFTqMvllLt1D', // Parodia
35 | 'n9hx8iQH8453dWQpdDvJcAvPzQej80xQz86TxuYaJ8CaOr4hEH2zHPlSeayVPjFZ', // SGM
36 | '5piWwi06VXdEuOsz1rbcHiglurbaYIPtslIgE0NNMGQgNcqErdJ4kUVYpDJsRlVC', // Aznaft
37 | 'q80UgWYIQVM2oZW5iQO6VRdLcOTuHkSgUx4U7NN8z76Ltgj7gVc6tSWvmpPkRUGH', // Licht
38 | '9zcVcKxiv60ZoBr6CaO9ecjR3i0Mj9yx4Qgt9IGwzxps8Q5ge1GQJiYe59GBxKip', // Tenderlicious
39 | 'M67ZAZIgboiBcUtcKoHOuwXlQJWN9DEwhr0CIqR9xjiwpDyb4cUrwUIynKnuQmrU', // ManticoreKiller
40 | 'iBKZrtZEP6Gq1m1y4hpbIH2htBKegkaj6eyO70L9FMAEydiV4gA4ufiLWFx0R5C2', // JB Columbia
41 | 'zbH5Myv66HmR9Mda39xlLXa9TyBGzXnKZV7xpN5NCDTXorn52123eHY4kcZmPNLx', // Teal Knight
42 | 'pee4OZmPo9yrINv30kIMMVviEr1PRfiuIYQEOGXTK6lnLZumy9O942NabE8BiEce', // unnamed
43 | '08IhobFLBYah8Mk8MKqqG6W576iS4jznjK4WnIsSzcFC0OhkIY51DQV0DWWsgfbg', // Pie
44 | '36spA3cA2FNDamjM4SaiNNfNMkUMSERgduUvAL3Ms8bsioX4uoMyQteMWx1dRpdp', // Sergio
45 | 'i3tpmHTC2ty8CCzjhISDKO1MrkZOwmoWZ08XZLOg3IfCqbtAsdC8QPKPMhbPHQmV', // Corrupt X
46 | 'gQHpJkeGoxknxqkiX9msLhwS1NzikXa1RiOKOJD2o2zf15XL35P1YWZeMcivXLNB', // Jorjito Gamer
47 | 'kKWsRf0OdLWzipECohr5FqjuyecPZYOGxl1zAXabtllaWx2OVKfLTKBiit8KVg5j', // warrior
48 | '77L1QgQgsTQrZHhTSuv1iK1NyvpBL9AYyvmkF21Sjp4T7ldxGodQnC9dM1YtvZzG', // TTTank
49 | 'M6I9vmmRiitxg07rBG2IuC7aNpp7LHQGVPtwGfkk3hIBR0jhlWwaqzpzPXqU2awM', // CX
50 | '5AxKhPIu5jF3B3cIxjA2BHUy30ccYgEUXJmK16ksJotp9D9WVlY6QqPLDPGim1MK', // Faxaro
51 | 'kcrJTPqvhraysgCNrFZORGNR4UTMRvbQ2zuhI3iXpGyMg6wDtU5QMgcV8vNdLLHQ', // Mipha
52 | 'EXoiZYDuwSwmp7Zg0m7hdaLyv2PMbQgQorkwRznC0NC3saubVNtxVUGtOWZ2xdcz', // svorlds
53 | 'G0t2lQYeaTHHU8sp5ibNjFCCLMr41cPCOJRKUC5eUGfkUKDxpVwo5azomBSznZuR', // FTM
54 | 'kf2VcjtzpMvVwhlgIjq4MX6LWbIoNzcvfsxARS0qWiuVWf6BPPsQ2p1FgBVvNoB1', // pnvv / Cannon Man
55 | '3hO6R7AOR0aiiFuRyGaHKrgJHjTEpsD2LZ866bhvlz2Ru9AT8QmiBNf5PZuXCFIA', // wowie's friend
56 | 'z272UlNODnYVK79jva6pybRpwtp1h0FdJh8F8JRQJ5VY9lPrcugp6nd403Op4voC',
57 | 'eOb4DCk81Hzay8Kgjcu6tbbpIUCveloxahmnkmg3aU6FlvdWjJd2Uui5cFQdsnby',
58 | '9qGqNv5iYTSIhkCaMmZpvYhSpaLnHQJnj6m2gdoVWIXgLaFgIrbcFYHM8bcBsGYS',
59 | 'qqWz1E1uVtErG4N80YDVQJywzOk6PJFDrC6uzqoQ9XL2nNrCCr1KvY8XUEyCroHT',
60 | 'r0KXqfIifiavtqP3v0b5gqb5ArQY5sJWO7fjG4P6AFE5MRyfjDGK7sO7nXg23Tkv',
61 | 'nUzNolF4Yys4ua6x78GiVH0Fparcm8GyD60IZzVHji0b2gQL3citWEEi3b1J9iRT',
62 | 'XSxFurVLlc7o99nnakK5EPA2Z16tqBxP3xKcq5y4XOjRyfFRqaSxbBNRUtab71FH',
63 | 'uYLfr6k6wEmgMtGVna366Gujor3gUWhWUHgbsz2uUNhQ8OKkwzb1IpDehnz7dfFL',
64 | 'TVA4eYx29geFN6kb2Osyt5veaih0OOJG2MzB4qBBlUQr5CpRJqIhrTModxcT5NXI',
65 | 'eyQqQE0h0l6x7XpkXpnZdYPsRJgvdl6L8xAoEzF0ZGlTV8HH0wUePj03LuULDhSN',
66 | 'ZuOzwoZw4lCWwekTMh9bEAw4Tv92uLhzGN0DMDV2Rk7Sfn3Hsbf87ssHcvxTbDek',
67 |
68 | // Public
69 | 'PUBLICRSUZbhCMu2ocDrhtje1ev6ff3eM6IxsCPUBLIC',
70 | 'PUBLICb7HbKa0zFp5PzJVkcu17GIbp56JeHxZlPUBLIC',
71 | 'PUBLICwxTybWuUrYfEA84kVunN5btV4vROYCW0PUBLIC',
72 | 'PUBLICfOKBjTZzW1VvoEfJTY3G7U2TcwT8iREyPUBLIC',
73 | 'PUBLICKKRLO0lpLy2IDHUdqzE0MBsZUhrBnYRpPUBLIC',
74 | 'PUBLICsC7wKFQ6CXPB241uA5RzORP2Z14CSO86PUBLIC',
75 | 'PUBLIC6criSrXdLBoTtIWQHCmcOPfzqgDZcGOiPUBLIC',
76 | 'PUBLIC3QdiZpPEAtB4gif0TEU3822qJz3W23J2PUBLIC',
77 | 'PUBLICEDZLxLjRRfa8tS5EqRIExtHpWq0MJSVZPUBLIC',
78 | 'PUBLIC5vmCtP1IjDnglKJk7AmWg3hAuZ4ZGGnVPUBLIC',
79 | 'PUBLICe1r6NsdjhOnpNuPqnskTzLvJoaXn3dsqPUBLIC',
80 | 'PUBLICTbfzA0MB2H6hRataGEQENmu1o9eOpytkPUBLIC',
81 | 'PUBLICpJlxtdn2iplYuIWXznUX3f6RHHPC3uFrPUBLIC',
82 | 'PUBLICadVvUN4mp0MTSAnsc3BKIJ6l40Y5sV00PUBLIC',
83 |
84 | 'TRUSTED5vmCtP1IjDnglKJk7sAmWg3hAuZ4ZGGnVTRUSTED',
85 | 'TRUSTEDe1r6NsdjhOnpNuPqnskTfzLvJoaXn3dsqTRUSTED',
86 | 'TRUSTEDTbfzA0MB2H6hRataGE3QENmu1o9eOpytkTRUSTED',
87 | 'TRUSTEDpJlxtdn2iplYuIWXsznUX3f6RHHPC3uFrTRUSTED',
88 | 'TRUSTEDadVvUN4mp0MTSAnsc3BKfIJ6l40Y5sV00TRUSTED',
89 | 'TRUSTED3nYR28Kwhnx1n6JvP4Tm r2dxLhrTvrcNTRUSTED',
90 | 'TRUSTEDNwHIdUtjLSmITUVNg5B6c4uVWiB7IFq2STRUSTED',
91 | 'TRUSTEDDIIocNBJS9mYstVFSuiwNxbQeEXOFlrPhTRUSTED',
92 | 'TRUSTED17rtKXqQ7wzek6Ejf9rGCfOdRr5vrm5AxTRUSTED',
93 | 'TRUSTEDWJkuJFZ2Wljq2WXasxHrM0Vsbra5iyb6vTRUSTED',
94 | 'TRUSTEDzxVdPsuU1yGRQrkbADH6rBaE8TKdAvJabTRUSTED',
95 | 'TRUSTED7nAZ3NBi9ZB07KfLV0cnGO0YEXoSGf1lLTRUSTED',
96 | 'TRUSTEDFyJTLBCrokyoFICQFi4hAGJd09jkCDqOJTRUSTED',
97 | 'TRUSTEDPBHbBZkW9foaXPDfGe6xq9Y6XvJhrwowqTRUSTED',
98 | 'TRUSTEDtTZe5CYcmmCQBLj0WztAHn5MnI0dhqNrXTRUSTED',
99 |
100 | 'GUDPOSTERNwR7FWcY1eeNkyiCrzGfuo3wGWhETFmbGUDPOSTER',
101 | 'GUDPOSTERR2gdw10L7u4auP3yr1G1EC59TnRA3H31GUDPOSTER',
102 | 'GUDPOSTERVLX8LwHtMrLIMFx0XdzTdauVAmSKV9SZGUDPOSTER',
103 | 'GUDPOSTER8Uk4cGa2ut3vFfaPmjbmRBtAXpFHXsBNGUDPOSTER',
104 | 'GUDPOSTERdHHy9pqMejwGZJ7nUZMRw0Mnc1g8UJ8oGUDPOSTER',
105 | 'GUDPOSTERrgZPXqFSJXdChEMvgQjjxjGZfsObOArCGUDPOSTER',
106 | 'GUDPOSTERysJI3BfzB2cRCDDdFkAaFWxZk5TNHwfvGUDPOSTER',
107 | 'GUDPOSTERlFps80nCJ6cnFGjyH9QoKqgETwGX1sIQGUDPOSTER',
108 | 'GUDPOSTERmED6CZg213gXoCYyDqxMLGFtuuCPn8NmGUDPOSTER',
109 | 'GUDPOSTERlSL92YPpoqh48GuQwydpGuocJAH6Vx5VGUDPOSTER',
110 |
111 | 'GIVEAWAYZ1yVvobK3MWgCBxYjFheJd3UrWW2ULJuGIVEAWAY',
112 | 'GIVEAWAYaVGcMBm3LwxmLkxxGSt6NNg9AUDsj5v5GIVEAWAY',
113 | 'GIVEAWAYAMkJmX3xKv3tiieS5oAfEsJbni4xInIwGIVEAWAY',
114 | 'GIVEAWAYi3AbdptFr9m2fGGqY9p6Vvi3uRX6ALHRGIVEAWAY',
115 | 'GIVEAWAYxwABlNSPU4291UJICWyeXQB4ET0ZyA0uGIVEAWAY',
116 | 'GIVEAWAYczPSwYnpHDGKaimREjN1e86N6CmSH0NWGIVEAWAY',
117 | 'GIVEAWAYDx3U7MOBNyDmjv6Rz6Le6wgG4Xk0cwilGIVEAWAY',
118 | 'GIVEAWAYCOr2yK7od6RRch52ToBO5s0xxizBVVajGIVEAWAY',
119 | 'GIVEAWAYV7fiIzckU8xQ57i3Bu8ngWetPOzS9ktvGIVEAWAY',
120 | 'GIVEAWAYpbo21yNoMcvwhbIeMOsqMIjzYKOLZyEgGIVEAWAY',
121 |
122 | // Twitter
123 | '500kBomberContestTokenVUBefeRUMQsLShjas4dhfSF',
124 | '500kBomberContestTokenNSEefeRUMQsLShjbs4dhfSF', // TnT
125 | '500kBomberContestTokenWDWefeRUMQsLShjcs4dhfSF', // crnz
126 | '500kPoacherContestTokenZZb1FkYER7B0ZV7bs9df8s',
127 | '500kAutoDoubleContestTokenKBSj41qloynOGws87X2', // JeShAn
128 | '500kFortressContestTokenl2fd42tL7C6ZynSDF33ox', // Lucario
129 | // Youtube
130 | 'SGMTokenGiveaway51NP3JOh9NKvsnVh6PDRGI1wALGXWLzE2jZXztWKxlyPN00w',
131 | 'SGMTokenGiveaway2puyw4VGFTTSqgxeFvvvqxMTzZ5S3XPtVQXLCSIOpW7Rxv8m',
132 | 'SGMTokenGiveawayYAu4abk9oLMaBqOXfx2QvSqznNqw7mTFv7lBFk5LJ7ksPd7W',
133 | 'SGMTokenGiveawaybgSA5xNNpo4Vhsfg8lOlop8f4FOPWk9VXcMvjl62JYWhKOWF',
134 | 'SGMTokenGiveawaya7C7vBTBPxgWEgg1g3UbYttE30A33aFVqEEd2pdV3PfbxvA0',
135 | 'SGMTokenGiveawayBFu7eKC22KxKYuFiUTOyjmMCpBhr1HseP7pNo4yl5xOZt9IS',
136 | 'SGMTokenGiveawayAHVq7eEAUWZzCtK4vcHslWIDMPykPAfsnq4jdsHYE3HIhlBO',
137 | 'SGMTokenGiveawayS0wxtOYFcnBirWbbP9EePvgo8rPVrhatpixkaH78CdKdtorr',
138 | 'SGMTokenGiveaway7p8JwRnATdS3H10gIKy5dKQXlbj93WplkC9NpfjNTREG9IQn',
139 | 'SGMTokenGiveawaynM1ffqsEM31Vv6KMmlxhs6Ug0s65FiyN3w9eP6QM7FmpbS2i',
140 |
141 | 'SGMTokenAa05Q1oDwf0Mxaw57vBTBPX3M25gjitRD0daHTObk796GqSJ3KUhKf5p',
142 | 'SGMTokenxg3Kw7jPUoxFOXbO4POF19iovCUnNzqoQ9XL2rTAoXoAtyHDZR5YFgAk',
143 | 'SGMToken7KteCaOERDa8TkfzIQIm54rhewlKL2lWIDMPykPAfsnq41MGxgogphB9',
144 |
145 | 'OMTokenIGnPS8RSGiP8lvTQDdve9ANPfSOyTgvPQMYdFlcn7IVcJg8oeGreEBYs',
146 | 'OMTokenLTARU3UJldlHUf8215Wg4AbdThRvA3j0wG2FbwyZCTixkaH78CdK8BnV',
147 | 'OMToken7sOXlNs9Qu58TmaCu9TpD4JkzRuGrKKOS74tZimimR8Iu5du7v6GRbRH',
148 |
149 | 'JBColombiaTokenwZXpYskkovgQL4jZlqS42xaqgVAvHZPZgVcccsBkHhsXhq69',
150 | 'JBColombiaToken8WwiA5demyL1gQZ9D5kvFMOwkJRc3STikct22cMoPmjfli69',
151 | 'JBColombiaTokenPDuZydKLePKQ9TyOMqiquI0YVHcCJBJb3pORyzfo42nHhT69',
152 | 'JBColombiaTokeniC0Eh8jMoncX4bAKbslR174tZimimBXoUGhvaKY0dBwbLI69',
153 | 'JBColombiaTokenWWqX44i7VqxtQB3qsViJHbJnK3FryxqgAAFerRFxYO2wJc69',
154 | 'JBColombiaTokenlzgPyfwuto7KY8BqxDserADmpeuMR31wxgD0dWpNWvHZv969',
155 |
156 | 'SMTokenlSrBG8RTazOHzZ6zeyBPFI1tOSiuDSJNcfozraRKb8votLtwmNFC964KG',
157 | 'SMTokennrNg7MzqzJe2xz11cKDETqCBKVhDiOS6x1gyTMV8EHLkRGGFXAHLUVUjk',
158 | 'SMTokenfjlzipOhA8Lfp38kt9FnzGKRg6g79hujlFVPbEyzsbEqbYOD2ohveMSh8',
159 | 'SMTokenNHPtbYKUDrR8MBQoQIymCwdbFSoHHNTuBMPvS4iugQigBMvfrGurB3qM4',
160 | 'SMTokenI33BqYnppCCVAMOkykIeOWIsmetgkymFK1A7XgeZGGW52xVq1xRKv38vC',
161 | 'SMTokenHxNBGJGRf6SqXAOIhgMEOuPUp4X4LszwBEeco3Wrw2IuOe3jxoWyLKdR0',
162 | 'SMTokennjophXq0WC3jzDpPrDbfXLE2eoFOMvQWKucR0ZwECIlXDBTQnF33uyDXd',
163 | // Patreon / rewards
164 | 'tokenlordkarma88tokenlordkarma88tokenlordkarma88tokenlordkarma88',
165 | 'hereIsUrTokenBuddyThxForTheOverGunnerLmao',
166 | 'DukeonkledDukeonkleThankYouSoMuch123e911DukeonkledDukeonkledDuke',
167 | 'FireNationFireNationThanksATon018s380280FireNationFireNationFire',
168 |
169 | 'rewardTokenJSdf323H0Cj85aVOG3SPlgp7Y9BuBoFcwpmNFjfLEDQhOFTIpukdr', // Call
170 | 'rewardTokenDg2JDTp0rxDKXIPE8PHcmdHqWyH2CqPqpcAf6QcT8m2hgBZnJ7KHE',
171 | 'rewardTokenad3JTsTwuVLkQvfmVH2d2Ukbf8WbFuPBqTpYFdFx9AuZEnmv9EW8U',
172 | 'rewardTokenJsa43Tthn1M5Ey9oDRODzzrazqRxL28cTchgInjVCrSfnWEATdYeP',
173 | 'rewardTokensdfsJTyz2YMS3GLDfD2NvqXK46p1ScsmdLxI1owBkjHw983lwkR8Z',
174 | // Wiki
175 | 'WIKIREWARDV7V0bZRP8lM3fUvwuAX7DC5FpZCU1AyJByaulkH9YHZ7WIKIREWARD',
176 | 'WIKIREWARDDOE8Iqg5K124sNXSR51WWycmCnFtCLjyF7uole5sgQgoWIKIREWARD',
177 | 'WIKIREWARD5z5xXA0flzxeRgGu6EjSWlOq23gdGoYALClfsUT143Y9WIKIREWARD',
178 | 'WIKIREWARD4DTEvdwSBKPBRCAJxeS9surL09uzxx33gAHmMYFldRsMWIKIREWARD',
179 | 'WIKIREWARDqGXxMucMJcSeqWFcAfCLVNStnmOezkzOUot8xbfpCuk1WIKIREWARD',
180 | 'EDITOR1eKAAURvtnHYFuUz6dzPqOwPt6SFWbacEucDnm8KroabolnzLZrdEDITOR',
181 | 'EDITOR38Gi67EFmLdh6nXuKqtRc79HKk34c6bQl08tbUeZlGcxBS2c350yEDITOR',
182 | 'EDITOR7mAKjd6XYprdtvbWqqUjEEfCqomx67aLSyG70eiFuvRVv2Eest27EDITOR',
183 | 'EDITORoNzv0DxKzLYY7YCYdIsRHdNz8DNNiuqI2I9mBM2blBpWZ39chumsEDITOR',
184 | 'EDITOR399V1FLGtsne5BMg5QfeeHdR63bxkV51Av0ET3F5y92q7EMhI8R3EDITOR',
185 | 'EDITORmUJbmoFVshllWIUb11kyXxQfyESa4t3SYcGRHSlWzLrzfwkHCIVUEDITOR',
186 | // Themes
187 | 'YouAreTheCreatorOfBadlands',
188 | 'WowYouMadeADopeFishyTheme',
189 | 'ThanksForHelpingPlantAForest',
190 | 'MidnightIsSuperCoolNotYouTheTheme',
191 | 'DrinkBleachPlz',
192 | 'FrostyAndBeautifulJustLikeYourColdHeart',
193 | ];
194 |
195 | // Get class definitions and index them
196 | const Class = (() => {
197 | const def = require('./lib/definitions');
198 | let i = 0;
199 | for (let k in def) {
200 | if (!def.hasOwnProperty(k)) continue;
201 | def[k].index = i++;
202 | }
203 | return def;
204 | })();
205 |
206 | const ROOMSPEED = 1;
207 | // Define entities
208 | const makeEntity = (() => {
209 | // Pooled memory
210 | const __a = {
211 | int: [],
212 | float: [],
213 | str: [],
214 | };
215 | // Shared math functions
216 | const getLength = (x, y) => {
217 | return Math.sqrt(x * x + y * y);
218 | };
219 | const getDirection = (x, y) => {
220 | return Math.atan2(y, x);
221 | };
222 | const DEGTORAD = Math.PI / 180;
223 | // The value loader
224 | const load = (fallback, val) => { return (val == null) ? fallback : val; };
225 | // A status container creator
226 | const newStatusBox = (() => {
227 | const attribute = (status, id, index, inital) => {
228 | status[index] += id * inital;
229 | return {
230 | get: () => { return status[index] & id; },
231 | set: bool => {
232 | if (bool) status[index] = status[index] | id;
233 | else status[index] = status[index] & ~id;
234 | },
235 | };
236 | };
237 | return () => {
238 | let status = [0];
239 | return {
240 | ghost: attribute(status, 1, 0, false),
241 | inGrid: attribute(status, 2, 0, false),
242 | invuln: attribute(status, 4, 0, false),
243 | };
244 | };
245 | })();
246 | // A kills container creator
247 | const newKillBox = () => {
248 | let data = [0, 0, 0];
249 | return {
250 | get: data.slice,
251 | addSolo: () => data[0]++,
252 | addAssist: () => data[1]++,
253 | addBoss: () => data[2]++,
254 | };
255 | };
256 | // A health bar creator
257 | const healthTypes = (() => {
258 | // Static-type functions
259 | const regenerateStatic = (data, boost) => {
260 | const amount = data[0], max = data[1];
261 | data[0] += max / 10 / 60 / 2.5 + boost;
262 | data[0] = Math.min(data[0], max);
263 | };
264 | const getStaticDamage = (data, amount, capped) => {
265 | return capped ? Math.min(amount, data[0]) : amount;
266 | };
267 | // Dynamic-type functions
268 | const regenerateDynamic = (data, boost) => {
269 | const amount = data[0], max = data[1], regen = data[2];
270 | const r = util.clamp(amount / max, 0, 1);
271 | if (!r) data[0] = 0.0001;
272 | else if (r === 1) data[0] = max;
273 | else {
274 | data[0] += regen * Math.exp(-50 * Math.pow(Math.sqrt(0.5 * r) - 0.4, 2)) / 3 + r * max / 10 / 15 + boost;
275 | data[0] = Math.min(data[0], max);
276 | }
277 | };
278 | const getDynamicDamage = (data, amount, capped) => {
279 | const permeability = data[1] ? util.clamp(data[0] / data[1], 0, 1) : 0;
280 | return (capped) ?
281 | Math.min(amount * permeability, data[0]) :
282 | amount * permeability;
283 | };
284 | // Shared functions
285 | const getRatio = data => {
286 | return data[1] ? util.clamp(1 - Math.pow(data[0] / data[1] - 1, 4), 0, 1) : 0;
287 | };
288 | return {
289 | newStatic: () => {
290 | var data = [1.0, 0.0];
291 | return {
292 | dealDamage: amount => data[0] -= getStaticDamage(data, amount, 1),
293 | getAmount: () => { return data[0]; },
294 | getDisplay: () => { return data[0] / data[1]; },
295 | getRatio: () => { return getRatio(data); },
296 | getDamage: (amount, capped) => { return getStaticDamage(data, amount, capped); },
297 | regenerate: boost => regenerateStatic(data, boost),
298 | };
299 | },
300 | newDynamic: () => {
301 | var data = [0.0, 0.0, 0.0];
302 | return {
303 | dealDamage: amount => data[0] -= getDynamicDamage(data, amount, 1),
304 | getAmount: () => { return data[0]; },
305 | getDisplay: () => { return data[0] / data[1]; },
306 | getRatio: () => { return getRatio(data); },
307 | getDamage: (amount, capped) => { return getDynamicDamage(data, amount, capped); },
308 | regenerate: boost => regenerateDynamic(data, boost),
309 | };
310 | },
311 | };
312 | })();
313 | // The skills container creator
314 | // Index references
315 | const skc = {
316 | rld: 0,
317 | pen: 1,
318 | str: 2,
319 | dam: 3,
320 | spd: 4,
321 | shi: 5,
322 | atk: 6,
323 | hlt: 7,
324 | rgn: 8,
325 | mob: 9,
326 | accel: 10,
327 | rst: 11,
328 | brst: 12,
329 | ghost: 13,
330 | };
331 | const newSkills = (() => {
332 | // The big update method
333 | const update = (() => {
334 | // Some math functions
335 | const apply = (f, x) => { return (x<0) ? 1 / (1 - x * f) : f * x + 1; };
336 | const curves = (() => {
337 | const make = x => { return Math.log(4*x + 1) / Math.log(5); };
338 | let length = c.MAX_SKILL*2;
339 | let storedValues = new Array(length);
340 | for (let i=0; i {
344 | // Reset it if it's past the cap
345 | for (let i=0; i<10; i++) {
346 | if (data.raw[i] > data.caps[i]) {
347 | data.points += data.raw[i] - data.caps[i];
348 | data.raw[i] = data.caps[i];
349 | }
350 | }
351 | // Refresh all the stuff
352 | // Bullet stats
353 | data.real[skc.rld] = Math.pow(0.5, curves[data.raw[skc.rld]]);
354 | data.real[skc.pen] = apply(2.5, curves[data.raw[skc.pen]]);
355 | data.real[skc.str] = apply(2, curves[data.raw[skc.str]]);
356 | data.real[skc.dam] = apply(3, curves[data.raw[skc.dam]]);
357 | data.real[skc.spd] = 0.5 + apply(1.5, curves[data.raw[skc.spd]]);
358 | // Misc bullet stats
359 | data.real[skc.accel] = apply(0.5, curves[data.raw[skc.rld]]);
360 | data.real[skc.rst] = 0.5 * curves[data.raw[skc.str]] + 2.5 * curves[data.raw[skc.pen]];
361 | data.real[skc.ghost] = curves[data.raw[skc.pen]];
362 | // Body stats
363 | data.real[skc.shi] = c.GLASS_HEALTH_FACTOR * apply(3 / c.GLASS_HEALTH_FACTOR - 1, curves[data.raw[skc.shi]]);
364 | data.real[skc.atk] = apply(1, curves[data.raw[skc.atk]]);
365 | data.real[skc.hlt] = c.GLASS_HEALTH_FACTOR * apply(2 / c.GLASS_HEALTH_FACTOR - 1, curves[data.raw[skc.hlt]]);
366 | data.real[skc.mob] = apply(0.8, curves[data.raw[skc.mob]]);
367 | data.real[skc.rgn] = apply(25, curves[data.raw[skc.rgn]]);
368 | // Misc body stats
369 | data.real[skc.brst] = 0.3 * (0.5 * curves[data.raw[skc.atk]] + 0.5 * curves[data.raw[skc.hlt]] + curves[data.raw[skc.rgn]]);
370 | };
371 | })();
372 | // Modification methods
373 | const change = (data, index, levels) => {
374 | if (data.points && data.raw[index] < data.caps[index]) {
375 | data.raw[index] += levels;
376 | update(data);
377 | }
378 | };
379 | const set = (data, values) => {
380 | for (let i=0; i<10; i++) {
381 | data.raw[i] = values[i];
382 | }
383 | update(data);
384 | };
385 | const setCaps = (data, values) => {
386 | for (let i=0; i<10; i++) {
387 | data.caps[i] = values[i];
388 | }
389 | update(data);
390 | };
391 | const maintain = (() => {
392 | const levelToPoint = (() => {
393 | const templevelers = [
394 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
395 | 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
396 | 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
397 | 31, 32, 33, 34, 35, 36, 38, 40, 42, 44,
398 | ];
399 | // Generate the real level array check thingy
400 | const levelers = new Array(c.SKILL_CAP);
401 | for (let i=0; i {
405 | let tempArray = [];
406 | for (let i=0; i {
411 | if (data.level < c.SKILL_CAP) {
412 | let didStuff = false;
413 | while (data.score - data.deduction >= levelToScore[data.level]) {
414 | data.deduction += levelToScore[data.level];
415 | data.level++;
416 | data.points += levelToPoint[data.level];
417 | data.canUpgrade = data.canUpgrade || data.level == c.TIER_1 || data.level == c.TIER_2 || data.level == c.TIER_3;
418 | didStuff = true;
419 | }
420 | if (didStuff) {
421 | update(data);
422 | return 1;
423 | }
424 | }
425 | return false;
426 | };
427 | })();
428 | const returnSkills = data => {
429 | for (let i=0; i<10; i++) {
430 | __a.int[i] = data.raw[i];
431 | }
432 | return __a.int;
433 | };
434 | return () => {
435 | const data = {
436 | raw: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
437 | caps: [c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL,
438 | c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL],
439 | real: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
440 | points: 0,
441 | score: 0,
442 | deduction: 0,
443 | level: 0,
444 | canUpgrade: false,
445 | };
446 | return {
447 | change: (index, levels) => change(data, index, levels),
448 | update: () => update(data),
449 | set: values => set(data, values),
450 | setCaps: values => setCaps(data, values),
451 | maintain: () => maintain(data),
452 | get: () => returnSkills(data),
453 | };
454 | };
455 | })();
456 | // A gun
457 | const newGun = (() => {
458 | const live = (() => {
459 | const doRecoil = gun => {
460 | let motion = gun.physics[0], position = gun.physics[1];
461 | if (motion || position) {
462 | position += motion;
463 | motion -= 0.25 * position / ROOMSPEED;
464 | if (motion > 0) motion *= 0.75;
465 | }
466 | if (gun.settings.canShoot.get() && gun.settings.hasNoRecoil.get()) {
467 | if (motion > 0) gun.body.accelerate(
468 | -position * gun.physics[2] /*trueRecoil*/ * 0.045 / ROOMSPEED,
469 | gun.body.facing + gun.mechanics.angle
470 | );
471 | }
472 | gun.physics[0] = motion; gun.physics[1] = position;
473 | };
474 | const doLive = (() => {
475 | // The shooting function
476 | const fire = (() => {
477 | const bulletInit = (() => {
478 | const interpret = (() => {
479 | const out = {
480 | SPEED: 0.0,
481 | HEALTH: 0.0,
482 | RESIST: 0.0,
483 | DAMAGE: 0.0,
484 | PENETRATION: 0.0,
485 | RANGE: 0.0,
486 | DENSITY: 0.0,
487 | PUSHABILITY: 0.0,
488 | HETERO: 0.0,
489 | };
490 | return gun => {
491 | const shoot = gun.properties.settings;
492 | const sk = gun.body.getSkills();
493 | // Defaults
494 | out.SPEED = shoot.maxSpeed * sk[skc.spd];
495 | out.HEALTH = shoot.health * sk[skc.str];
496 | out.RESIST = shoot.resist + sk[skc.rst];
497 | out.DAMAGE = shoot.damage * sk[skc.dam];
498 | out.PENETRATION = Math.max(1, shoot.pen * sk[skc.pen]);
499 | out.RANGE = shoot.range / Math.sqrt(sk[skc.spd]);
500 | out.DENSITY = shoot.density * sk[skc.pen] * sk[skc.pen];
501 | out.PUSHABILITY = 1 / sk[skc.pen];
502 | out.HETERO = 3 - 2.8 * sk[skc.ghost];
503 | // Special cases
504 | switch (gun.properties.calculator) {
505 | case 0: break;
506 | case 5: // THRUSTER
507 | gun.physics[3] = shoot.recoil * Math.sqrt(sk[skc.rld] * sk[skc.spd]);
508 | break;
509 | case 6: // SUSTAINED
510 | out.RANGE = shoot.range;
511 | break;
512 | case 3: // SWARM
513 | out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (sk[skc.pen] - 1) + 1));
514 | out.HEALTH /= shoot.pen * sk[skc.pen];
515 | break;
516 | case 8: // TRAP
517 | out.PUSHABILITY = 1 / Math.pow(sk[skc.pen], 0.5);
518 | out.RANGE = shoot.range;
519 | break;
520 | case 7: // NECRO
521 | case 2: // DRONE
522 | out.PUSHABILITY = 1;
523 | out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (sk[skc.pen] - 1) + 1));
524 | out.HEALTH = (shoot.health * sk[skc.str]) / Math.pow(sk[skc.pen], 0.8);
525 | out.DAMAGE = shoot.damage * sk[skc.dam] * shoot.pen * sk[skc.pen];
526 | out.RANGE = shoot.range;
527 | break;
528 | }
529 | // Go through and make sure we respect its natural properties
530 | for (let property in out) {
531 | if (gun.properties.bullet.stat[property] == null || !out.hasOwnProperty(property)) continue;
532 | out[property] *= gun.properties.bullet.stat[property];
533 | }
534 | return out;
535 | };
536 | })();
537 | const necroFunction = (gun, mancer, host) => {
538 | const body = gun.body, props = gun.properties;
539 | const reloadFactor = body.getSkills()[0];
540 | const permission = props.countsOwnKids ?
541 | props.countsOwnKids > gun.children.length * reloadFactor :
542 | body.getMaxChildren() ?
543 | body.getMaxChildren() > body.getKids() * reloadFactor :
544 | true;
545 | if (permission) {
546 | __a.float[0] = host.getFacing();
547 | __a.float[1] = host.getSize();
548 | // Reset it as much as possible
549 | host.define(Class.genericEntity);
550 | // Turn it
551 | bulletInit(gun, host);
552 | // Init it with stuff
553 | host.setTeam(mancer.getTeam());
554 | host.setMaster(mancer.getMaster());
555 | host.setColor(mancer.getBulletColor());
556 | host.setFacing(__a.float[0]);
557 | host.setSize(__a.float[1]);
558 | host.fullHeal();
559 | return true;
560 | }
561 | return false;
562 | };
563 | return (gun, o) => {
564 | const body = gun.body, props = gun.properties;
565 | // Define it by its natural properties
566 | props.bullet.types.forEach(type => o.define(type));
567 | // Pass the gun attributes
568 | o.define({
569 | BODY: interpret(gun),
570 | SIZE: body.size * gun.mechanics.width * props.settings.size / 2 ,
571 | LABEL: this.master.label + (props.label === '' ? '' : ' ' + props.label) + ' ' + o.getLabel(),
572 | });
573 | o.setColor(body.getBulletColor());
574 | // Prepare to pass gun skills
575 | let skill = body.getSkills();
576 | skill[5] = skill[6] = skill[7] = skill[8] = skill[9] = 0;
577 | o.assignSkills(skill);
578 | // Keep track of it and give it the function it needs to remove itself upon death
579 | gun.children.push(o);
580 | o.addDerefFunction(() => util.remove(gun.children, gun.children.indexOf(o)));
581 | if (body.getMaxChildren()) {
582 | body.addChild(o);
583 | }
584 | o.addDerefFunction((() => body.removeChild(o)));
585 | // Set the source
586 | o.setSource(body);
587 | // Necromancers' bullshit
588 | if (props.calculator === 7) o.necro = host => necroFunction(gun, o, host);
589 | // Otherwise
590 | o.refreshBodyAttributes();
591 | o.life();
592 | };
593 | })();
594 | return (gun, x, y, ddd) => {
595 | const body = gun.body, props = gun.properties, physics = gun.physics, mech = gun.mechanics;
596 | const sk = body.getSkills();
597 | // Recoil
598 | gun.lastShot[0] = util.time();
599 | gun.lastShot[1] = 3 * Math.log(Math.sqrt(sk[skc.spd]) + physics[3] + 1) + 1;
600 | physics.motion += gun.lastShot[1];
601 | // Find inaccuracy
602 | let ss, sd;
603 | do {
604 | ss = ran.gauss(0, Math.sqrt(props.settings.shudder));
605 | } while (Math.abs(ss) >= props.settings.shudder * 2);
606 | do {
607 | sd = ran.gauss(0, props.settings.spray * props.settings.shudder);
608 | } while (Math.abs(sd) >= props.settings.spray / 2);
609 | sd *= Math.PI / 180;
610 | // Find speed
611 | const speed = (props.negRecoil ? -1 : 1) * props.settings.speed * c.runSpeed * sk[skc.spd] * (1 + ss);
612 | let sx = speed * Math.cos(mech.angle + body.facing + sd),
613 | sy = speed * Math.sin(mech.angle + body.facing + sd);
614 | // Boost it if we should
615 | let velocity = body.getVelocity();
616 | let vlen = getLength(velocity[0], velocity[1]);
617 | if (vlen) {
618 | let slen = getLength(sx, sy);
619 | let extraBoost =
620 | Math.max(0, sx * velocity[0] + sy * velocity[1]);
621 | if (extraBoost) {
622 | extraBoost /= slen * slen;
623 | sx += extraBoost * sx;
624 | sy += extraBoost * sy;
625 | }
626 | }
627 | // Create the bullet
628 | const position = body.getPosition(), size = body.getSize();
629 | const o = makeEntity(
630 | position[0] + size * x - sx,
631 | position[1] + size * y - sy
632 | );
633 | o.shove(sx, sy);
634 | o.forceSizeUpdate();
635 | bulletInit(gun, o);
636 | };
637 | })();
638 | // The actual update function
639 | return gun => {
640 | // Live
641 | const body = gun.body, props = gun.properties, physics = gun.physics, mech = gun.mechanics;
642 | const sk = body.getSkills();
643 | // Decides what to do based on child-counting settings
644 | let permission = (props.countsOwnKids ?
645 | props.countsOwnKids > gun.children.length * (props.calculator === 7 ? sk[0] : 1) :
646 | body.getMaxChildren() ? body.getKids().length * (props.calculator === 7 ? sk[0] : 1) :
647 | true) && !body.isInvulnurable();
648 | // Cycle up if we should
649 | if (permission || !props.waitToCycle && physics.cycle < 1)
650 | physics.cycle += 1 / props.settings.reload / ROOMSPEED / ((props.calculator === 7 || props.calculator === 4) ? 1 : sk[skc.rld]);
651 | // Firing routines
652 | if (permission && physics.cycle >= 1 && (props.autofire || (props.altFire ? body.controls.alt.get() : body.controls.fire.get()))) {
653 | // Find the end of the gun barrel
654 | const gx =
655 | mech.offset * Math.cos(mech.direction + mech.angle + body.facing) +
656 | (1.5 * mech.length - mech.width * props.settings.size / 2) * Math.cos(mech.angle + body.facing);
657 | const gy =
658 | mech.offset * Math.sin(mech.direction + mech.angle + body.facing) +
659 | (1.5 * mech.length - mech.width * props.settings.size / 2) * Math.sin(mech.angle + body.facing);
660 | // Shoot, multiple times in a tick if needed
661 | while (permission && physics.cycle >= 1) {
662 | fire(gun, gx, gy, sk);
663 | // Figure out if we may still shoot
664 | permission = props.countsOwnKids ?
665 | props.countsOwnKids > gun.children.length * (props.calculator === 7 ? sk[0] : 1) :
666 | body.getMaxChildren() ? body.getKids().length * (props.calculator === 7 ? sk[0] : 1) :
667 | true;
668 | // Cycle down
669 | physics.cycle -= 1;
670 | } // If we're not shooting, only cycle up to where we'll have the proper firing delay
671 | } else if (physics.cycle > !props.waitToCycle - mech.delay) physics.cycle = !props.waitToCycle - mech.delay;
672 | };
673 | })();
674 | // The life function
675 | return gun => {
676 | doRecoil(gun);
677 | doLive(gun);
678 | };
679 | })();
680 | const getTracking = gun => {
681 | const speed = gun.body.getSkills()[skc.spd];
682 | __a.float[0] = c.runSpeed * speed * gun.properties.settings.maxSpeed * gun.properties.bullet.stats.SPEED;
683 | __a.float[1] = speed * gun.properties.settings.range * gun.properties.bullet.stats.RANGE;
684 | return __a.float;
685 | };
686 | return (body, info) => {
687 | const isInert = info.PROPERTIES == null;
688 | const properties = isInert ? null : {
689 | settings: info.PROPERTIES.SHOOT_SETTINGS,
690 | label: load('', info.PROPERTIES.LABEL),
691 | autofire: load(false, info.PROPERTIES.AUTOFIRE),
692 | altFire: load(false, info.PROPERTIES.ALT_FIRE),
693 | calculator: load(0, info.PROPERTIES.STAT_CALCULATOR),
694 | waitToCycle: load(false, info.PROPERTIES.WAIT_TO_CYCLE),
695 | countsOwnKids: load(false, info.PROPERTIES.MAX_CHILDREN),
696 | syncsSkills: load(false, info.PROPERTIES.SYNCS_SKILLS),
697 | negRecoil: load(false, info.PROPERTIES.NEGATIVE_RECOIL),
698 | bullet: (() => {
699 | let types = (Array.isArray(info.PROPERTIES.TYPE)) ? info.PROPERTIES.TYPE.splice() : [info.PROPERTIES.TYPE];
700 | let stats = {};
701 | types.forEach(function setStats(type) {
702 | if (type.PARENT != null) { // Make sure we load from the parents first
703 | for (let i=0; i {} : () => getTracking(gun),
737 | live: isInert ? () => {} : () => live(gun),
738 | };
739 | };
740 | });
741 | // The attributes object
742 | const Attributes = () => {
743 | return {
744 | physical: {
745 | acceleration: 0,
746 | topSpeed: 0,
747 | penetration: 0,
748 | damage: 0,
749 | fov: 0,
750 | density: 0,
751 | stealth: 0,
752 | pushability: 0,
753 | range: 0,
754 | },
755 | settings: {
756 | drawHealth: false,
757 | drawShape: false,
758 | damageEffects: false,
759 | ratioEffects: false,
760 | motionEffects: false,
761 | acceptsScore: false,
762 | givesKillMessage: false,
763 | canGoOutsideRoom: false,
764 | hitsOwnType: false,
765 | diesAtLowSpeed: false,
766 | diesAtRange: false,
767 | independent: false,
768 | persistsAfterDeath: false,
769 | clearOnMasterUpgrade: false,
770 | healthWithLevel: false,
771 | isObstacle: false,
772 | isNecromancer: false,
773 | hasNoRecoil: false,
774 | cravesAttention: false,
775 | buffVsFood: false,
776 | leaderboardable: false,
777 | reloadToAcceleration: false,
778 | variesInSize: false,
779 | isFood: false,
780 | isIntangable: false,
781 | },
782 | body: {
783 | acceleration: 0,
784 | speed: 0,
785 | health: 0,
786 | resist: 0,
787 | shield: 0,
788 | regen: 0,
789 | damage: 0,
790 | penetration: 0,
791 | fov: 0,
792 | range: 0,
793 | density: 0,
794 | stealth: 0,
795 | pushability: 0,
796 | heteroMultiplier: 0,
797 | },
798 | aiSettings: {
799 | farm: false,
800 | blind: false,
801 | chase: false,
802 | skynet: false,
803 | view360: false,
804 | reverseDirection: false,
805 | shapefriend: false,
806 | },
807 | index: -1,
808 | mockup: {},
809 | label: '',
810 | type: -1,
811 | shape: 0,
812 | color: 0,
813 | motionType: -1,
814 | facingType: -1,
815 | damageClass: 0,
816 | skillNames: 0,
817 | dangerValue: 1,
818 | squiggle: 1,
819 | upgrades: [],
820 | maxChildren: 0,
821 | creationMessage: '',
822 | };
823 | };
824 | // A definer
825 | const define = (() => {
826 | const check = val => {
827 | return val != null;
828 | };
829 | return (def) => {
830 | const obj = Attributes();
831 | if (def.PARENT != null) {
832 | for (let i=0; i {
845 | toAdd.push(eval('new io_' + ioName + '(this)'));
846 | });
847 | this.addController(toAdd);
848 | }
849 | if (check(def.MOTION_TYPE)) obj.motionType = def.MOTION_TYPE;
850 | if (check(def.FACING_TYPE)) obj.facingType = def.FACING_TYPE;
851 | if (check(def.BROADCAST_MESSAGE)) obj.creationMessage = def.BROADCAST_MESSAGE;
852 | if (check(def.DAMAGE_CLASS)) obj.damageClass = def.DAMAGE_CLASS;
853 | if (check(def.STAT_NAMES)) obj.skillNames = def.STAT_NAMES;
854 | if (check(def.DANGER)) obj.dangervalue = def.DANGER;
855 | // Settings stuff
856 | if (check(def.DRAW_HEALTH)) obj.settings.drawHealth = def.DRAW_HEALTH;
857 | if (check(def.DRAW_SELF)) obj.settings.drawShape = def.DRAW_SELF;
858 | if (check(def.DAMAGE_EFFECTS)) obj.settings.damageEffects = def.DAMAGE_EFFECTS;
859 | if (check(def.RATIO_EFFECTS)) obj.settings.ratioEffects = def.RATIO_EFFECTS;
860 | if (check(def.MOTION_EFFECTS)) obj.settings.motionEffects = def.MOTION_EFFECTS;
861 | if (check(def.ACCEPTS_SCORE)) obj.settings.acceptsScore = def.ACCEPTS_SCORE;
862 | if (check(def.GIVE_KILL_MESSAGE)) obj.settings.givesKillMessage = def.GIVE_KILL_MESSAGE;
863 | if (check(def.CAN_GO_OUTSIDE_ROOM)) obj.settings.canGoOutsideRoom = def.CAN_GO_OUTSIDE_ROOM;
864 | if (check(def.HITS_OWN_TYPE)) obj.settings.hitsOwnType = def.HITS_OWN_TYPE;
865 | if (check(def.DIE_AT_LOW_SPEED)) obj.settings.diesAtLowSpeed = def.DIE_AT_LOW_SPEED;
866 | if (check(def.DIE_AT_RANGE)) obj.settings.diesAtRange = def.DIE_AT_RANGE;
867 | if (check(def.INDEPENDENT)) obj.settings.independent = def.INDEPENDENT;
868 | if (check(def.PERSISTS_AFTER_DEATH)) obj.settings.persistsAfterDeath = def.PERSISTS_AFTER_DEATH;
869 | if (check(def.CLEAR_ON_MASTER_UPGRADE)) obj.settings.clearOnMasterUpgrade = def.CLEAR_ON_MASTER_UPGRADE;
870 | if (check(def.HEALTH_WITH_LEVEL)) obj.settings.health = def.HEALTH_WITH_LEVEL;
871 | if (check(def.OBSTACLE)) obj.settings.isObstacle = def.OBSTACLE;
872 | if (check(def.NECRO)) obj.settings.isNecromancer = def.NECRO;
873 | if (check(def.HAS_NO_RECOIL)) obj.settings.hasNoRecoil = def.HAS_NO_RECOIL;
874 | if (check(def.CRAVES_ATTENTION)) obj.settings.cravesAttention = def.CRAVES_ATTENTION;
875 | if (check(def.BUFF_VS_FOOD)) obj.settings.buffVsFood = def.BUFF_VS_FOOD;
876 | if (check(def.CAN_BE_ON_LEADERBOARD)) obj.settings.leaderboardable = def.CAN_BE_ON_LEADERBOARD;
877 | if (check(def.IS_SMASHER)) obj.settings.reloadToAcceleration = def.IS_SMASHER;
878 | if (check(def.INTANGIBLE)) obj.settings.isIntangable = def.INTANGIBLE;
879 | if (check(def.VARIES_IN_SIZE)) obj.settings.variesInSize = def.VARIES_IN_SIZE;
880 | // AI settings
881 | if (check(def.AI)) {
882 | if (check(def.AI.NO_LEAD)) obj.aiSettings.chase = def.AI.NO_LEAD;
883 | if (check(def.AI.SKYNET)) obj.aiSettings.skynet = def.AI.SKYNET;
884 | if (check(def.AI.BLIND)) obj.aiSettings.blind = def.AI.BLIND;
885 | if (check(def.AI.FARMER)) obj.aiSettings.farm = def.AI.FARMER;
886 | if (check(def.AI.FULL_VIEW)) obj.aiSettings.view360 = def.AI.FULL_VIEW;
887 | if (check(def.AI.STRAFE)) obj.aiSettings.reverseDirection = def.AI.STRAFE;
888 | if (check(def.AI.LIKES_SHAPES)) obj.aiSettings.shapefriend = def.AI.LIKES_SHAPES;
889 | }
890 | // Upgrades stuff
891 | if (def.RESET_UPGRADES) obj.upgrades = [];
892 | if (check(def.UPGRADES_TIER_1))
893 | def.UPGRADES_TIER_1.forEach(e => {
894 | obj.upgrades.push({ class: e, level: c.TIER_1, index: e.index,});
895 | });
896 | if (check(def.UPGRADES_TIER_2))
897 | def.UPGRADES_TIER_2.forEach(e => {
898 | obj.upgrades.push({ class: e, level: c.TIER_2, index: e.index,});
899 | });
900 | if (check(def.UPGRADES_TIER_3))
901 | def.UPGRADES_TIER_3.forEach(e => {
902 | obj.upgrades.push({ class: e, level: c.TIER_3, index: e.index,});
903 | });
904 | if (def.SIZE != null) {
905 | this.SIZE = def.SIZE * this.squiggle;
906 | if (this.coreSize == null) { this.coreSize = this.SIZE; }
907 | }
908 | if (def.SKILL != null && def.SKILL != []) {
909 | if (def.SKILL.length != 10) {
910 | throw('Inappropiate skill raws.');
911 | }
912 | this.skill.set(def.SKILL);
913 | }
914 | if (def.LEVEL != null) {
915 | if (def.LEVEL === -1) {
916 | this.skill.reset();
917 | }
918 | while (this.skill.level < c.SKILL_CHEAT_CAP && this.skill.level < def.LEVEL) {
919 | this.skill.score += this.skill.levelScore;
920 | this.skill.maintain();
921 | }
922 | this.refreshBodyAttributes();
923 | }
924 | if (def.SKILL_CAP != null && def.SKILL_CAP != []) {
925 | if (def.SKILL_CAP.length != 10) {
926 | throw('Inappropiate skill caps.');
927 | }
928 | this.skill.setCaps(def.SKILL_CAP);
929 | }
930 | if (def.VALUE != null) {
931 | this.skill.score = Math.max(this.skill.score, def.VALUE * this.squiggle);
932 | }
933 | if (def.ALT_ABILITIES != null) {
934 | this.abilities = def.ALT_ABILITIES;
935 | }
936 | if (def.GUNS != null) {
937 | let newGuns = [];
938 | def.GUNS.forEach((gundef) => {
939 | newGuns.push(new Gun(this, gundef));
940 | });
941 | this.guns = newGuns;
942 | }
943 | if (def.MAX_CHILDREN != null) {
944 | this.maxChildren = def.MAX_CHILDREN;
945 | }
946 | if (def.FOOD != null) {
947 | if (def.FOOD.LEVEL != null) {
948 | this.foodLevel = def.FOOD.LEVEL;
949 | this.foodCountup = 0;
950 | }
951 | }
952 | if (def.BODY != null) {
953 | if (def.BODY.ACCELERATION != null) {
954 | this.ACCELERATION = def.BODY.ACCELERATION;
955 | }
956 | if (def.BODY.SPEED != null) {
957 | this.SPEED = def.BODY.SPEED;
958 | }
959 | if (def.BODY.HEALTH != null) {
960 | this.HEALTH = def.BODY.HEALTH;
961 | }
962 | if (def.BODY.RESIST != null) {
963 | this.RESIST = def.BODY.RESIST;
964 | }
965 | if (def.BODY.SHIELD != null) {
966 | this.SHIELD = def.BODY.SHIELD;
967 | }
968 | if (def.BODY.REGEN != null) {
969 | this.REGEN = def.BODY.REGEN;
970 | }
971 | if (def.BODY.DAMAGE != null) {
972 | this.DAMAGE = def.BODY.DAMAGE;
973 | }
974 | if (def.BODY.PENETRATION != null) {
975 | this.PENETRATION = def.BODY.PENETRATION;
976 | }
977 | if (def.BODY.FOV != null) {
978 | this.FOV = def.BODY.FOV;
979 | }
980 | if (def.BODY.RANGE != null) {
981 | this.RANGE = def.BODY.RANGE;
982 | }
983 | if (def.BODY.SHOCK_ABSORB != null) {
984 | this.SHOCK_ABSORB = def.BODY.SHOCK_ABSORB;
985 | }
986 | if (def.BODY.DENSITY != null) {
987 | this.DENSITY = def.BODY.DENSITY;
988 | }
989 | if (def.BODY.STEALTH != null) {
990 | this.STEALTH = def.BODY.STEALTH;
991 | }
992 | if (def.BODY.PUSHABILITY != null) {
993 | this.PUSHABILITY = def.BODY.PUSHABILITY;
994 | }
995 | if (def.BODY.HETERO != null) {
996 | this.heteroMultiplier = def.BODY.HETERO;
997 | }
998 | this.refreshBodyAttributes();
999 | }
1000 | if (def.TURRETS != null) {
1001 | let o;
1002 | this.turrets.forEach(o => o.destroy());
1003 | this.turrets = [];
1004 | def.TURRETS.forEach(def => {
1005 | o = new Entity(this, this.master);
1006 | ((Array.isArray(def.TYPE)) ? def.TYPE : [def.TYPE]).forEach(type => o.define(type));
1007 | o.bindToMaster(def.POSITION, this);
1008 | });
1009 | }
1010 | if (def.mockup != null) {
1011 | this.mockup = def.mockup;
1012 | }
1013 | };
1014 | })();
1015 | // Return the constructor
1016 | return (x, y) => {
1017 | const creationTime = util.time();
1018 | const status = newStatusBox();
1019 | const kills = newKillBox();
1020 | const skills = newSkills();
1021 | // Inheritance and control
1022 | let family = {
1023 | master: null,
1024 | source: null,
1025 | parent: null,
1026 | };
1027 | // Health
1028 | const health = healthTypes.newStatic();
1029 | const shield = healthTypes.newDynamic();
1030 | // Return the new entity
1031 | return {
1032 | life: () => {},
1033 | getSkills: () => { return skills.get(); },
1034 | refreshBodyAttributes: () => {},
1035 | define: type => {},
1036 | setTeam: team => {},
1037 | getTeam: () => {},
1038 | setMaster: master => {},
1039 | getMaster: () => {},
1040 | setColor: col => {},
1041 | setFacing: dir => {},
1042 | setSize: size => {},
1043 | getFacing: () => {},
1044 | getSize: () => {},
1045 | getLabel: () => {},
1046 | getMaxChildren: () => {},
1047 | addChild: newlyborn => {},
1048 | removeChild: deadkid => {},
1049 | addDerefFunction: func => {},
1050 | isInvulnurable: () => {},
1051 | getVelocity: () => { return [0, 0]; },
1052 | getPosition: () => { return [0, 0]; },
1053 | accelerate: (amount, direction) => {},
1054 | shove: (x, y) => {},
1055 | forceSizeUpdate: () => {},
1056 | getBulletColor: () => {},
1057 | assignSkills: assignment => skills.set(assignment),
1058 | necro: () => {},
1059 | fullHeal: () => {},
1060 | };
1061 | };
1062 | });
--------------------------------------------------------------------------------