Jump to content

SQF Maze Generator


L3G0

Recommended Posts

On 23th December one on my Admins told me about the Idea to create an Event, where we create a Maze with bots and a safe.
 
After i answered great Idea he wanted to start mapping, but i said no, why do it by hand if the can automatize it?
This is how it look like In game: 1 2 3 4 5
 
Yesterday i wrote the first working Version of this Event and now i want to share the core, the Maze Generator with you.
 
These are two example outputs of this Maze Generator:

[[1,0],[6,8],[9,0,9,1,1,1,1,1,1,11,8,1,9,0,9,1,1,1,0,10,9,8,0,9,8,9,9,1,1,2,8,1,1,8,0,8,8,1,1,10,8,9,1,8,1,8,0,9,1,2,8,8,8,1,0,9,1,0,9,2,8,8,1,9,1,0,9,1,8,3,8,9,0,8,9,1,0,1,1,10,8,8,1,8,8,1,9,1,8,2,12,5,4,4,13,4,5,4,5,7]]
[[0,6],[0,9],[9,1,1,9,1,9,1,1,9,3,9,0,8,0,8,1,8,8,0,10,8,9,1,1,1,0,8,9,1,2,8,8,9,1,9,1,1,0,9,10,8,8,0,8,8,9,0,9,0,2,8,1,1,8,1,0,9,0,9,3,1,9,0,9,1,1,8,9,0,10,8,0,9,8,1,8,8,1,1,10,9,1,0,9,0,8,1,1,8,2,12,12,5,4,5,12,5,5,5,6]]

The first Number in the Array is a Random Startpoint somewhere at the outer wall, the second is the end of the longest path where you could place the Vault and the third array describes how each chamber is configured using binary interpretation.
 
The Walls are Interpreted like the following schema:

    1
   ---
 8 | | 2
   ---
    4

This should be enough explanation if you want to write the ingame parser and wall spawner yourself. I don't public my event script at the moment because i don't want to let the noob admins, that are not able to code one line, take this work for their pay to win servers...
 
My Maze Generator is based on the Depth-first search algorithm and implemented as recursive backtracker like descripted here:

http://www.astrolog.org/labyrnth/algrithm.htm or http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker
 
My first Idea was to write the prototype as callExtension but then i decided to instantly rewrite it in sqf, just for the fun :)
Here is my test code in C (don't complain about some strange design decisions, i wanted it to be easy convertible to sqf)

/*    1
 *   ---
 * 8 | | 2
 *   ---
 *    4
 */
#include <stdio.h>      /* printf, scanf, puts, NULL */
#include <stdlib.h>     /* srand, rand */
#include <time.h>

#define height 10
#define width 10
int visit_array[height*width];
int maze_array[height*width];
int distance = 0;
int end_distance = 0;
int end_x, end_y;
int start_x,start_y;

void recurse_maze(int cur_width, int cur_height, int dir) {
	if (cur_width < 0 || cur_height < 0) {
		//printf("negative position!!! %d %d\n", cur_width, cur_height);
		return;
	}

	int position = cur_width + width * cur_height;
	int randomnumber;
	int new_width, new_height, new_position;
	int new_dir;
	int dir_count = 4;
	int dir_array[4];
	int i,n;

	visit_array[position] = 1;
	distance++;

	// start remove entry wall
	if (dir == 0) {
		if (cur_height == 0) {
			maze_array[position] = maze_array[position] - 1;
		}
		if (cur_width == 0) {
			maze_array[position] = maze_array[position] - 8;
		}
	} else {
		if (dir == 4) {
			maze_array[position] = maze_array[position] - 1;
		}
		if (dir == 2) {
			maze_array[position] = maze_array[position] - 8;
		}
	}

	n = 1;
	for(i=0; i < dir_count; i++) {
		dir_array[i] = n;
		n = n * 2;
	}

	while (dir_count > 0) {
		new_width = cur_width;
		new_height = cur_height;

		randomnumber = rand() % dir_count;
		new_dir = dir_array[randomnumber];
		dir_count--;
		for(i=randomnumber; i < dir_count; i++) {
			dir_array[i] = dir_array[i+1];
		}

		switch(new_dir) {
			case 1: new_height = cur_height - 1; break;
			case 2: new_width = cur_width + 1; break;
			case 4: new_height = cur_height + 1; break;
			case 8: new_width = cur_width - 1; break;
			//default: printf("error new_dir %d",new_dir);
		}

		// invalid positions
		if (new_width >= width || new_height >= height || new_width < 0 || new_height < 0) {
			// don't create wall if it is the start
			if (dir != 0) {
				// add right line
				if (new_width == width) {
					maze_array[position] = maze_array[position] + 2;
				} 
				// add bottom line
				if (new_height == height) {
					maze_array[position] = maze_array[position] + 4;
				}
			} else {
				//printf("prevent entrywall creation\n");
			}
		} else {
			//printf("%d position %d\n", position, new_dir);
			int _new_position = new_width + width * new_height;
			if (visit_array[_new_position] == 0) {
				switch(new_dir) {
					case 1: maze_array[position] = maze_array[position] - 1; break;
					case 8: maze_array[position] = maze_array[position] - 8; break;
				}
				recurse_maze(new_width, new_height, new_dir);
			}
		}
	}

	if (distance > end_distance) {
		end_x = cur_width;
		end_y = cur_height;
		end_distance = distance;
	}

	distance--;
	return;
}

void print_maze() {
	int i,x,y;
	for (y = 0; y < height; y++) {
		for (x = 0; x < width; x++) {
			i = maze_array[x + width * y];

			if (i == 0)  printf("   ");
			if (i == 1)  printf("âââ");
			if (i == 2)  printf("  â");
			if (i == 3)  printf("âââ");
			if (i == 4)  printf("   ");
			if (i == 5)  printf("âââ");
			if (i == 6)  printf("  â");
			if (i == 7)  printf("âââ");
			if (i == 8)  printf("â  ");
			if (i == 9)  printf("âââ");
			if (i == 10) printf("â â");
			if (i == 11) printf("âââ");
			if (i == 12) printf("â  ");
			if (i == 13) printf("âââ");
			if (i == 14) printf("â â");
			if (i == 15) printf("âââ");
		}
		printf("\n");
		for (x = 0; x < width; x++) {
			i = maze_array[x + width * y];
			if (i == 0)  printf("   ");
			if (i == 1)  printf("   ");
			if (i == 2)  printf("  â");
			if (i == 3)  printf("  â");
			if (i == 4)  printf("   ");
			if (i == 5)  printf("   ");
			if (i == 6)  printf("  â");
			if (i == 7)  printf("  â");
			if (i == 8)  printf("â  ");
			if (i == 9)  printf("â  ");
			if (i == 10) printf("â â");
			if (i == 11) printf("â â");
			if (i == 12) printf("â  ");
			if (i == 13) printf("â  ");
			if (i == 14) printf("â â");
			if (i == 15) printf("â â");
		}
		printf("\n");
		for (x = 0; x < width; x++) {
			i = maze_array[x + width * y];
			if (i == 0)  printf("   ");
			if (i == 1)  printf("   ");
			if (i == 2)  printf("  â");
			if (i == 3)  printf("  â");
			if (i == 4)  printf("âââ");
			if (i == 5)  printf("âââ");
			if (i == 6)  printf("âââ");
			if (i == 7)  printf("âââ");
			if (i == 8)  printf("â  ");
			if (i == 9)  printf("â  ");
			if (i == 10) printf("â â");
			if (i == 11) printf("â â");
			if (i == 12) printf("âââ");
			if (i == 13) printf("âââ");
			if (i == 14) printf("âââ");
			if (i == 15) printf("âââ");
		}
		printf("\n");
	}
	printf("\n");
}

void serialize_maze() {
	int x,y,i,m=0;
	char output[4096];
	int totalchars = 0;
	totalchars += sprintf(output+totalchars, "[[%d,%d],[%d,%d],[", start_x, start_y, end_x, end_y);

	for (y = 0; y < height; y++) {
		for (x = 0; x < width; x++) {
			i = maze_array[x + width * y];
			if (m == 0) {
				totalchars += sprintf(output+totalchars, "%d", i);
				m = 1;
			} else {
				totalchars += sprintf(output+totalchars, ",%d", i);
			}
		}
	}

	totalchars += sprintf(output+totalchars, "]]", i);
	output[4095] = '\0';

	printf("%s\n",(char *)output);
}
int main(int c, char **v)
{
	int i;
	int x;
	int y;
	int r;
	int start_dir = 0;
	int randomnumber;

	time_t t;
	time(&t);
	srand((unsigned int)t);

	for (i=0; i < height*width; i++) {
		visit_array[i] = 0;
		maze_array[i] = 9;
	}

	randomnumber = rand() % 2;

	// start on top or bottom
	if (randomnumber == 1) {
		start_x = rand() % width;
		randomnumber = rand() % 2;
		if (randomnumber == 1) {
			start_y = 0;
			start_dir = 1;
		} else {
			start_y = height - 1;
			start_dir = 4;
		}
	// start left or right
	} else {
		start_y = rand() % height;
		randomnumber = rand() % 2;
		if (randomnumber == 1) {
			start_x = 0;
			start_dir = 8;
		} else {
			start_x = width - 1;
			start_dir = 2;
		}
	}

	recurse_maze(start_x, start_y, 0);

	printf("Start %d %d\n", start_x, start_y);
	printf("End %d %d\n", end_x, end_y);

	// print walls
	print_maze();
	serialize_maze();
/*
	for (y = 0; y < height; y++) {
		for (x = 0; x < width; x++) {
			i = maze_array[x + width * y];
			printf("%x",i);
			//printf("%d ",i);
		}
		printf("\n");
	}
	for (y = 0; y < height; y++) {
		for (x = 0; x < width; x++) {
			i = visit_array[x + width * y];
			printf("%x",i);
		}
		printf("\n");
	}
*/
	return 0;
}



Now the SQF Version of this Generator:

/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/

private ["_mazeWidth","_mazeHeight","_mazeCurWidth","_mazeCurHeight","_mazeDir","_position","_mazeNewWidth","_mazeNewHeight","_mazeNewDir","_mazeDirArray"];
_mazeWidth = _this select 0;
_mazeHeight = _this select 1;

/* don't run twice because this solution is not idempotent */
if (count mazeGlobalVisitArray > 0) exitWith { [[0,0],[0,0],[]] };

/* BEGIN Initialize */
mazeGlobalDistance = 0;
mazeGlobalMaxDistance = 0;

/* init arrays */
for [{_i=0},{_i<_mazeHeight*_mazeWidth},{_i=_i+1}] do {
	mazeGlobalVisitArray set [_i,0];
	mazeGlobalChamberArray set [_i,9];
};

/* find start on top or bottom */
if ((random 1) < 0.5) then {
	_mazeCurWidth = floor(random _mazeWidth);
	if ((random 1) < 0.5) then {
		_mazeCurHeight = 0;
		/* _mazeDir = 1; */
	} else {
		_mazeCurHeight = _mazeHeight - 1;
		/* _mazeDir = 4; */
	};
/* find start left or right */
} else {
	_mazeCurHeight = floor(random _mazeHeight);
	if ((random 1) < 0.5) then {
		_mazeCurWidth = 0;
		/* _mazeDir = 8; */
	} else {
		_mazeCurWidth = _mazeWidth - 1;
		/* _mazeDir = 2; */
	};
};
/* END Initialize */

_recurse = {
	private ["_mazeWidth","_mazeHeight","_mazeCurWidth","_mazeCurHeight","_mazeDir","_position","_mazeNewWidth","_mazeNewHeight","_mazeNewDir","_mazeDirArray"];
	_mazeWidth = _this select 0;
	_mazeHeight = _this select 1;
	_mazeCurWidth = _this select 2;
	_mazeCurHeight = _this select 3;
	_mazeDir = _this select 4;
	
	/* this should never happen */
	if (_mazeCurWidth < 0 || _mazeCurHeight < 0) exitWith { 
		diag_log format["negative position!!! %1 x %2", _mazeCurWidth, _mazeCurHeight];
		[[0,0],[0,0],[]]
	};

	_position = _mazeCurWidth + (_mazeWidth * _mazeCurHeight);
	mazeGlobalVisitArray set [_position,1];
	mazeGlobalDistance = mazeGlobalDistance + 1;

	/* remove entry walls */
	if (_mazeDir == 0) then {
		if (_mazeCurHeight == 0) then {
			mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1];
		};
		if (_mazeCurWidth == 0) then {
			mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8];
		};
	} else {
		if (_mazeDir == 4) then {
			mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1];
		};
		if (_mazeDir == 2) then {
			mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8];
		};
	};
	_mazeDirArray = [1,2,4,8];

	while {count _mazeDirArray > 0} do {
		/* diag_log format["%1 position loop %2", _position, count _mazeDirArray];*/
		_mazeNewWidth = _mazeCurWidth;
		_mazeNewHeight = _mazeCurHeight;
		
		/*
		_random = floor (random count _mazeDirArray);
		_mazeNewDir = _mazeDirArray select _random;
		_mazeDirArray set [_random, _mazeDirArray select ((count _mazeDirArray) - 1)];
		_mazeDirArray resize ((count _mazeDirArray) - 1);
		*/
		_mazeNewDir = _mazeDirArray call BIS_fnc_selectRandom;
		_mazeDirArray = _mazeDirArray - [_mazeNewDir];

		switch(_mazeNewDir) do {
			case 1: { _mazeNewHeight = _mazeNewHeight - 1; };
			case 2: { _mazeNewWidth = _mazeNewWidth + 1; };
			case 4: { _mazeNewHeight = _mazeNewHeight + 1; };
			case 8: { _mazeNewWidth = _mazeNewWidth - 1; };
		};

		/* invalid positions */
		if (_mazeNewWidth >= _mazeWidth || _mazeNewHeight >= _mazeHeight || _mazeNewWidth < 0 || _mazeNewHeight < 0) then {
			/* don't create wall if it is the start */
			if (_mazeDir != 0) then {
				/* add right line */
				if (_mazeNewWidth == _mazeWidth) then {
					mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) + 2];
				};
				/* add bottom line */
				if (_mazeNewHeight == _mazeHeight) then {
					mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) + 4];
				};
			} else {
				diag_log "prevent entrywall creation";
			};
		} else {
			/* diag_log format["%1 position %2", _position, _mazeNewDir]; */
			_mazeNewPosition = _mazeNewWidth + (_mazeWidth * _mazeNewHeight);
			/* diag_log format["new position %1 x %2 = %3", _mazeNewWidth, _mazeNewHeight, _mazeNewPosition]; */
			if ((mazeGlobalVisitArray select _mazeNewPosition) == 0) then {
				switch(_mazeNewDir) do {
					case 1: { mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1]; };
					case 8: { mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8]; };
				};
				[_mazeWidth,_mazeHeight,_mazeNewWidth,_mazeNewHeight,_mazeNewDir] call _recurse;
			};
		};
	};

	if (mazeGlobalDistance > mazeGlobalMaxDistance) then {
		mazeGlobalMaxEndPoint = [_mazeCurWidth,_mazeCurHeight];
		mazeGlobalMaxDistance = mazeGlobalDistance;
	};

	mazeGlobalDistance = mazeGlobalDistance -1;

	/* diag_log format["%1 reached end distance: %2", _position, mazeGlobalDistance]; */
};

[_mazeWidth,_mazeHeight,_mazeCurWidth,_mazeCurHeight,0] call _recurse;
/* generate return array */
_mazeReturnArray = [[_mazeCurWidth,_mazeCurHeight],mazeGlobalMaxEndPoint,mazeGlobalChamberArray];

/* cleanup for another run */
mazeGlobalVisitArray = [];
mazeGlobalChamberArray = [];
mazeGlobalDistance = 0;
mazeGlobalMaxDistance = 0;
mazeGlobalMaxEndPoint = [];

_mazeReturnArray



The following benchmark Numbers got created with the following Code:

mazeGlobalVisitArray = [];
mazeGlobalChamberArray = [];
mazeGlobalDistance = 0;
mazeGlobalMaxDistance = 0;
mazeGlobalMaxEndPoint = [];

_mazeWidth = 20;
_mazeHeight = 20;

_t1 = diag_tickTime;
_maze = [_mazeWidth,_mazeHeight] call generateMaze;
diag_log format["creating Maze of size %1 x %2 took %3 seconds", _mazeWidth, _mazeHeight, (diag_tickTime - _t1)];

_mazeStart = _maze select 0;
_mazeEnd = _maze select 1;
_mazeWalls = _maze select 2;
diag_log format["%1", _maze];

The tests where run in the ArmA 2 Editor without any other concurrent scripts:

10 x 10 took 0.186523 seconds
20 x 20 took 1.2207 seconds
30 x 30 took 4.67871 seconds
40 x 40 took 15.7334 seconds
50 x 50 took 25.251 seconds
60 x 60 took 58.6504 seconds
60 x 100 took 217.323 seconds
60 x 200 took 654.614 seconds

As comparison, the 60x200 Maze took 0.01 seconds with the c implementation (including all printf). If you want to test it with 60 x 200 in the c code, comment out the "serialize_maze();".
 
Well Now the Task lets start a Tiny Competition:
My code can be improved a lot, its just a solution hacked down in one Day. Maybe you want write this or another Algorithm and compete to my Solution :)

Link to comment
Share on other sites

What would i need to use to spawn it on a live server? seems pretty cool

This shows me, that you did not read my post. I explained how to spawn it, you just have to code it.

 

Be aware: I do not recommend to use the sqf based generator on live servers. I testet it on mine with 30 Users, to calculate the 20x20 Maze took over 200 seconds. If you realy want to use this on a live system, then write a dll in c/cpp and let it calculate the maze. This will take just some milliseconds instead of 200 seconds.

 

The Users needed 20 Minutes to solve it and escaped with the Price, so you should use at least a 25x25 Maze :D

Link to comment
Share on other sites

I'm guessing this is for A2 Epoch? I believe this probably belongs here: http://epochmod.com/forum/index.php?/forum/36-a2-epoch-events/

Nope it has nothing to do with Epoch, i just used the Epoch building structures to get some screenshots.

 

Its just the Algorithm to create a maze, how you spawn it, is another part.

I just wanted to creat an academic example what you can do, but you should not do! - Thats why i put it into off-topic.

Link to comment
Share on other sites

Oh, man, this is beautiful, thank you for sharing the SQF algorithm, L3G0.

 

One solution to this would be prefabs - a bunch of precalculated SQF files saved server side, then all you'd need to do is spawn them. Maybe give a random rotation to non essential walls if you want dynamics. It's obviously not what you are after, but it's certainly one way of doing it.

 

Good job, sir.

Link to comment
Share on other sites

It's obviously not what you are after, but it's certainly one way of doing it.

Yes this a good way to do this, but an other solution would be to use c code and put it into an dll, then you are still fexible in size and variation :)

 

Since i like this type of nonsence Work, i plan to do two more versions, and 3D Version and maybe i will to write another version where you can choose some kind of complexity.

 

I will do some Benchmarking with ArmA 3, will see if it is faster then ArmA 2 :>

Link to comment
Share on other sites

  • 2 weeks later...

Since i am going to take an outtime from SQF and ArmA i want to share the last Version of my Maze Spawner which uses the Generator. If you use it and change anything of the code, share it in this thread! I want to see how you use it! :)
 
You will need the latest Version of WAI to use the Vehicle and Bot Spawn.

Maybe you will want to change these two lines in WAI/compile/custom_publish_vehicle.sqf:

_unit = _ailist select (floor(random(count _ailist)));
_unit addWeapon _carkey;

to:

if (count _ailist > 0) then {
	_unit = _ailist select (floor(random(count _ailist)));
	_unit addWeapon _carkey;
} else {
	diag_log "could not find a unit to add key to";
};

This will prevent the error Messages when spawning an vehicle without attached bots while wai_lock_vehicles == true.

 

If you want to use it on a productive system you should convert it to createVehicleLocal, it is not wise to use this script as it is on fully populated Epoch Servers.
 
Now the script, have fun :)

/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
*/

private ["_startPosition","_halfMetalFloorSize","_mazeHeight","_mazeWidth","_maze","_mazeStart","_mazeEnd","_mazeWalls","_mazeStartFloor","_x","_y","_object","_chamberConfig","_t1","_keyid","_carkey","_mazeBotGroup","_mazeBot_x","_mazeBot_y"];
diag_log "starting maze spawn waiting for generateMaze";
waituntil{!isnil "generateMaze"};
_startPosition = [16359, 10169];
_halfMetalFloorSize = 2.64;

_mazeWidth = 20;
_mazeHeight = 20;
_mazeBotCount = 20;

_t1 = diag_tickTime;
_maze = [_mazeWidth,_mazeHeight] call generateMaze;
diag_log format["creating Maze of size %1 x %2 took %3 ms", _mazeWidth, _mazeHeight, (diag_tickTime - _t1)];

_mazeStart = _maze select 0;
_mazeEnd = _maze select 1;
_mazeWalls = _maze select 2;
diag_log format["%1", _maze];

/* _mazeStartFloor = objNull;*/
/* attachTo needs enableSimulation true; :/
if (isNull _mazeStartFloor) then {
	_object setPos _startPosition;
	_mazeStartFloor = _object;
} else {
	_object attachTo [_mazeStartFloor, [_x * 2 * _halfMetalFloorSize, _y * 2 * _halfMetalFloorSize, 0]];
};
*/

for [{_y=0},{_y<_mazeHeight},{_y=_y+1}] do {
	for [{_x=0},{_x<_mazeWidth},{_x=_x+1}] do {
		_position = [(_startPosition select 0) + _x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _y * 2 * _halfMetalFloorSize];
		/* create floor */
		_object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
		_object addEventHandler ["HandleDamage", {false}];
		_object enableSimulation false;
		_object setPos _position;
		mazeObjects set [count mazeObjects,_object];
		
		/* create roof */
		/*
		_object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
		_object addEventHandler ["HandleDamage", {false}];
		_object enableSimulation false;
		_object setPos _position + [3.2];
		mazeObjects set [count mazeObjects,_object];
		*/
		
		/* create walls */
		_chamberConfig = _mazeWalls select (_x + _mazeWidth * _y);
		for [{_dir=1},{_dir<=8},{_dir=_dir*2}] do {
			_wallDir = 0;
			_wallPosition = [];

			switch (_dir) do { 
				case 1: { _wallPosition = [(_position select 0), (_position select 1) - _halfMetalFloorSize]; }; 
				case 2: { _wallPosition = [(_position select 0) + _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
				case 4: { _wallPosition = [(_position select 0), (_position select 1) + _halfMetalFloorSize]; }; 
				case 8: { _wallPosition = [(_position select 0) - _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
			};

			if (_chamberConfig % 2 == 1) then {
				_object = createVehicle ["CinderWall_DZ", [0,0], [], 0, "CAN_COLLIDE"];
				_object addEventHandler ["HandleDamage", {false}];
				_object enableSimulation false;
				_object setPos _wallPosition;
				_object setDir _wallDir;
				mazeObjects set [count mazeObjects,_object];
			};

			_chamberConfig = floor(_chamberConfig / 2);
		};
	};
};

/* BEGIN create start platform */
_mazeStartPlattformCenter_x = (_mazeStart select 0);
_mazeStartPlattformCenter_y = (_mazeStart select 1);

if (_mazeStartPlattformCenter_x <= 0 && _mazeStartPlattformCenter_y <= 0) then {
	_mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 2;
	_mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 2;
} else {
	if (_mazeStartPlattformCenter_x <= 0) then {
		_mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 3;
	};
	if (_mazeStartPlattformCenter_y <= 0) then {
		_mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 3;
	};
};

if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1) && _mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
	_mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 2;
	_mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 2;
} else {
	if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1)) then {
		_mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 3;
	};
	if (_mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
		_mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 3;
	};
};

for [{_y=-2},{_y<=2},{_y=_y+1}] do {
	for [{_x=-2},{_x<=2},{_x=_x+1}] do {
		_mazeStartPlattform_x = _mazeStartPlattformCenter_x + _x;
		_mazeStartPlattform_y = _mazeStartPlattformCenter_y + _y;
		if (_mazeStartPlattform_x >= _mazeWidth || _mazeStartPlattform_y >= _mazeHeight || _mazeStartPlattform_x < 0 || _mazeStartPlattform_y < 0) then {
			_position = [(_startPosition select 0) + _mazeStartPlattform_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattform_y * 2 * _halfMetalFloorSize];
			_object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
			_object addEventHandler ["HandleDamage", {false}];
			_object enableSimulation false;
			_object setPos _position;
			mazeObjects set [count mazeObjects,_object];
		};
	};
};
/* END create start platform */

/* BEGIN spawn vehicle */
sleep 2;
_position = [(_startPosition select 0) + _mazeStartPlattformCenter_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattformCenter_y * 2 * _halfMetalFloorSize, 0.2];
_object = ["LAV25_HQ_DZE",_position,"maze",true,0] call custom_publish;
sleep 1;
_object setPos _position;
_object setFuel 1;
_keyid = parseNumber(_object getVariable ["CharacterID", "0"]);
_carkey = "";
if ((_keyid > 0) && (_keyid <= 2500)) then {_carkey = format["ItemKeyGreen%1",_keyid];};
if ((_keyid > 2500) && (_keyid <= 5000)) then {_carkey = format["ItemKeyRed%1",_keyid-2500];};
if ((_keyid > 5000) && (_keyid <= 7500)) then {_carkey = format["ItemKeyBlue%1",_keyid-5000];};
if ((_keyid > 7500) && (_keyid <= 10000)) then {_carkey = format["ItemKeyYellow%1",_keyid-7500];};
if ((_keyid > 10000) && (_keyid <= 12500)) then {_carkey = format["ItemKeyBlack%1",_keyid-10000];};
mazeObjects set [count mazeObjects,_object];
/* END spawn vehicle */

/* BEGIN create safe */
_position = [(_startPosition select 0) + (_mazeEnd select 0) * 2 * _halfMetalFloorSize, (_startPosition select 1) + (_mazeEnd select 1) * 2 * _halfMetalFloorSize, 0.2];
_object = createVehicle ["VaultStorage", [0,0], [], 0, "CAN_COLLIDE"];
_object setVariable ["ObjectID","1",true];
_object setVariable ["CharacterID","0",true];
_object setPos _position;
_object addWeaponCargoGlobal[_carkey,2];
mazeObjects set [count mazeObjects,_object];
/* END create safe */

/* BEGIN spawn wai bots */
_mazeBotGroup = [_position,_mazeBotCount,"Extreme","Random",4,"Random","Bandit","Random","Bandit"] call spawn_group;
{
	doStop _x;
	_x forceSpeed 0;
	/* _x disableAI "MOVE"; */
	_mazeBot_x = floor(random (_mazeWidth - 2)) + 1;
	_mazeBot_y = floor(random (_mazeHeight - 2)) + 1;
	_position = [(_startPosition select 0) + _mazeBot_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeBot_y * 2 * _halfMetalFloorSize, 0.2];
	_x setPos _position;
} forEach units _mazeBotGroup;
/* END spawn wai bots */

diag_log "end maze spawn";

Link to comment
Share on other sites

  • 2 months later...

hey L3G0, could you post your  custom_publish file?

I got it running so far, only the part with the carkey alludes me. :D

 

€: nevermind, figured that part out too.

 

the only thing now, that is not working the way I want it, is, how the bots spawn.

most of the time, they spawn at the entrance and not in the maze. can that be tweaked either?

 

€:€: figured that out as well. we had quiet our fun with it at our pvp/pve event today :)

Link to comment
Share on other sites

  • 2 years later...

Nice scripts... I hope I were here some years ago.
I'm working to make this work in 1.0.6.1 (maybe in 1.0.6.2)
 

generateMaze function

Spoiler

/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/

private ["_mazeWidth","_mazeHeight","_mazeCurWidth","_mazeCurHeight","_mazeDir","_position","_mazeNewWidth","_mazeNewHeight","_mazeNewDir","_mazeDirArray"];
_mazeWidth = _this select 0;
_mazeHeight = _this select 1;

/* don't run twice because this solution is not idempotent */
if (count mazeGlobalVisitArray > 0) exitWith { [[0,0],[0,0],[]] };

/* BEGIN Initialize */
mazeGlobalDistance = 0;
mazeGlobalMaxDistance = 0;
mazeGlobalVisitArray = [];
mazeGlobalChamberArray = [];
mazeGlobalMaxEndPoint = [];

/* init arrays */
for [{_i=0},{_i<_mazeHeight*_mazeWidth},{_i=_i+1}] do {
    mazeGlobalVisitArray set [_i,0];
    mazeGlobalChamberArray set [_i,9];
};

/* find start on top or bottom */
if ((random 1) < 0.5) then {
    _mazeCurWidth = floor(random _mazeWidth);
    if ((random 1) < 0.5) then {
        _mazeCurHeight = 0;
        /* _mazeDir = 1; */
    } else {
        _mazeCurHeight = _mazeHeight - 1;
        /* _mazeDir = 4; */
    };
/* find start left or right */
} else {
    _mazeCurHeight = floor(random _mazeHeight);
    if ((random 1) < 0.5) then {
        _mazeCurWidth = 0;
        /* _mazeDir = 8; */
    } else {
        _mazeCurWidth = _mazeWidth - 1;
        /* _mazeDir = 2; */
    };
};
/* END Initialize */

_recurse = {
    private ["_mazeWidth","_mazeHeight","_mazeCurWidth","_mazeCurHeight","_mazeDir","_position","_mazeNewWidth","_mazeNewHeight","_mazeNewDir","_mazeDirArray"];
    _mazeWidth = _this select 0;
    _mazeHeight = _this select 1;
    _mazeCurWidth = _this select 2;
    _mazeCurHeight = _this select 3;
    _mazeDir = _this select 4;
    
    /* this should never happen */
    if (_mazeCurWidth < 0 || _mazeCurHeight < 0) exitWith { 
        diag_log format["negative position!!! %1 x %2", _mazeCurWidth, _mazeCurHeight];
        [[0,0],[0,0],[]]
    };

    _position = _mazeCurWidth + (_mazeWidth * _mazeCurHeight);
    mazeGlobalVisitArray set [_position,1];
    mazeGlobalDistance = mazeGlobalDistance + 1;

    /* remove entry walls */
    if (_mazeDir == 0) then {
        if (_mazeCurHeight == 0) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1];
        };
        if (_mazeCurWidth == 0) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8];
        };
    } else {
        if (_mazeDir == 4) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1];
        };
        if (_mazeDir == 2) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8];
        };
    };
    _mazeDirArray = [1,2,4,8];

    while {count _mazeDirArray > 0} do {
        /* diag_log format["%1 position loop %2", _position, count _mazeDirArray];*/
        _mazeNewWidth = _mazeCurWidth;
        _mazeNewHeight = _mazeCurHeight;
        
        /*
        _random = floor (random count _mazeDirArray);
        _mazeNewDir = _mazeDirArray select _random;
        _mazeDirArray set [_random, _mazeDirArray select ((count _mazeDirArray) - 1)];
        _mazeDirArray resize ((count _mazeDirArray) - 1);
        */
        _mazeNewDir = _mazeDirArray call BIS_fnc_selectRandom;
        _mazeDirArray = _mazeDirArray - [_mazeNewDir];

        switch(_mazeNewDir) do {
            case 1: { _mazeNewHeight = _mazeNewHeight - 1; };
            case 2: { _mazeNewWidth = _mazeNewWidth + 1; };
            case 4: { _mazeNewHeight = _mazeNewHeight + 1; };
            case 8: { _mazeNewWidth = _mazeNewWidth - 1; };
        };

        /* invalid positions */
        if (_mazeNewWidth >= _mazeWidth || _mazeNewHeight >= _mazeHeight || _mazeNewWidth < 0 || _mazeNewHeight < 0) then {
            /* don't create wall if it is the start */
            if (_mazeDir != 0) then {
                /* add right line */
                if (_mazeNewWidth == _mazeWidth) then {
                    mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) + 2];
                };
                /* add bottom line */
                if (_mazeNewHeight == _mazeHeight) then {
                    mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) + 4];
                };
            } else {
                diag_log "prevent entrywall creation";
            };
        } else {
            /* diag_log format["%1 position %2", _position, _mazeNewDir]; */
            _mazeNewPosition = _mazeNewWidth + (_mazeWidth * _mazeNewHeight);
            /* diag_log format["new position %1 x %2 = %3", _mazeNewWidth, _mazeNewHeight, _mazeNewPosition]; */
            if ((mazeGlobalVisitArray select _mazeNewPosition) == 0) then {
                switch(_mazeNewDir) do {
                    case 1: { mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1]; };
                    case 8: { mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8]; };
                };
                [_mazeWidth,_mazeHeight,_mazeNewWidth,_mazeNewHeight,_mazeNewDir] call _recurse;
            };
        };
    };

    if (mazeGlobalDistance > mazeGlobalMaxDistance) then {
        mazeGlobalMaxEndPoint = [_mazeCurWidth,_mazeCurHeight];
        mazeGlobalMaxDistance = mazeGlobalDistance;
    };

    mazeGlobalDistance = mazeGlobalDistance -1;

    /* diag_log format["%1 reached end distance: %2", _position, mazeGlobalDistance]; */
};

[_mazeWidth,_mazeHeight,_mazeCurWidth,_mazeCurHeight,0] call _recurse;
/* generate return array */
_mazeReturnArray = [[_mazeCurWidth,_mazeCurHeight],mazeGlobalMaxEndPoint,mazeGlobalChamberArray];

/* cleanup for another run */
mazeGlobalVisitArray = [];
mazeGlobalChamberArray = [];
mazeGlobalDistance = 0;
mazeGlobalMaxDistance = 0;
mazeGlobalMaxEndPoint = [];

_mazeReturnArray
 

and mission
 

Spoiler

/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
};

*/

private ["_startPosition","_halfMetalFloorSize","_mazeHeight","_mazeWidth","_maze","_mazeStart","_mazeEnd","_mazeWalls","_mazeStartFloor","_x","_y","_object","_chamberConfig","_t1","_keyid","_carkey","_mazeBotGroup","_mazeBot_x","_mazeBot_y","_type","_handle"];
diag_log "[Maze]: starting maze spawn waiting for generateMaze";
waituntil{!isnil "generateMaze"};

_halfMetalFloorSize = 2.64;
mazeObjects = [];
_mazeWidth = 20;
_mazeHeight = 20;
_mazeBotCount = 20;

//_startPosition = [15000, 8000];//original position was out of map in chernarus
_startPosition = [((_mazeWidth max _mazeHeight) * _halfMetalFloorSize)] call find_position;

_t1 = diag_tickTime;
_maze = [_mazeWidth,_mazeHeight] call generateMaze;
diag_log format["[Maze]: creating Maze of size %1 x %2 took %3 ms", _mazeWidth, _mazeHeight, (diag_tickTime - _t1)];

_mazeStart = _maze select 0;
_mazeEnd = _maze select 1;
_mazeWalls = _maze select 2;
diag_log format["[Maze]: %1", _maze];

/* _mazeStartFloor = objNull;*/
/* attachTo needs enableSimulation true; :/
if (isNull _mazeStartFloor) then {
    _object setPos _startPosition;
    _mazeStartFloor = _object;
} else {
    _object attachTo [_mazeStartFloor, [_x * 2 * _halfMetalFloorSize, _y * 2 * _halfMetalFloorSize, 0]];
};
*/

for [{_y=0},{_y<_mazeHeight},{_y=_y+1}] do {
    for [{_x=0},{_x<_mazeWidth},{_x=_x+1}] do {
        _position = [(_startPosition select 0) + _x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _y * 2 * _halfMetalFloorSize];
        /* create floor */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos _position;
        mazeObjects set [count mazeObjects,_object];
        
        /* create roof */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos (_position + [3.2]);
        mazeObjects set [count mazeObjects,_object];
        
        /* create walls */
        _chamberConfig = _mazeWalls select (_x + _mazeWidth * _y);
        for [{_dir=1},{_dir<=8},{_dir=_dir*2}] do {
            _wallDir = 0;
            _wallPosition = [];

            switch (_dir) do { 
                case 1: { _wallPosition = [(_position select 0), (_position select 1) - _halfMetalFloorSize]; }; 
                case 2: { _wallPosition = [(_position select 0) + _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
                case 4: { _wallPosition = [(_position select 0), (_position select 1) + _halfMetalFloorSize]; }; 
                case 8: { _wallPosition = [(_position select 0) - _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
            };

            if (_chamberConfig % 2 == 1) then {
                _object = createVehicle ["CinderWall_DZ", [0,0], [], 0, "CAN_COLLIDE"];
                _object addEventHandler ["HandleDamage", {false}];
                _object enableSimulation false;
                _object setPos _wallPosition;
                _object setDir _wallDir;
                mazeObjects set [count mazeObjects,_object];
            };

            _chamberConfig = floor(_chamberConfig / 2);
        };
    };
};

/* BEGIN create start platform */
_mazeStartPlattformCenter_x = (_mazeStart select 0);
_mazeStartPlattformCenter_y = (_mazeStart select 1);

if (_mazeStartPlattformCenter_x <= 0 && _mazeStartPlattformCenter_y <= 0) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 2;
} else {
    if (_mazeStartPlattformCenter_x <= 0) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 3;
    };
    if (_mazeStartPlattformCenter_y <= 0) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 3;
    };
};

if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1) && _mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 2;
} else {
    if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1)) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 3;
    };
    if (_mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 3;
    };
};

for [{_y=-2},{_y<=2},{_y=_y+1}] do {
    for [{_x=-2},{_x<=2},{_x=_x+1}] do {
        _mazeStartPlattform_x = _mazeStartPlattformCenter_x + _x;
        _mazeStartPlattform_y = _mazeStartPlattformCenter_y + _y;
        if (_mazeStartPlattform_x >= _mazeWidth || _mazeStartPlattform_y >= _mazeHeight || _mazeStartPlattform_x < 0 || _mazeStartPlattform_y < 0) then {
            _position = [(_startPosition select 0) + _mazeStartPlattform_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattform_y * 2 * _halfMetalFloorSize];
            _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
            _object addEventHandler ["HandleDamage", {false}];
            _object enableSimulation false;
            _object setPos _position;
            mazeObjects set [count mazeObjects,_object];
        };
    };
};
/* END create start platform */

/* BEGIN spawn vehicle */
sleep 2;
_position = [(_startPosition select 0) + _mazeStartPlattformCenter_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattformCenter_y * 2 * _halfMetalFloorSize, 0.2];
_object = ["LAV25_HQ_DZE",_position,"maze",true,0] call custom_publish;
sleep 1;
_object setPos _position;
_object setFuel 1;
//_keyid = parseNumber(_object getVariable ["CharacterID", "0"]);
_keyid = ceil(random(12500));//(I spawn vehicles in mission unlocked, so lock it here)
_object setVariable ["CharacterID",str(_keyid),true];//
_object setvehiclelock "locked";//
[_object,6,4,30,0,1] call dynamic_crate;//

_carkey = "";
if ((_keyid > 0) && (_keyid <= 2500)) then {_carkey = format["ItemKeyGreen%1",_keyid];};
if ((_keyid > 2500) && (_keyid <= 5000)) then {_carkey = format["ItemKeyRed%1",_keyid-2500];};
if ((_keyid > 5000) && (_keyid <= 7500)) then {_carkey = format["ItemKeyBlue%1",_keyid-5000];};
if ((_keyid > 7500) && (_keyid <= 10000)) then {_carkey = format["ItemKeyYellow%1",_keyid-7500];};
if ((_keyid > 10000) && (_keyid <= 12500)) then {_carkey = format["ItemKeyBlack%1",_keyid-10000];};
mazeObjects set [count mazeObjects,_object];
/* END spawn vehicle */

/* BEGIN create safe */
_position = [(_startPosition select 0) + (_mazeEnd select 0) * 2 * _halfMetalFloorSize, (_startPosition select 1) + (_mazeEnd select 1) * 2 * _halfMetalFloorSize, 0.2];
_object = createVehicle ["VaultStorage", [0,0], [], 0, "CAN_COLLIDE"];
_object setVariable ["ObjectID","1",true];
_object setVariable ["CharacterID","0",true];
_object setVariable ["permaLoot",true];
_object setPos _position;
//_handle = ["maze",_position,"Maze",[(_mazeWidth * _halfMetalFloorSize * 2), (_mazeHeight * _halfMetalFloorSize * 2)]] spawn AIcity_marker;//(my server-side marker function..this just show(&delete) marker per 100 sec)
clearWeaponCargoGlobal _object;
clearMagazineCargoGlobal _object;
_object addWeaponCargoGlobal[_carkey,1];
mazeObjects set [count mazeObjects,_object];
dayz_serverObjectMonitor set [count dayz_serverObjectMonitor, _object];//save obj in 1061
/* END create safe */

/* BEGIN spawn wai bots */
_mazeBotGroup = [_position,_mazeBotCount,"easy","Revolver_DZ",4,"none","special",1,"Bandit"] call spawn_group;
{
    _mazeBot_x = floor(random (_mazeWidth - 2)) + 1;
    _mazeBot_y = floor(random (_mazeHeight - 2)) + 1;
    _position = [(_startPosition select 0) + _mazeBot_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeBot_y * 2 * _halfMetalFloorSize, 0.2];
    _x setPos _position;
    _x forceSpeed 0;
    doStop _x;
    _x disableAI "MOVE";
} forEach units _mazeBotGroup;
/* END spawn wai bots */

diag_log "[Maze]: end maze spawn";

while {_carkey in ((getWeaponCargo _object) select 0)} do {sleep 5;};// mission announce. wait for key taken
diag_log "[Maze]: Maze completed";
//terminate _handle;//
RemoteMessage = ["radio","[RADIO] The Maze is cleard."];//
publicVariable "RemoteMessage";//
{if((isPlayer _x) && (_x distance _object < _mazeWidth)) then {[nil,_x,"loc",rTITLETEXT,"Use the key to unlock the car outside.","PLAIN DOWN",5] call RE;diag_log format["[Maze]: %1 has cleard the maze",name _x];};} forEach playableUnits;//

 


To run this event once, I put this code into server_functions.sqf

Spoiler

//Maze
[] spawn {
    generateMaze = compile preprocessFileLineNumbers "\z\addons\dayz_server\addons\maze\mazegen.sqf";
    waitUntil{!isNil "wai_staticloaded"};
    waitUntil{wai_staticloaded};
    call compile preProcessFileLineNumbers "\z\addons\dayz_server\addons\maze\maze.sqf";
};


 

Link to comment
Share on other sites

  • 1 month later...
On 10.12.2017 at 3:04 PM, Schalldampfer said:

Nice scripts... I hope I were here some years ago.

lool cool, i never would have though someone would find this here again. :D

Thank you for sharing your changes! :)

 

I thought i would have to add this to DesolationREDUX to revive it myself, but i am glad to see there is still use for it in ArmA 2. <3

Link to comment
Share on other sites

  • 3 months later...
On 12/10/2017 at 11:04 PM, Schalldampfer said:

Nice scripts... I hope I were here some years ago.
I'm working to make this work in 1.0.6.1 (maybe in 1.0.6.2)
 

generateMaze function

  Reveal hidden contents

/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/

private ["_mazeWidth","_mazeHeight","_mazeCurWidth","_mazeCurHeight","_mazeDir","_position","_mazeNewWidth","_mazeNewHeight","_mazeNewDir","_mazeDirArray"];
_mazeWidth = _this select 0;
_mazeHeight = _this select 1;

/* don't run twice because this solution is not idempotent */
if (count mazeGlobalVisitArray > 0) exitWith { [[0,0],[0,0],[]] };

/* BEGIN Initialize */
mazeGlobalDistance = 0;
mazeGlobalMaxDistance = 0;
mazeGlobalVisitArray = [];
mazeGlobalChamberArray = [];
mazeGlobalMaxEndPoint = [];

/* init arrays */
for [{_i=0},{_i<_mazeHeight*_mazeWidth},{_i=_i+1}] do {
    mazeGlobalVisitArray set [_i,0];
    mazeGlobalChamberArray set [_i,9];
};

/* find start on top or bottom */
if ((random 1) < 0.5) then {
    _mazeCurWidth = floor(random _mazeWidth);
    if ((random 1) < 0.5) then {
        _mazeCurHeight = 0;
        /* _mazeDir = 1; */
    } else {
        _mazeCurHeight = _mazeHeight - 1;
        /* _mazeDir = 4; */
    };
/* find start left or right */
} else {
    _mazeCurHeight = floor(random _mazeHeight);
    if ((random 1) < 0.5) then {
        _mazeCurWidth = 0;
        /* _mazeDir = 8; */
    } else {
        _mazeCurWidth = _mazeWidth - 1;
        /* _mazeDir = 2; */
    };
};
/* END Initialize */

_recurse = {
    private ["_mazeWidth","_mazeHeight","_mazeCurWidth","_mazeCurHeight","_mazeDir","_position","_mazeNewWidth","_mazeNewHeight","_mazeNewDir","_mazeDirArray"];
    _mazeWidth = _this select 0;
    _mazeHeight = _this select 1;
    _mazeCurWidth = _this select 2;
    _mazeCurHeight = _this select 3;
    _mazeDir = _this select 4;
    
    /* this should never happen */
    if (_mazeCurWidth < 0 || _mazeCurHeight < 0) exitWith { 
        diag_log format["negative position!!! %1 x %2", _mazeCurWidth, _mazeCurHeight];
        [[0,0],[0,0],[]]
    };

    _position = _mazeCurWidth + (_mazeWidth * _mazeCurHeight);
    mazeGlobalVisitArray set [_position,1];
    mazeGlobalDistance = mazeGlobalDistance + 1;

    /* remove entry walls */
    if (_mazeDir == 0) then {
        if (_mazeCurHeight == 0) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1];
        };
        if (_mazeCurWidth == 0) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8];
        };
    } else {
        if (_mazeDir == 4) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1];
        };
        if (_mazeDir == 2) then {
            mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8];
        };
    };
    _mazeDirArray = [1,2,4,8];

    while {count _mazeDirArray > 0} do {
        /* diag_log format["%1 position loop %2", _position, count _mazeDirArray];*/
        _mazeNewWidth = _mazeCurWidth;
        _mazeNewHeight = _mazeCurHeight;
        
        /*
        _random = floor (random count _mazeDirArray);
        _mazeNewDir = _mazeDirArray select _random;
        _mazeDirArray set [_random, _mazeDirArray select ((count _mazeDirArray) - 1)];
        _mazeDirArray resize ((count _mazeDirArray) - 1);
        */
        _mazeNewDir = _mazeDirArray call BIS_fnc_selectRandom;
        _mazeDirArray = _mazeDirArray - [_mazeNewDir];

        switch(_mazeNewDir) do {
            case 1: { _mazeNewHeight = _mazeNewHeight - 1; };
            case 2: { _mazeNewWidth = _mazeNewWidth + 1; };
            case 4: { _mazeNewHeight = _mazeNewHeight + 1; };
            case 8: { _mazeNewWidth = _mazeNewWidth - 1; };
        };

        /* invalid positions */
        if (_mazeNewWidth >= _mazeWidth || _mazeNewHeight >= _mazeHeight || _mazeNewWidth < 0 || _mazeNewHeight < 0) then {
            /* don't create wall if it is the start */
            if (_mazeDir != 0) then {
                /* add right line */
                if (_mazeNewWidth == _mazeWidth) then {
                    mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) + 2];
                };
                /* add bottom line */
                if (_mazeNewHeight == _mazeHeight) then {
                    mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) + 4];
                };
            } else {
                diag_log "prevent entrywall creation";
            };
        } else {
            /* diag_log format["%1 position %2", _position, _mazeNewDir]; */
            _mazeNewPosition = _mazeNewWidth + (_mazeWidth * _mazeNewHeight);
            /* diag_log format["new position %1 x %2 = %3", _mazeNewWidth, _mazeNewHeight, _mazeNewPosition]; */
            if ((mazeGlobalVisitArray select _mazeNewPosition) == 0) then {
                switch(_mazeNewDir) do {
                    case 1: { mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 1]; };
                    case 8: { mazeGlobalChamberArray set [_position,(mazeGlobalChamberArray select _position) - 8]; };
                };
                [_mazeWidth,_mazeHeight,_mazeNewWidth,_mazeNewHeight,_mazeNewDir] call _recurse;
            };
        };
    };

    if (mazeGlobalDistance > mazeGlobalMaxDistance) then {
        mazeGlobalMaxEndPoint = [_mazeCurWidth,_mazeCurHeight];
        mazeGlobalMaxDistance = mazeGlobalDistance;
    };

    mazeGlobalDistance = mazeGlobalDistance -1;

    /* diag_log format["%1 reached end distance: %2", _position, mazeGlobalDistance]; */
};

[_mazeWidth,_mazeHeight,_mazeCurWidth,_mazeCurHeight,0] call _recurse;
/* generate return array */
_mazeReturnArray = [[_mazeCurWidth,_mazeCurHeight],mazeGlobalMaxEndPoint,mazeGlobalChamberArray];

/* cleanup for another run */
mazeGlobalVisitArray = [];
mazeGlobalChamberArray = [];
mazeGlobalDistance = 0;
mazeGlobalMaxDistance = 0;
mazeGlobalMaxEndPoint = [];

_mazeReturnArray
 

and mission
 

  Reveal hidden contents

/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
};

*/

private ["_startPosition","_halfMetalFloorSize","_mazeHeight","_mazeWidth","_maze","_mazeStart","_mazeEnd","_mazeWalls","_mazeStartFloor","_x","_y","_object","_chamberConfig","_t1","_keyid","_carkey","_mazeBotGroup","_mazeBot_x","_mazeBot_y","_type","_handle"];
diag_log "[Maze]: starting maze spawn waiting for generateMaze";
waituntil{!isnil "generateMaze"};

_halfMetalFloorSize = 2.64;
mazeObjects = [];
_mazeWidth = 20;
_mazeHeight = 20;
_mazeBotCount = 20;

//_startPosition = [15000, 8000];//original position was out of map in chernarus
_startPosition = [((_mazeWidth max _mazeHeight) * _halfMetalFloorSize)] call find_position;

_t1 = diag_tickTime;
_maze = [_mazeWidth,_mazeHeight] call generateMaze;
diag_log format["[Maze]: creating Maze of size %1 x %2 took %3 ms", _mazeWidth, _mazeHeight, (diag_tickTime - _t1)];

_mazeStart = _maze select 0;
_mazeEnd = _maze select 1;
_mazeWalls = _maze select 2;
diag_log format["[Maze]: %1", _maze];

/* _mazeStartFloor = objNull;*/
/* attachTo needs enableSimulation true; :/
if (isNull _mazeStartFloor) then {
    _object setPos _startPosition;
    _mazeStartFloor = _object;
} else {
    _object attachTo [_mazeStartFloor, [_x * 2 * _halfMetalFloorSize, _y * 2 * _halfMetalFloorSize, 0]];
};
*/

for [{_y=0},{_y<_mazeHeight},{_y=_y+1}] do {
    for [{_x=0},{_x<_mazeWidth},{_x=_x+1}] do {
        _position = [(_startPosition select 0) + _x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _y * 2 * _halfMetalFloorSize];
        /* create floor */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos _position;
        mazeObjects set [count mazeObjects,_object];
        
        /* create roof */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos (_position + [3.2]);
        mazeObjects set [count mazeObjects,_object];
        
        /* create walls */
        _chamberConfig = _mazeWalls select (_x + _mazeWidth * _y);
        for [{_dir=1},{_dir<=8},{_dir=_dir*2}] do {
            _wallDir = 0;
            _wallPosition = [];

            switch (_dir) do { 
                case 1: { _wallPosition = [(_position select 0), (_position select 1) - _halfMetalFloorSize]; }; 
                case 2: { _wallPosition = [(_position select 0) + _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
                case 4: { _wallPosition = [(_position select 0), (_position select 1) + _halfMetalFloorSize]; }; 
                case 8: { _wallPosition = [(_position select 0) - _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
            };

            if (_chamberConfig % 2 == 1) then {
                _object = createVehicle ["CinderWall_DZ", [0,0], [], 0, "CAN_COLLIDE"];
                _object addEventHandler ["HandleDamage", {false}];
                _object enableSimulation false;
                _object setPos _wallPosition;
                _object setDir _wallDir;
                mazeObjects set [count mazeObjects,_object];
            };

            _chamberConfig = floor(_chamberConfig / 2);
        };
    };
};

/* BEGIN create start platform */
_mazeStartPlattformCenter_x = (_mazeStart select 0);
_mazeStartPlattformCenter_y = (_mazeStart select 1);

if (_mazeStartPlattformCenter_x <= 0 && _mazeStartPlattformCenter_y <= 0) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 2;
} else {
    if (_mazeStartPlattformCenter_x <= 0) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 3;
    };
    if (_mazeStartPlattformCenter_y <= 0) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 3;
    };
};

if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1) && _mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 2;
} else {
    if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1)) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 3;
    };
    if (_mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 3;
    };
};

for [{_y=-2},{_y<=2},{_y=_y+1}] do {
    for [{_x=-2},{_x<=2},{_x=_x+1}] do {
        _mazeStartPlattform_x = _mazeStartPlattformCenter_x + _x;
        _mazeStartPlattform_y = _mazeStartPlattformCenter_y + _y;
        if (_mazeStartPlattform_x >= _mazeWidth || _mazeStartPlattform_y >= _mazeHeight || _mazeStartPlattform_x < 0 || _mazeStartPlattform_y < 0) then {
            _position = [(_startPosition select 0) + _mazeStartPlattform_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattform_y * 2 * _halfMetalFloorSize];
            _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
            _object addEventHandler ["HandleDamage", {false}];
            _object enableSimulation false;
            _object setPos _position;
            mazeObjects set [count mazeObjects,_object];
        };
    };
};
/* END create start platform */

/* BEGIN spawn vehicle */
sleep 2;
_position = [(_startPosition select 0) + _mazeStartPlattformCenter_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattformCenter_y * 2 * _halfMetalFloorSize, 0.2];
_object = ["LAV25_HQ_DZE",_position,"maze",true,0] call custom_publish;
sleep 1;
_object setPos _position;
_object setFuel 1;
//_keyid = parseNumber(_object getVariable ["CharacterID", "0"]);
_keyid = ceil(random(12500));//(I spawn vehicles in mission unlocked, so lock it here)
_object setVariable ["CharacterID",str(_keyid),true];//
_object setvehiclelock "locked";//
[_object,6,4,30,0,1] call dynamic_crate;//

_carkey = "";
if ((_keyid > 0) && (_keyid <= 2500)) then {_carkey = format["ItemKeyGreen%1",_keyid];};
if ((_keyid > 2500) && (_keyid <= 5000)) then {_carkey = format["ItemKeyRed%1",_keyid-2500];};
if ((_keyid > 5000) && (_keyid <= 7500)) then {_carkey = format["ItemKeyBlue%1",_keyid-5000];};
if ((_keyid > 7500) && (_keyid <= 10000)) then {_carkey = format["ItemKeyYellow%1",_keyid-7500];};
if ((_keyid > 10000) && (_keyid <= 12500)) then {_carkey = format["ItemKeyBlack%1",_keyid-10000];};
mazeObjects set [count mazeObjects,_object];
/* END spawn vehicle */

/* BEGIN create safe */
_position = [(_startPosition select 0) + (_mazeEnd select 0) * 2 * _halfMetalFloorSize, (_startPosition select 1) + (_mazeEnd select 1) * 2 * _halfMetalFloorSize, 0.2];
_object = createVehicle ["VaultStorage", [0,0], [], 0, "CAN_COLLIDE"];
_object setVariable ["ObjectID","1",true];
_object setVariable ["CharacterID","0",true];
_object setVariable ["permaLoot",true];
_object setPos _position;
//_handle = ["maze",_position,"Maze",[(_mazeWidth * _halfMetalFloorSize * 2), (_mazeHeight * _halfMetalFloorSize * 2)]] spawn AIcity_marker;//(my server-side marker function..this just show(&delete) marker per 100 sec)
clearWeaponCargoGlobal _object;
clearMagazineCargoGlobal _object;
_object addWeaponCargoGlobal[_carkey,1];
mazeObjects set [count mazeObjects,_object];
dayz_serverObjectMonitor set [count dayz_serverObjectMonitor, _object];//save obj in 1061
/* END create safe */

/* BEGIN spawn wai bots */
_mazeBotGroup = [_position,_mazeBotCount,"easy","Revolver_DZ",4,"none","special",1,"Bandit"] call spawn_group;
{
    _mazeBot_x = floor(random (_mazeWidth - 2)) + 1;
    _mazeBot_y = floor(random (_mazeHeight - 2)) + 1;
    _position = [(_startPosition select 0) + _mazeBot_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeBot_y * 2 * _halfMetalFloorSize, 0.2];
    _x setPos _position;
    _x forceSpeed 0;
    doStop _x;
    _x disableAI "MOVE";
} forEach units _mazeBotGroup;
/* END spawn wai bots */

diag_log "[Maze]: end maze spawn";

while {_carkey in ((getWeaponCargo _object) select 0)} do {sleep 5;};// mission announce. wait for key taken
diag_log "[Maze]: Maze completed";
//terminate _handle;//
RemoteMessage = ["radio","[RADIO] The Maze is cleard."];//
publicVariable "RemoteMessage";//
{if((isPlayer _x) && (_x distance _object < _mazeWidth)) then {[nil,_x,"loc",rTITLETEXT,"Use the key to unlock the car outside.","PLAIN DOWN",5] call RE;diag_log format["[Maze]: %1 has cleard the maze",name _x];};} forEach playableUnits;//

 


To run this event once, I put this code into server_functions.sqf

  Reveal hidden contents

//Maze
[] spawn {
    generateMaze = compile preprocessFileLineNumbers "\z\addons\dayz_server\addons\maze\mazegen.sqf";
    waitUntil{!isNil "wai_staticloaded"};
    waitUntil{wai_staticloaded};
    call compile preProcessFileLineNumbers "\z\addons\dayz_server\addons\maze\maze.sqf";
};


 

the second sqf (mission) updated for new WAI:
 

Spoiler

/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    L3G0 SQF Maze Generator https://epochmod.com/forum/topic/30393-sqf-maze-generator/?do=findComment&comment=191592

[] spawn {
    generateMaze = compile preprocessFileLineNumbers "\z\addons\dayz_server\addons\maze\mazegen.sqf";
    waitUntil{!isNil "wai_staticloaded"};
    waitUntil{wai_staticloaded};
    call compile preProcessFileLineNumbers "\z\addons\dayz_server\addons\maze\maze.sqf";
};

*/

private ["_startPosition","_halfMetalFloorSize","_mazeHeight","_mazeWidth","_maze","_mazeStart","_mazeEnd","_mazeWalls","_mazeStartFloor","_x","_y","_object","_chamberConfig","_t1","_keyid","_carkey","_mazeBotGroup","_mazeBot_x","_mazeBot_y","_type","_area","_dots","_title","_crate","_car","_mazeObjects"];
diag_log "[Maze]: starting maze spawn waiting for generateMaze";
waituntil{!isnil "generateMaze"};
_halfMetalFloorSize = 2.64;
_mazeObjects = [];
_mazeWidth = 14;
_mazeHeight = 14;
_mazeBotCount = 12;

waituntil{!isnil "get_trader_markers"};//
trader_markers = call get_trader_markers;//
_startPosition = [((_mazeWidth max _mazeHeight) * _halfMetalFloorSize)] call find_position;//

_t1 = diag_tickTime;
_maze = [_mazeWidth,_mazeHeight] call generateMaze;
diag_log format["[Maze]: creating Maze of size %1 x %2 took %3 ms", _mazeWidth, _mazeHeight, (diag_tickTime - _t1)];

_mazeStart = _maze select 0;
_mazeEnd = _maze select 1;
_mazeWalls = _maze select 2;
diag_log format["[Maze]: %1", _maze];

for [{_y=0},{_y<_mazeHeight},{_y=_y+1}] do {
    for [{_x=0},{_x<_mazeWidth},{_x=_x+1}] do {
        _position = [(_startPosition select 0) + _x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _y * 2 * _halfMetalFloorSize];
        /* create floor */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos _position;
        _mazeObjects set [count _mazeObjects,_object];
        
        /* create roof */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos (_position + [3.2]);
        _mazeObjects set [count _mazeObjects,_object];
        
        /* create walls */
        _chamberConfig = _mazeWalls select (_x + _mazeWidth * _y);
        for [{_dir=1},{_dir<=8},{_dir=_dir*2}] do {
            _wallDir = 0;
            _wallPosition = [];

            switch (_dir) do { 
                case 1: { _wallPosition = [(_position select 0), (_position select 1) - _halfMetalFloorSize]; }; 
                case 2: { _wallPosition = [(_position select 0) + _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
                case 4: { _wallPosition = [(_position select 0), (_position select 1) + _halfMetalFloorSize]; }; 
                case 8: { _wallPosition = [(_position select 0) - _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
            };

            if (_chamberConfig % 2 == 1) then {
                _object = createVehicle ["CinderWall_DZ", [0,0], [], 0, "CAN_COLLIDE"];
                _object addEventHandler ["HandleDamage", {false}];
                _object enableSimulation false;
                _object setPos _wallPosition;
                _object setDir _wallDir;
                _mazeObjects set [count _mazeObjects,_object];
            };

            _chamberConfig = floor(_chamberConfig / 2);
        };
    };
};

/* BEGIN create start platform */
_mazeStartPlattformCenter_x = (_mazeStart select 0);
_mazeStartPlattformCenter_y = (_mazeStart select 1);

if (_mazeStartPlattformCenter_x <= 0 && _mazeStartPlattformCenter_y <= 0) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 2;
} else {
    if (_mazeStartPlattformCenter_x <= 0) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 3;
    };
    if (_mazeStartPlattformCenter_y <= 0) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 3;
    };
};

if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1) && _mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 2;
} else {
    if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1)) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 3;
    };
    if (_mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 3;
    };
};

for [{_y=-2},{_y<=2},{_y=_y+1}] do {
    for [{_x=-2},{_x<=2},{_x=_x+1}] do {
        _mazeStartPlattform_x = _mazeStartPlattformCenter_x + _x;
        _mazeStartPlattform_y = _mazeStartPlattformCenter_y + _y;
        if (_mazeStartPlattform_x >= _mazeWidth || _mazeStartPlattform_y >= _mazeHeight || _mazeStartPlattform_x < 0 || _mazeStartPlattform_y < 0) then {
            _position = [(_startPosition select 0) + _mazeStartPlattform_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattform_y * 2 * _halfMetalFloorSize];
            if (surfaceIsWater _position) then {
                _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
            } else {
                _object = createVehicle ["Sr_border", [0, 0], [], 0, "CAN_COLLIDE"];
            };
            _object allowDammage false;
            _object enableSimulation false;
            _object setPos _position;
            _mazeObjects set [count _mazeObjects,_object];
        };
    };
};
/* END create start platform */

/* BEGIN create safe */
_position = [(_startPosition select 0) + (_mazeEnd select 0) * 2 * _halfMetalFloorSize, (_startPosition select 1) + (_mazeEnd select 1) * 2 * _halfMetalFloorSize, 0.2];
_crate = createVehicle ["USBasicAmmunitionBox", [0,0], [], 0, "CAN_COLLIDE"];//"VaultStorage"
_crate setPos _position;
_crate call wai_crate_setup;
_mazeObjects set [count _mazeObjects,_crate];
/* END create safe */

/* BEGIN spawn vehicle */
sleep 2;
_position = [(_startPosition select 0) + _mazeStartPlattformCenter_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattformCenter_y * 2 * _halfMetalFloorSize, 0.2];
_type = ["BRDM2_INS","BTR60_TK_EP1","BMP2_HQ_INS","M113_TK_EP1_DZE","BAF_Jackal2_GMG_D"] call BIS_fnc_selectRandom;
_car = [_crate,_type,_position,-1,true,0] call custom_publish;
sleep 1;
_car setPos _position;
_keyid = parseNumber(_car getVariable ["CharacterID", "0"]);
if (_keyid == 0) then {
    _keyid = ceil(random(12500));
    _car setVariable ["CharacterID",str(_keyid),true];
};
_car setvehiclelock "locked";

_carkey = "";
if ((_keyid > 0) && (_keyid <= 2500)) then {_carkey = format["ItemKeyGreen%1",_keyid];};
if ((_keyid > 2500) && (_keyid <= 5000)) then {_carkey = format["ItemKeyRed%1",_keyid-2500];};
if ((_keyid > 5000) && (_keyid <= 7500)) then {_carkey = format["ItemKeyBlue%1",_keyid-5000];};
if ((_keyid > 7500) && (_keyid <= 10000)) then {_carkey = format["ItemKeyYellow%1",_keyid-7500];};
if ((_keyid > 10000) && (_keyid <= 12500)) then {_carkey = format["ItemKeyBlack%1",_keyid-10000];};
_mazeObjects set [count _mazeObjects,_car];
/* END spawn vehicle */

/* BEGIN spawn wai bots */
_mazeBotGroup = [_position,_mazeBotCount,"easy","Revolver_DZ",4,"none","special",1,"Bandit"] call spawn_group;
{
    _mazeBot_x = floor(random (_mazeWidth - 2)) + 1;
    _mazeBot_y = floor(random (_mazeHeight - 2)) + 1;
    _position = [(_startPosition select 0) + _mazeBot_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeBot_y * 2 * _halfMetalFloorSize, 0.2];
    _x setPos _position;
    _x forceSpeed 0;
    doStop _x;
    _x disableAI "MOVE";
} forEach units _mazeBotGroup;
/* END spawn wai bots */

 

//add rewards
[_car,[[4,ai_wep_special_good],[4,crate_tools_sniper],[25,crate_items_president],[2,ai_wep_special_rare],[1,crate_backpacks_large]]] call dynamic_crate;//
if ( !(_carkey in ((getWeaponCargo _crate) select 0)) ) then {//
    _crate addWeaponCargoGlobal[_carkey,1];//
};//

diag_log "[Maze]: end maze spawn";
RemoteMessage = ["radio","[RADIO] A-mazing maze has been spawned! Who solve it first?"];//
publicVariable "RemoteMessage";//

//wait for players
_title = format["maze%1",round(serverTime/60)];
while { ({(alive _x) && (_x distance _crate <= (_mazeWidth * _halfMetalFloorSize * 2) )} count playableUnits) < 1 } do {
    _area = createMarker [_title, _position];
    _area setMarkerColor "ColorOrange";
    _area setMarkerShape "RECTANGLE";
    _area setMarkerBrush "Horizontal";
    _area setMarkerSize [(_mazeWidth * _halfMetalFloorSize * 2), (_mazeHeight * _halfMetalFloorSize * 2)];
    _dots = createMarker [_title+"_dot", _position];
    _dots setMarkerText "Maze";
    _dots setMarkerType "mil_dot";
    _dots setMarkerColor "ColorRed";
    sleep 7;
    deleteMarker _area;
    deleteMarker _dots;
};

//activate AIs
{
    _x enableAI "MOVE";
} forEach units _mazeBotGroup;
diag_log "[Maze]: someone in maze";

//wait for clear
while {_carkey in ((getWeaponCargo _crate) select 0)} do {
    _area = createMarker [_title, _position];
    _area setMarkerColor "ColorRed";
    _area setMarkerShape "RECTANGLE";
    _area setMarkerBrush "Horizontal";
    _area setMarkerSize [(_mazeWidth * _halfMetalFloorSize * 2), (_mazeHeight * _halfMetalFloorSize * 2)];
    _dots = createMarker [_title+"_dot", _position];
    _dots setMarkerText "Maze";
    _dots setMarkerType "mil_dot";
    _dots setMarkerColor "ColorOrange";
    sleep 1;
    deleteMarker _area;
    deleteMarker _dots;
};//

diag_log "[Maze]: Maze completed";
RemoteMessage = ["radio","[RADIO] The Maze is cleard."];//
publicVariable "RemoteMessage";//
{if((isPlayer _x) && (_x distance _crate < _mazeWidth)) then {[nil,_x,"loc",rTITLETEXT,"Use the key to unlock the car outside.","PLAIN DOWN",5] call RE;diag_log format["[Maze]: %1 has cleard the maze",name _x];};} forEach playableUnits;//
MazeDone = true;

 

Link to comment
Share on other sites

new version to despawn maze after clearing
maze.sqf

Spoiler

/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    L3G0 SQF Maze Generator https://epochmod.com/forum/topic/30393-sqf-maze-generator/?do=findComment&comment=191592

[] spawn {
    generateMaze = compile preprocessFileLineNumbers "\z\addons\dayz_server\addons\maze\mazegen.sqf";
    waitUntil{!isNil "wai_staticloaded"};
    waitUntil{wai_staticloaded};
    call compile preProcessFileLineNumbers "\z\addons\dayz_server\addons\maze\maze.sqf";
};

*/

private ["_startPosition","_halfMetalFloorSize","_mazeHeight","_mazeWidth","_maze","_mazeStart","_mazeEnd","_mazeWalls","_mazeStartFloor","_x","_y","_object","_chamberConfig","_t1","_keyid","_carkey","_mazeBotGroup","_mazeBot_x","_mazeBot_y","_type","_area","_dots","_title","_crate","_car","_mazeObjects","_mission"];
diag_log "[Maze]: starting maze spawn waiting for generateMaze";
waituntil{!isnil "generateMaze"};
_halfMetalFloorSize = 2.64;
_mazeObjects = [];
_mazeWidth = 14;
_mazeHeight = 14;
_mazeBotCount = 12;

wai_mission_data = wai_mission_data + [[0,[],[],[],[],[],[]]];
_mission = count wai_mission_data -1;
_startPosition = [((_mazeWidth max _mazeHeight) * _halfMetalFloorSize)] call find_position;

_t1 = diag_tickTime;
_maze = [_mazeWidth,_mazeHeight] call generateMaze;
diag_log format["[Maze]: creating Maze of size %1 x %2 took %3 ms", _mazeWidth, _mazeHeight, (diag_tickTime - _t1)];

_mazeStart = _maze select 0;
_mazeEnd = _maze select 1;
_mazeWalls = _maze select 2;
diag_log format["[Maze]: %1", _maze];

/* _mazeStartFloor = objNull;*/
/* attachTo needs enableSimulation true; :/
if (isNull _mazeStartFloor) then {
    _object setPos _startPosition;
    _mazeStartFloor = _object;
} else {
    _object attachTo [_mazeStartFloor, [_x * 2 * _halfMetalFloorSize, _y * 2 * _halfMetalFloorSize, 0]];
};
*/

for [{_y=0},{_y<_mazeHeight},{_y=_y+1}] do {
    for [{_x=0},{_x<_mazeWidth},{_x=_x+1}] do {
        _position = [(_startPosition select 0) + _x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _y * 2 * _halfMetalFloorSize];
        /* create floor */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos _position;
        _mazeObjects set [count _mazeObjects,_object];
        
        /* create roof */
        _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
        _object addEventHandler ["HandleDamage", {false}];
        _object enableSimulation false;
        _object setPos (_position + [3.2]);
        _mazeObjects set [count _mazeObjects,_object];
        
        /* create walls */
        _chamberConfig = _mazeWalls select (_x + _mazeWidth * _y);
        for [{_dir=1},{_dir<=8},{_dir=_dir*2}] do {
            _wallDir = 0;
            _wallPosition = [];

            switch (_dir) do { 
                case 1: { _wallPosition = [(_position select 0), (_position select 1) - _halfMetalFloorSize]; }; 
                case 2: { _wallPosition = [(_position select 0) + _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
                case 4: { _wallPosition = [(_position select 0), (_position select 1) + _halfMetalFloorSize]; }; 
                case 8: { _wallPosition = [(_position select 0) - _halfMetalFloorSize, (_position select 1)]; _wallDir = 90;}; 
            };

            if (_chamberConfig % 2 == 1) then {
                _object = createVehicle ["CinderWall_DZ", [0,0], [], 0, "CAN_COLLIDE"];
                _object addEventHandler ["HandleDamage", {false}];
                _object enableSimulation false;
                _object setPos _wallPosition;
                _object setDir _wallDir;
                _mazeObjects set [count _mazeObjects,_object];
            };

            _chamberConfig = floor(_chamberConfig / 2);
        };
    };
};

/* BEGIN create start platform */
_mazeStartPlattformCenter_x = (_mazeStart select 0);
_mazeStartPlattformCenter_y = (_mazeStart select 1);

if (_mazeStartPlattformCenter_x <= 0 && _mazeStartPlattformCenter_y <= 0) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 2;
} else {
    if (_mazeStartPlattformCenter_x <= 0) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x - 3;
    };
    if (_mazeStartPlattformCenter_y <= 0) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y - 3;
    };
};

if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1) && _mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
    _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 2;
    _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 2;
} else {
    if (_mazeStartPlattformCenter_x >= (_mazeWidth - 1)) then {
        _mazeStartPlattformCenter_x = _mazeStartPlattformCenter_x + 3;
    };
    if (_mazeStartPlattformCenter_y >= (_mazeHeight - 1)) then {
        _mazeStartPlattformCenter_y = _mazeStartPlattformCenter_y + 3;
    };
};

for [{_y=-2},{_y<=2},{_y=_y+1}] do {
    for [{_x=-2},{_x<=2},{_x=_x+1}] do {
        _mazeStartPlattform_x = _mazeStartPlattformCenter_x + _x;
        _mazeStartPlattform_y = _mazeStartPlattformCenter_y + _y;
        if (_mazeStartPlattform_x >= _mazeWidth || _mazeStartPlattform_y >= _mazeHeight || _mazeStartPlattform_x < 0 || _mazeStartPlattform_y < 0) then {
            _position = [(_startPosition select 0) + _mazeStartPlattform_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattform_y * 2 * _halfMetalFloorSize];
            if (surfaceIsWater _position) then {
                _object = createVehicle ["MetalFloor_DZ", [0, 0], [], 0, "CAN_COLLIDE"];
            } else {
                _object = createVehicle ["Sr_border", [0, 0], [], 0, "CAN_COLLIDE"];
            };
            _object allowDammage false;
            _object enableSimulation false;
            _object setPos _position;
            //_mazeObjects set [count _mazeObjects,_object];
        };
    };
};
/* END create start platform */

/* BEGIN create safe */
_position = [(_startPosition select 0) + (_mazeEnd select 0) * 2 * _halfMetalFloorSize, (_startPosition select 1) + (_mazeEnd select 1) * 2 * _halfMetalFloorSize, 0.2];
_crate = createVehicle ["USBasicAmmunitionBox", [0,0], [], 0, "CAN_COLLIDE"];//"VaultStorage"
_crate setPos _position;
_crate call wai_crate_setup;
/* END create safe */

/* BEGIN spawn vehicle */
sleep 2;
_position = [(_startPosition select 0) + _mazeStartPlattformCenter_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeStartPlattformCenter_y * 2 * _halfMetalFloorSize, 0.2];
_type = ["BMP2_HQ_CDF","M113_PMC","LAV25_HQ_DZE","HMMWV_M998_crows_MK19_DES_EP1","GAZ_Vodnik_DZE"] call BIS_fnc_selectRandom;
_car = [_type,_position,_mission,true,0] call custom_publish;
sleep 1;
_car setPos _position;
_keyid = ceil(random(12499) + 1);
_car setVariable ["CharacterID",str(_keyid),true];
_car setvehiclelock "locked";

_carkey = "";
if ((_keyid > 0) && (_keyid <= 2500)) then {_carkey = format["ItemKeyGreen%1",_keyid];};
if ((_keyid > 2500) && (_keyid <= 5000)) then {_carkey = format["ItemKeyRed%1",_keyid-2500];};
if ((_keyid > 5000) && (_keyid <= 7500)) then {_carkey = format["ItemKeyBlue%1",_keyid-5000];};
if ((_keyid > 7500) && (_keyid <= 10000)) then {_carkey = format["ItemKeyYellow%1",_keyid-7500];};
if ((_keyid > 10000) && (_keyid <= 12500)) then {_carkey = format["ItemKeyBlack%1",_keyid-10000];};
/* END spawn vehicle */

/* BEGIN spawn wai bots */
_mazeBotGroup = [_position,_mazeBotCount,"easy","Makarov_SD_DZ",4,"none","special",1,"Bandit"] call spawn_group;
{
    _mazeBot_x = floor(random (_mazeWidth - 2)) + 1;
    _mazeBot_y = floor(random (_mazeHeight - 2)) + 1;
    _position = [(_startPosition select 0) + _mazeBot_x * 2 * _halfMetalFloorSize, (_startPosition select 1) + _mazeBot_y * 2 * _halfMetalFloorSize, 0.2];
    _x setPos _position;
    _x forceSpeed 0;
    doStop _x;
    _x disableAI "MOVE";
} forEach units _mazeBotGroup;
/* END spawn wai bots */

[_car,[[4,ai_wep_sniper],[4,crate_tools_buildable],[25,(crate_items_wood + crate_items_buildables + crate_items_vehicle_repair + crate_items_misc)],[2,(ai_wep_machine)],[1,crate_backpacks_large]]] call dynamic_crate;//
if ( !(_carkey in ((getWeaponCargo _crate) select 0)) ) then {
    _crate addWeaponCargoGlobal[_carkey,1];
};
{ _x setVectorUp surfaceNormal position _x; } count _mazeObjects;
_car setVectorUp surfaceNormal position _car;
_crate setVectorUp surfaceNormal position _crate;

WAI_MarkerReady        = true;
diag_log "[Maze]: end maze spawn";
RemoteMessage = ["radio","A-mazing maze has been spawned! Who solve it first?"];
publicVariable "RemoteMessage";

//wait for players
_position = [(_startPosition select 0) + _mazeWidth * _halfMetalFloorSize, (_startPosition select 1) + _mazeHeight * _halfMetalFloorSize];
_title = format["maze%1",round(serverTime/60)];
while { ({(alive _x) && (_x distance _crate <= (_mazeWidth * _halfMetalFloorSize * 1.42) )} count playableUnits) < 1 } do {
    _area = createMarker [_title, _position];
    _area setMarkerColor "ColorOrange";
    _area setMarkerShape "RECTANGLE";
    _area setMarkerBrush "Horizontal";
    _area setMarkerSize [(_mazeWidth * _halfMetalFloorSize * 2), (_mazeHeight * _halfMetalFloorSize * 2)];
    _dots = createMarker [_title+"_dot", _position];
    _dots setMarkerText "Maze";
    _dots setMarkerType "mil_dot";
    _dots setMarkerColor "ColorRed";
    sleep 7;
    deleteMarker _area;
    deleteMarker _dots;
};

//activate AIs
{
    _x enableAI "MOVE";
} forEach units _mazeBotGroup;
diag_log "[Maze]: someone in maze";

//wait for clear
while {_carkey in ((getWeaponCargo _crate) select 0)} do {
    _area = createMarker [_title, _position];
    _area setMarkerColor "ColorRed";
    _area setMarkerShape "RECTANGLE";
    _area setMarkerBrush "Horizontal";
    _area setMarkerSize [(_mazeWidth * _halfMetalFloorSize * 2), (_mazeHeight * _halfMetalFloorSize * 2)];
    _dots = createMarker [_title+"_dot", _position];
    _dots setMarkerText "Maze";
    _dots setMarkerType "mil_dot";
    _dots setMarkerColor "ColorOrange";
    sleep 1;
    deleteMarker _area;
    deleteMarker _dots;
};

diag_log "[Maze]: Maze completed";
RemoteMessage = ["radio","The Maze is cleard."];
publicVariable "RemoteMessage";
{if((isPlayer _x) && (_x distance _crate < _mazeWidth)) then {[nil,_x,"loc",rTITLETEXT,"Use the key to unlock the car outside.","PLAIN DOWN",5] call RE;diag_log format["[Maze]: %1 has cleard the maze",name _x];};} forEach playableUnits;

MazeDone = true;
wai_mission_data set [_mission, -1];

//kill AIs
{
    _x setDamage 1;
} forEach units _mazeBotGroup;

//remove walls
{
    _x setDamage 1;
} forEach _mazeObjects;
sleep 1;
{
    deleteVehicle _x;
} forEach _mazeObjects;
 


and this is the script to spawn maze after clearing

Spoiler


//Maze
[] spawn {
    sleep (300 + (random 900));
    MazeDone = true;
    generateMaze = compile preprocessFileLineNumbers "\z\addons\dayz_server\addons\maze\mazegen.sqf";
    waitUntil{!isNil "wai_staticloaded"};
    waitUntil{wai_staticloaded};
    while {true} do {
        if (MazeDone) then {
            [] execVM "\z\addons\dayz_server\addons\maze\maze.sqf";
            MazeDone = false;
        };
        sleep 120 + (random 480);
    };
};
 

(maze.sqf must have MazeDone=true;)

Edited by Schalldampfer
update for WAI2.2.6
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Discord

×
×
  • Create New...