1515 You should have received a copy of the GNU Affero General Public License
1616 along with this program. If not, see <https://www.gnu.org/licenses/>
1717*/
18- import ArenaEntity , { ArenaState } from "../Native/Arena" ;
18+ import ArenaEntity from "../Native/Arena" ;
1919import GameServer from "../Game" ;
20- import MazeWall from "../Entity/Misc/MazeWall" ;
21- import { VectorAbstract } from "../Physics/Vector" ;
20+ import MazeGenerator , { MazeGeneratorConfig } from "../Systems/MazeGenerator" ;
2221
2322import ShapeManager from "../Entity/Shape/Manager" ;
2423
@@ -33,215 +32,40 @@ export class MazeShapeManager extends ShapeManager {
3332
3433 return Math.floor(12.5 * ratio);
3534 */
36-
35+
3736 return 1300 ;
3837 }
3938}
4039
41- // constss.
42- const CELL_SIZE = 635 ;
43- const GRID_SIZE = 40 ;
44- const ARENA_SIZE = CELL_SIZE * GRID_SIZE ;
45- const SEED_AMOUNT = Math . floor ( Math . random ( ) * 30 ) + 30 ;
46- const TURN_CHANCE = 0.2 ;
47- const BRANCH_CHANCE = 0.2 ;
48- const TERMINATION_CHANCE = 0.2 ;
40+ const config : MazeGeneratorConfig = {
41+ CELL_SIZE : 635 ,
42+ GRID_SIZE : 40 ,
43+ SEED_AMOUNT : Math . floor ( Math . random ( ) * 30 ) + 30 ,
44+ TURN_CHANCE : 0.2 ,
45+ BRANCH_CHANCE : 0.2 ,
46+ TERMINATION_CHANCE : 0.2
47+ }
4948
50- /**
51- * Maze Gamemode Arena
52- *
53- * Implementation details:
54- * Maze map generator by damocles <github.com/SpanksMcYeet>
55- * - Added into codebase on December 3rd 2022
56- */
5749export default class MazeArena extends ArenaEntity {
5850 static override GAMEMODE_ID : string = "maze" ;
5951
6052 protected shapes : ShapeManager = new MazeShapeManager ( this ) ;
6153
62- /** Stores all the "seed"s */
63- private SEEDS : VectorAbstract [ ] = [ ] ;
64- /** Stores all the "wall"s, contains cell based coords */
65- private WALLS : ( VectorAbstract & { width : number , height : number } ) [ ] = [ ] ;
66- /** Rolled out matrix of the grid */
67- private MAZE : Uint8Array = new Uint8Array ( GRID_SIZE * GRID_SIZE ) ;
54+ public mazeGenerator : MazeGenerator = new MazeGenerator ( this , config ) ;
6855
6956 public constructor ( game : GameServer ) {
7057 super ( game ) ;
71- this . updateBounds ( ARENA_SIZE , ARENA_SIZE ) ;
58+
59+ const arenaSize = config . CELL_SIZE * config . GRID_SIZE
60+ this . updateBounds ( arenaSize , arenaSize ) ;
61+
62+ this . mazeGenerator . buildMaze ( ) ;
63+
7264 this . allowBoss = false ;
73- this . _buildMaze ( ) ;
74- }
75- /** Creates a maze wall from cell coords */
76- private _buildWallFromGridCoord ( gridX : number , gridY : number , gridW : number , gridH : number ) {
77- const scaledW = gridW * CELL_SIZE ;
78- const scaledH = gridH * CELL_SIZE ;
79- const scaledX = gridX * CELL_SIZE - ARENA_SIZE / 2 + ( scaledW / 2 ) ;
80- const scaledY = gridY * CELL_SIZE - ARENA_SIZE / 2 + ( scaledH / 2 ) ;
81- new MazeWall ( this . game , scaledX , scaledY , scaledH , scaledW ) ;
82- }
83- /** Allows for easier (x, y) based getting of maze cells */
84- private _get ( x : number , y : number ) : number {
85- return this . MAZE [ y * GRID_SIZE + x ] ;
86- }
87- /** Allows for easier (x, y) based setting of maze cells */
88- private _set ( x : number , y : number , value : number ) : number {
89- return this . MAZE [ y * GRID_SIZE + x ] = value ;
90- }
91- /** Converts MAZE grid into an array of set and unset bits for ease of use */
92- private _mapValues ( ) : [ x : number , y : number , value : number ] [ ] {
93- const values : [ x : number , y : number , value : number ] [ ] = Array ( this . MAZE . length ) ;
94- for ( let i = 0 ; i < this . MAZE . length ; ++ i ) values [ i ] = [ i % GRID_SIZE , Math . floor ( i / GRID_SIZE ) , this . MAZE [ i ] ] ;
95- return values ;
96- }
97- /** Builds the maze */
98- protected _buildMaze ( ) {
99- // Plant some seeds
100- for ( let i = 0 ; i < 10000 ; i ++ ) {
101- // Stop if we exceed our maximum seed amount
102- if ( this . SEEDS . length >= SEED_AMOUNT ) break ;
103- // Attempt a seed planting
104- let seed : VectorAbstract = {
105- x : Math . floor ( ( Math . random ( ) * GRID_SIZE ) - 1 ) ,
106- y : Math . floor ( ( Math . random ( ) * GRID_SIZE ) - 1 ) ,
107- } ;
108- // Check if our seed is valid (is 3 GU away from another seed, and is not on the border)
109- if ( this . SEEDS . some ( a => ( Math . abs ( seed . x - a . x ) <= 3 && Math . abs ( seed . y - a . y ) <= 3 ) ) ) continue ;
110- if ( seed . x <= 0 || seed . y <= 0 || seed . x >= GRID_SIZE - 1 || seed . y >= GRID_SIZE - 1 ) continue ;
111- // Push it to the pending seeds and set its grid to a wall cell
112- this . SEEDS . push ( seed ) ;
113- this . _set ( seed . x , seed . y , 1 ) ;
114- }
115- const direction : number [ ] [ ] = [
116- [ - 1 , 0 ] , [ 1 , 0 ] , // left and right
117- [ 0 , - 1 ] , [ 0 , 1 ] , // up and down
118- ] ;
119- // Let it grow!
120- for ( let seed of this . SEEDS ) {
121- // Select a direction we want to head in
122- let dir : number [ ] = direction [ Math . floor ( Math . random ( ) * 4 ) ] ;
123- let termination = 1 ;
124- // Now we can start to grow
125- while ( termination >= TERMINATION_CHANCE ) {
126- // Choose the next termination chance
127- termination = Math . random ( ) ;
128- // Get the direction we're going in
129- let [ x , y ] = dir ;
130- // Move forward in that direction, and set that grid to a wall cell
131- seed . x += x ;
132- seed . y += y ;
133- if ( seed . x <= 0 || seed . y <= 0 || seed . x >= GRID_SIZE - 1 || seed . y >= GRID_SIZE - 1 ) break ;
134- this . _set ( seed . x , seed . y , 1 ) ;
135- // Now lets see if we want to branch or turn
136- if ( Math . random ( ) <= BRANCH_CHANCE ) {
137- // If the seeds exceeds 75, then we're going to stop creating branches in order to avoid making a massive maze tumor(s)
138- if ( this . SEEDS . length > 75 ) continue ;
139- // Get which side we want the branch to be on (left or right if moving up or down, and up and down if moving left or right)
140- let [ xx , yy ] = direction . filter ( a => a . every ( ( b , c ) => b !== dir [ c ] ) ) [ Math . floor ( Math . random ( ) * 2 ) ] ;
141- // Create the seed
142- let newSeed = {
143- x : seed . x + xx ,
144- y : seed . y + yy ,
145- } ;
146- // Push the seed and set its grid to a maze zone
147- this . SEEDS . push ( newSeed ) ;
148- this . _set ( seed . x , seed . y , 1 ) ;
149- } else if ( Math . random ( ) <= TURN_CHANCE ) {
150- // Get which side we want to turn to (left or right if moving up or down, and up and down if moving left or right)
151- dir = direction . filter ( a => a . every ( ( b , c ) => b !== dir [ c ] ) ) [ Math . floor ( Math . random ( ) * 2 ) ] ;
152- }
153- }
154- }
155- // Now lets attempt to add some singular walls around the arena
156- for ( let i = 0 ; i < 10 ; i ++ ) {
157- // Attempt to place it
158- let seed = {
159- x : Math . floor ( ( Math . random ( ) * GRID_SIZE ) - 1 ) ,
160- y : Math . floor ( ( Math . random ( ) * GRID_SIZE ) - 1 ) ,
161- } ;
162- // Check if our sprinkle is valid (is 3 GU away from another wall, and is not on the border)
163- if ( this . _mapValues ( ) . some ( ( [ x , y , r ] ) => r === 1 && ( Math . abs ( seed . x - x ) <= 3 && Math . abs ( seed . y - y ) <= 3 ) ) ) continue ;
164- if ( seed . x <= 0 || seed . y <= 0 || seed . x >= GRID_SIZE - 1 || seed . y >= GRID_SIZE - 1 ) continue ;
165- // Set its grid to a wall cell
166- this . _set ( seed . x , seed . y , 1 ) ;
167- }
168- // Now it's time to fill in the inaccessible pockets
169- // Start at the top left
170- let queue : number [ ] [ ] = [ [ 0 , 0 ] ] ;
171- this . _set ( 0 , 0 , 2 ) ;
172- let checkedIndices = new Set ( [ 0 ] ) ;
173- // Now lets cycle through the whole map
174- for ( let i = 0 ; i < 3000 && queue . length > 0 ; i ++ ) {
175- let next = queue . shift ( ) ;
176- if ( next == null ) break ;
177- let [ x , y ] = next ;
178- // Get what the coordinates of what lies to the side of our cell
179- for ( let [ nx , ny ] of [
180- [ x - 1 , y ] , // left
181- [ x + 1 , y ] , // right
182- [ x , y - 1 ] , // top
183- [ x , y + 1 ] , // bottom
184- ] ) {
185- // If its a wall ignore it
186- if ( this . _get ( nx , ny ) !== 0 ) continue ;
187- let i = ny * GRID_SIZE + nx ;
188- // Check if we've already checked this cell
189- if ( checkedIndices . has ( i ) ) continue ;
190- // Add it to the checked cells if we haven't already
191- checkedIndices . add ( i ) ;
192- // Add it to the next cycle to check
193- queue . push ( [ nx , ny ] ) ;
194- // Set its grid to an accessible cell
195- this . _set ( nx , ny , 2 ) ;
196- }
197- }
198- // Cycle through all areas of the map
199- for ( let x = 0 ; x < GRID_SIZE ; x ++ ) {
200- for ( let y = 0 ; y < GRID_SIZE ; y ++ ) {
201- // If we're not a wall, ignore the cell and move on
202- if ( this . _get ( x , y ) === 2 ) continue ;
203- // Define our properties
204- let chunk = { x, y, width : 0 , height : 1 } ;
205- // Loop through adjacent cells and see how long we should be
206- while ( this . _get ( x + chunk . width , y ) !== 2 ) {
207- this . _set ( x + chunk . width , y , 2 ) ;
208- chunk . width ++ ;
209- }
210- // Now lets see if we need to be t h i c c
211- outer: while ( true ) {
212- // Check the row below to see if we can still make a box
213- for ( let i = 0 ; i < chunk . width ; i ++ )
214- // Stop if we can't
215- if ( this . _get ( x + i , y + chunk . height ) === 2 ) break outer;
216- // If we can, remove the line of cells from the map and increase the height of the block
217- for ( let i = 0 ; i < chunk . width ; i ++ )
218- this . _set ( x + i , y + chunk . height , 2 ) ;
219- chunk . height ++ ;
220- }
221- this . WALLS . push ( chunk ) ;
222- }
223- }
224- // Create the walls!
225- for ( let { x, y, width, height} of this . WALLS )
226- this . _buildWallFromGridCoord ( x , y , width , height ) ;
22765 }
22866
22967 public isValidSpawnLocation ( x : number , y : number ) : boolean {
23068 // Should never spawn inside walls
231- for ( let wall of this . WALLS ) {
232- const wallX = wall . x * CELL_SIZE - ARENA_SIZE / 2 ;
233- const wallY = wall . y * CELL_SIZE - ARENA_SIZE / 2 ;
234- const wallW = wall . width * CELL_SIZE ;
235- const wallH = wall . height * CELL_SIZE ;
236- if (
237- x >= wallX &&
238- x <= wallX + wallW &&
239- y >= wallY &&
240- y <= wallY + wallH
241- ) {
242- return false ;
243- }
244- }
245- return true ;
69+ return ! this . mazeGenerator . isInWall ( x , y ) ;
24670 }
24771}
0 commit comments