Jump to content
Sign in to follow this  
[evo] dan

Best way to pass a starting position through and EVH?

Recommended Posts

Hi all,

I'm trying to make a script that respawns one of several crates after 1 has been destroyed. I am wondering if I can pass the starting position of each of the crates through the event handler so that on the box being destroyed, it'll automatically respawn back at base where it started for reuse. At the moment I have used a non-local variable, but obviously that gets overwritten everytime the original script is called. I don't think that I can change the variable and then having a different one for each without copying the script multiple times (or could a function solve this?).

I am also open to any other methods of doing this, but I thought that the EVH would be the most CPU efficient way of doing it.

This is the way that I am currently doing it, but obviously it runs into the overwriting issue that I have described.

First call:

//Get objects original name
_box = _this select 0;

//Get object type so it can be used later
_type = typeOf _box;
pos = getPosASL _box;

//create event handlers to detect the object having been moved.
_box addMPEventHandler ["mpkilled", {[(_this select 0),pos] execVM "BoxCreator.sqf";}];
hint "evh added";

BoxCreator.sqf:

//Get objects original name
_box = _this select 0;
number = _this select 1;

//Get object type so it can be used later
_type = typeOf _box;

//Remove event handler and delete box
_box removeMPEventHandler ["mpkilled", 0];
deleteVehicle _box;
hint format ["%1 Poof!", number];

//Spawn New Box
_newBox = _type createVehicle number;
_newBox addMPEventHandler ["mpkilled", {[(_this select 0),number] execVM "BoxCreator.sqf";}];
hint "new evh added";

So, in summary, this is the desired behaviour:

-I have multiple boxes at base.

-1 gets destroyed and then ONLY that box is respawned back at base at its starting position.

Share this post


Link to post
Share on other sites

Try this in your call line within the EH:

[(_this select 0), getPosATL (_this select 1)] execVM "BoxCreator.sqf";

Remove all your "pos" stuff, and now (_this select 1) in your BoxCreator.sqf will be the position of the old box, no need for any global variables, so make them local. And do the same as above with the EH changes in the BoxCreator.sqf.

Share this post


Link to post
Share on other sites

Yes, seems to work, thanks for that, somehow I couldn't get it to work before. Anyway, heres the code that I am using:

To call use:

[box1] execVM "BoxRespawn.sqf";

Where box1 is the name of your object.

BoxRespawn.sqf:

//Get objects original name
_box = _this select 0;

//create event handlers to detect the object having been moved.
_box addMPEventHandler ["mpkilled", {[(_this select 0), getPosATL (_this select 1)] execVM "BoxCreator.sqf";}];

BoxCreator.sqf:

//Get objects original name
_box = _this select 0;
_number = _this select 1;

//Get object type so it can be used later
_type = typeOf _box;

//Remove event handler and delete box
_box removeMPEventHandler ["mpkilled", 0];
deleteVehicle _box;

//Spawn New Box
_newBox = _type createVehicle _number;
_newBox addMPEventHandler ["mpkilled", {[(_this select 0), getPosATL (_this select 1)] execVM "BoxCreator.sqf";}];

Yes I could probably merge the 2 scripts and do a check within them, but it works well enough as it is. (and I might have some extra stuff to put into the first script for the box)

Share this post


Link to post
Share on other sites

Just did more testing, box respawns near where it was destroyed, not where it started the game as desired.

Share this post


Link to post
Share on other sites

You didn't say that the boxes were moved, in that case you will probably need to use get/set variable and set the variable value as it's original position (server side).

Share this post


Link to post
Share on other sites

Heres what I have go to work for me in the way I intended:

BoxRespawn.sqf:

//Get objects original name
_box = _this select 0;
_pos = getPosATL _box;
_varname = format ["%1", _box];

//put the starting position into a variable
_box setVariable [_varname, [_pos select 0, _pos select 1, _pos select 2], false];

//create event handlers to detect the object having been moved.
_box addMPEventHandler ["mpkilled", {[(_this select 0)] execVM "BoxCreator.sqf";}];

BoxCreator.sqf:

//Get objects original name
_box = _this select 0;

//Fetch the original position
_varname = format ["%1", _box];
_objVar = _box getVariable _varname;
_box setVariable [_varname, nil, false];

//Get object type so it can be used later
_type = typeOf _box;

//Remove event handler and delete box
_box removeMPEventHandler ["mpkilled", 0];
deleteVehicle _box;

//Spawn New Box
_newBox = _type createVehicle [_objVar select 0, _objVar select 1, _objVar select 2];
_newVarname = format ["%1", _newBox];
_newBox addMPEventHandler ["mpkilled", {[(_this select 0)] execVM "BoxCreator.sqf";}];
_newBox setVariable [_newVarname, [_objVar select 0, _objVar select 1, _objVar select 2], false];

Share this post


Link to post
Share on other sites

That'll work, FYI it's a position, just put the variable name, no need for:

[_var select 0, _var select 1, _var select 2];
//same as
_var;

Share this post


Link to post
Share on other sites

I accidently went a bit further, and built this into a way I could do this in a persistent manner so on reload of the mission, the boxes would be where they were last time, provided you haven't done a restart on the mission. I think this is more of what I wanted then I had originally imagined! So I am going to post it all up here for you guys to look at and for you to use. If you want to use it properly in the mission, I recommend removing the addActions and putting them elsewhere within your mission to do it automatically for you so that the players do not have to worry about it. I'd also recommend changing the profileNamespace variables to something different and unique so that they are unlikely to be overwritten by a different mission.

Init.sqf:

//set the run counter to zero
_run1 = 0;

//Add the addActions
player addAction ["Save Stuff", "SaveProfile.sqf"];
player addAction ["Clear Stuff", "ClearProfile.sqf"];

//serverside stuff
if(isServer) then {
//get any variables needed
ArrayPos = profileNamespace getVariable ["positionVars", [[0,0,0],[0,0,0]]];
ArrayResp = profileNamespace getVariable ["respawnablesArray", [box1, box2]];
RespawnPos = [[0,0,0],[0,0,0]]; //init the respawn positions for the boxes

//if the array of positions is empty, then set the mission up for first run
if((ArrayPos select 0) select 1 == 0) then {
	_run1 = 1;
};

_arraySize = (count ArrayResp) -1; //fetch size of the array for the for loop counting

//for loop for doing any needed position changes on reload (not restart)
for "_x" from 0 to _arraySize do
{
	_currentObject = ArrayResp select _x; //Get current object
	_pos = getPosATL _currentObject; //get current objects position
	RespawnPos set [_x, _pos]; //add the current objects starting position to the respawn position array
	[_currentObject,0] execVM "BoxRespawnAlt.sqf"; //put current name and a 0 into the respawn script
	//if first time run, set current pos as the respawn pos, else move the 
	if(_run1 == 1) then {
		ArrayPos set [_x, _pos]; //if first run, build up the position array
	} else {
		_objPos = ArrayPos select _x; //if not first run, then move objects to previous positions
		_currentObject setPosATL (_objPos);
	};
};
profileNamespace setVariable ["positionVars", ArrayPos]; //save the positions just in case
saveProfileNamespace;
};

BoxRespawnAlt.sqf:

_box = _this select 0; //get objects name
_firstRun = _this select 1; //is it the first run?
_arraySize = (count ArrayResp) -1; //get the array size for the for loop

for "_x" from 0 to _arraySize do
{
_currentObject = ArrayResp select _x; //Select current object
if(_box == _currentObject) then {
	if(_firstRun == 1) then { //if not first run, execute this code
		_box removeMPEventHandler ["mpkilled", 0]; //remove old event handler
		_type = typeOf _box; //get object type
		deleteVehicle _box; //delete dead object
		_RespPos = RespawnPos select _x; //get the respawn pos relating to the current object
		_newBox = _type createVehicle (_RespPos); //create a new object at the respawn pos
		_newBox addMPEventHandler ["mpkilled", {[(_this select 0),1] execVM "BoxRespawnAlt.sqf";}]; //add the event handler
		ArrayResp set [_x, _newBox]; //update the position in case
	} else { //if first run, simply add the event handler
		_box addMPEventHandler ["mpkilled", {[(_this select 0),1] execVM "BoxRespawnAlt.sqf";}];
	};
};
};

SaveProfile.sqf:

_myCount = (count ArrayResp) -1; //get array size ready for the for lopp
for "_x" from 0 to _myCount do
{
_currentElement = ArrayResp select _x; //get current object
_pos = getPosATL _currentElement; //get current objects position
ArrayPos set [_x, _pos]; //update the array
};
profileNamespace setVariable ["positionVars", ArrayPos];
saveProfileNamespace; //save the array for future usage

ClearProfile.sqf:

profileNamespace setVariable ["positionVars", nil]; //set both arrays to nil in order to clear them out
profileNamespace setVariable ["respawnablesArray", nil];
saveProfileNamespace; //save profile so that the variables are deleted from it.

I also have a version of this that gives you the choice whether or not to active the R3F creation factory on a particular object as well, with a case structure allowing some flexibility in what kind of setup the object has (or doesn't have).

I think I could use on one saved variable if I used a multi-dimensioned array, but I am not sure if the 'set' command supports that. Does anybody know if it does?

Enjoy and thanks for the help!

Edited by [EVO] Dan

Share this post


Link to post
Share on other sites

Use the pushBack command, it's faster and easier to understand.

_exampleArray = [];//simply empty to start

_firstArr = [1,2,3];
_secondArr = [4,5,6];

_exampleArray pushBack _firstArr;
_exampleArray pushBack _secondArr;

//output (value of _exampleArray)
[[1,2,3],[4,5,6]]

Share this post


Link to post
Share on other sites
Use the pushBack command, it's faster and easier to understand.

_exampleArray = [];//simply empty to start

_firstArr = [1,2,3];
_secondArr = [4,5,6];

_exampleArray pushBack _firstArr;
_exampleArray pushBack _secondArr;

//output (value of _exampleArray)
[[1,2,3],[4,5,6]]

I couldn't find a way to get the 'set' command to do multi-dimensioned arrays.

At the moment I have it set up so that on reloading the mission, the previous objects will match up in the array position wise as the name of any respawned objects will have been different. Using pushback would seemingly change that so I think i'll be sticking to the way I have done it at the moment, unless anyone has a better solution to this.

I know on loading the mission the names will not match up, but the order in which it is read will mean that when they are read in order, they move the correct object to the correct position with the correct R3F status. I think the only way to do it different, could be that if the names aren't the same, delete the placed objects and create a new object with the properties of the objects in the array, although I would need to also include the type so that it spawns the correct object, and then I could use pushBack as the information would not matter which order it was put in.

But what would then be the best way of replacing data within the array when it needs updating?

Should I stick with the current method of assigning a name to each element?

Also, what would the best way of searching through the array and then pulling out the subarray with all the data in it for positions and type?

So, in summary, this is what I have done:

-A couple of named objects have been preplaced on the map at the start.

-These objects can be slingloaded or moved via the R3F logitics script to other places.

-At some point in the mission, either a save or a clearing of the profileNamespace can happen, which will update the last positions/reset them so that when the mission is reloaded, the objects will be moved to their previous position if it is different to the start position/a non-zero position exists in the stored array.

-Each object needs to have its name stored, its position stored and what type of R3F it is allowed to have (a number).

Edited by [EVO] Dan

Share this post


Link to post
Share on other sites

Just been having a further play with the stuff and I got it working in what I think could be a more efficient way.

Init.sqf:

//init the logistics script
execVM "R3F_LOG\init.sqf";

//Add the addActions
player addAction ["Save Stuff", "SaveProfile.sqf"];
player addAction ["Clear Stuff", "ClearProfile.sqf"];

//get the variable with the objects info in
ArrayDetails = profileNamespace getVariable ["ArrayDetails", []];
_arraySize = (count ArrayDetails);//check the array size

//if array is empty, then put in the default values into the array
if(_arraySize == 0) then {
_part1 = [box1,"B_supplyCrate_F",[3770,7942,0.5],1,1,[3770,7942,0.5]];
_part2 = [box2,"B_supplyCrate_F",[3775,7945,0.5],0,1,[3775,7945,0.5]];
ArrayDetails pushBack _part1;
ArrayDetails pushBack _part2;
};

//Check array size again
_arraySize = (count ArrayDetails) -1; 
for "_x" from 0 to _arraySize do {
_currentObject = ArrayDetails select _x; //get currently active object info
_box = _currentObject select 0; //get current objects name
[_box] execVM "BoxRespawn.sqf"; //call the event handler/respawn script
};

BoxRespawn.sqf:

_boxIn = _this select 0; //get the objects name that was just destroyed
_arraySize = (count ArrayDetails) -1; //get array size
for "_x" from 0 to _arraySize do {
_currentObject = ArrayDetails select _x; //get subarray for current object
_box = _currentObject select 0;
_type = _currentObject select 1;
_pos = _currentObject select 2;
_R3FYN = _currentObject select 3;
_firstRun = _currentObject select 4;
_defaultPos = _currentObject select 5;
if(_box == _boxIn) then { //when a match has been found then activate
	if(_firstRun == 1) then { //if first run, simply respawn at last saved position and add the event handler
		_box = _type createVehicle (_pos);
		_box addMPEventHandler ["mpkilled", {[_this select 0] execVM "BoxRespawn.sqf";}];
		_firstRun = 0;
	} else { //if not first run, respawn back at base
		deleteVehicle _boxIn;
		_box = _type createVehicle (_defaultPos);
		_box addMPEventHandler ["mpkilled", {[_this select 0] execVM "BoxRespawn.sqf";}];
		_firstRun = 0;
		_pos = _defaultPos; //reset the saved pos back to the default position
	};
	switch (_R3FYN) do {
	case 0: { };
	case 1: {[_box, -1, west, "MEDIUM"] execVM "R3F_LOG\USER_FUNCT\init_creation_factory.sqf"};
	};
	_putTogetherArray = [_box, _type, _pos, _R3FYN, _firstRun, _defaultPos]; //put array back together
	ArrayDetails = ArrayDetails - [_currentObject]; //remove old info
	ArrayDetails pushBack _putTogetherArray; //put the info at the back of the array
};
};

SaveProfile.sqf:

_arraySize = (count ArrayDetails) - 1; //get array size
for "_x" from 0 to _arraySize do
{
_currentObject = ArrayDetails select _x; //get the subarray with the current objects info in it.
_box = _currentObject select 0;
_type = _currentObject select 1;
_R3FYN = _currentObject select 3;
_firstRun = 1; //reset first run counter so that it spawns correctly in future
_defaultPos = _currentObject select 5;
_pos = getPosATL _box; //get current objects position
_putTogetherArray = [_box, _type, _pos, _R3FYN, _firstRun, _defaultPos]; //put info back together
ArrayDetails = ArrayDetails - [_currentObject]; //take the old info out of the array
ArrayDetails pushBack _putTogetherArray; //put the new info into the array at the back
};
profileNamespace setVariable ["ArrayDetails", ArrayDetails]; //set the variable in the profileNamespace
saveProfileNamespace; //save the array for future usage

ClearProfile.sqf:

profileNamespace setVariable ["ArrayDetails", nil]; //set array to nil in order to clear them out
saveProfileNamespace; //save profile so that the variables are deleted from it.

Now i've just got to work on creating persistance for more things.

Edited by [EVO] Dan

Share this post


Link to post
Share on other sites

I have tried taking it further, but keep running into issues when booting up on a locally hosted dedicated server (via tadst). Heres the folder if anyone want to try it out:

https://dl.dropboxusercontent.com/u/28062918/EVO_Stratis_Clearance.Stratis.rar

Main issues I seem to run into:

-When reloading the mission, I have to rejoin in order for me to be moved back to my old position before I disconnected.

-Ammoboxes seem to no longer want to spawn.

I tried in the editor, the ammboxes spawn, but I get the following error in the logs for BoxRespawn.sqf:

20:33:17 Error in expression <tPos = _currentObject select 5;
if(_box == _boxIn) then { 
if(_firstRun == 1) th>
20:33:17   Error position: <== _boxIn) then { 
if(_firstRun == 1) th>
20:33:17   Error Generic error in expression

Can anybody help me out with this?

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×