[evo] dan 79 Posted December 24, 2014 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
jshock 512 Posted December 25, 2014 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
[evo] dan 79 Posted December 25, 2014 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
[evo] dan 79 Posted December 25, 2014 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
jshock 512 Posted December 26, 2014 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
[evo] dan 79 Posted December 26, 2014 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
jshock 512 Posted December 26, 2014 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
[evo] dan 79 Posted December 26, 2014 (edited) 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 December 26, 2014 by [EVO] Dan Share this post Link to post Share on other sites
jshock 512 Posted December 27, 2014 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
[evo] dan 79 Posted December 27, 2014 (edited) 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 December 27, 2014 by [EVO] Dan Share this post Link to post Share on other sites
[evo] dan 79 Posted December 27, 2014 (edited) 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 December 27, 2014 by [EVO] Dan Share this post Link to post Share on other sites
[evo] dan 79 Posted December 27, 2014 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