| [25622] | 1 | /**
|
|---|
| 2 | * Class that can be tagged to any tile. Can be used to constrain placers and entity placement to given areas.
|
|---|
| 3 | */
|
|---|
| 4 | class TileClass {
|
|---|
| [9096] | 5 |
|
|---|
| [25622] | 6 | constructor(size)
|
|---|
| [9096] | 7 | {
|
|---|
| [25622] | 8 | this.size = size;
|
|---|
| 9 | this.width = Math.ceil(size / 16); // Need one entry per 16 tiles as each tile takes a single bit
|
|---|
| 10 | this.inclusionGrid = new Uint16Array(this.size * this.width);
|
|---|
| [9096] | 11 | }
|
|---|
| 12 |
|
|---|
| [25622] | 13 | /**
|
|---|
| 14 | * Returns true if the given position is part of the tileclass.
|
|---|
| 15 | */
|
|---|
| 16 | has(position)
|
|---|
| [9096] | 17 | {
|
|---|
| [25622] | 18 | if (position.x < 0 || position.x >= this.size || position.y < 0 || position.y >= this.size)
|
|---|
| 19 | return 0;
|
|---|
| 20 | // x >> 4 == Math.floor(x / 16); used to find the integer this x is included in
|
|---|
| 21 | // x & 0xF == x % 16; used to find the bit position of the given x
|
|---|
| 22 | return this.inclusionGrid[position.y * this.width + (position.x >> 4)] & (1 << (position.x & 0xF));
|
|---|
| [9096] | 23 | }
|
|---|
| [18840] | 24 |
|
|---|
| [25622] | 25 | /**
|
|---|
| 26 | * Adds the given position to the tileclass.
|
|---|
| 27 | */
|
|---|
| 28 | add(position)
|
|---|
| [9096] | 29 | {
|
|---|
| [25622] | 30 | if (position.x < 0 || position.x >= this.size || position.y < 0 || position.y >= this.size)
|
|---|
| 31 | return;
|
|---|
| 32 | this.inclusionGrid[position.y * this.width + (position.x >> 4)] |= 1 << (position.x & 0xF);
|
|---|
| [9096] | 33 | }
|
|---|
| [18840] | 34 |
|
|---|
| [25622] | 35 | /**
|
|---|
| 36 | * Removes the given position to the tileclass.
|
|---|
| 37 | */
|
|---|
| 38 | remove(position)
|
|---|
| [9096] | 39 | {
|
|---|
| [25622] | 40 | if (position.x < 0 || position.x >= this.size || position.y < 0 || position.y >= this.size)
|
|---|
| 41 | return;
|
|---|
| 42 | this.inclusionGrid[position.y * this.width + (position.x >> 4)] &= ~(1 << (position.x & 0xF));
|
|---|
| [9096] | 43 | }
|
|---|
| 44 |
|
|---|
| [25622] | 45 | /**
|
|---|
| 46 | * Count the number of tiles in the tileclass within the given radius of the given position.
|
|---|
| 47 | * Can return either the total number of members or nonmembers.
|
|---|
| 48 | */
|
|---|
| 49 | countInRadius(position, radius, returnMembers)
|
|---|
| [9096] | 50 | {
|
|---|
| [25622] | 51 | let members = 0;
|
|---|
| 52 | let total = 0;
|
|---|
| 53 | const radius2 = radius * radius;
|
|---|
| 54 | const [x, y] = [position.x, position.y];
|
|---|
| [18840] | 55 |
|
|---|
| [25622] | 56 | const yMin = Math.max(Math.ceil(y - radius), 0);
|
|---|
| 57 | const yMax = Math.min(Math.floor(y + radius), this.size - 1);
|
|---|
| 58 | for (let iy = yMin; iy <= yMax; ++iy)
|
|---|
| [15621] | 59 | {
|
|---|
| [25622] | 60 | const dy = iy - y;
|
|---|
| 61 | const dy2 = dy * dy;
|
|---|
| 62 | const delta = Math.sqrt(radius2 - dy2);
|
|---|
| 63 | const xMin = Math.max(Math.ceil(x - delta), 0);
|
|---|
| 64 | const xMax = Math.min(Math.floor(x + delta), this.size - 1);
|
|---|
| [21026] | 65 |
|
|---|
| [25622] | 66 | const indexXMin = xMin >> 4;
|
|---|
| 67 | const indexXMax = xMax >> 4;
|
|---|
| 68 | const indexY = iy * this.width;
|
|---|
| 69 | for (let indexX = indexXMin; indexX <= indexXMax; ++indexX)
|
|---|
| [15621] | 70 | {
|
|---|
| [25622] | 71 | const imin = indexX == indexXMin ? xMin & 0xF : 0;
|
|---|
| 72 | const imax = indexX == indexXMax ? xMax & 0xF : 15;
|
|---|
| 73 | total += imax - imin + 1;
|
|---|
| 74 | if (this.inclusionGrid[indexY + indexX])
|
|---|
| 75 | for (let i = imin; i <= imax; ++i)
|
|---|
| 76 | if (this.inclusionGrid[indexY + indexX] & (1 << i))
|
|---|
| 77 | ++members;
|
|---|
| [15621] | 78 | }
|
|---|
| 79 | }
|
|---|
| [25622] | 80 |
|
|---|
| 81 | return returnMembers ? members : total - members;
|
|---|
| [9096] | 82 | }
|
|---|
| [18840] | 83 |
|
|---|
| [25622] | 84 | /**
|
|---|
| 85 | * Counts the number of tiles marked in the tileclass within the given radius of the given position.
|
|---|
| 86 | */
|
|---|
| 87 | countMembersInRadius(position, radius)
|
|---|
| 88 | {
|
|---|
| 89 | return this.countInRadius(position, radius, true);
|
|---|
| 90 | }
|
|---|
| [9096] | 91 |
|
|---|
| [25622] | 92 | /**
|
|---|
| 93 | * Counts the number of tiles not marked in the tileclass within the given radius of the given position.
|
|---|
| 94 | */
|
|---|
| 95 | countNonMembersInRadius(position, radius)
|
|---|
| 96 | {
|
|---|
| 97 | return this.countInRadius(position, radius, false);
|
|---|
| 98 | }
|
|---|
| 99 | }
|
|---|