Ninjaisfast 0 Posted June 30, 2019 Me again. I'm trying to execute a script from an addAction. I simply want to cancel an active script (which is started from an action) by starting another script from an action, but that requires the script I want to cancel to have a script handle, which as far as I can tell, a script from an addAction doesn't have. All actions are on the same object. (and run from init field) How I am starting the script that runs, which I want to cancel (runs and passes argument fine): this addAction ["Yellow","script.sqf",yellow,1,false,true,"","",2]; What I've tried: this addAction ["Green",{_scriptHandle = []execVM "script.sqf"},green,1,false,true,"","",2]; And putting things in the [ ] before execVM. But I can't work out how to correctly pass the arguments. In the script.sqf, the destination (green in this case) is selected through: _destinationName = _this select 3 ; But this doesn't work properly if I try to execVM it. script_cancel.sqf will just terminate the script handle. this addAction ["CANCEL","script_cancel.sqf",nil,1,false,true,"","",2]; How do I pass the arguments correctly if I'm running the script from execVM, or can I just put something in the start of my script.sqf to give it a handle? Thanks in advance ❤️ Share this post Link to post Share on other sites
Ninjaisfast 0 Posted June 30, 2019 Worked it out, posting solution in case anyone has similar troubles. this addAction ["Green",{ScriptHandle = [_this select 0, _this select 1, _this select 2, green] execVM "script.sqf"},nil,1,false,true,"","",2]; Cancel via terminate ScriptHandle . Share this post Link to post Share on other sites
mrcurry 496 Posted July 1, 2019 Nice @Ninjaisfast but it is not very robust. If you ever need to use it on a separate object you're going to have issues with handles overwriting each other. A safer place to store your handle is in the variable space of the object it's attached to. //This is the code that goes into your action call params ["_target", "_caller", "_id"]; private _handle = [_target, _caller, _id, green] execVM "someScript.sqf"; _target setVariable ["someScript_handle", _handle]; //In the cancel action you use terminate (_this#0 getVariable ["someScript_handle", scriptNull]); Also keep in mind what happens if the player activates the action again before cancel is used and make sure you handle that in your script. --- Speaking of robustness. I wouldn't recommend the use of terminate, at least not as the go to make-awesome-script-go-stop tool. When terminate is used the script will stop immediately and you often can't be 100% sure at which stage your initial script is at when it's terminated. A bit like pulling the plug. Imagine a script controlling a set of traffic lights. While the light is on a script is running a loop switching the colors of the lights from green to yellow to red etc. When we want to simulate someone cutting the power the light is supposed to go dark. We don't need the script anymore since the light is off so we terminate it... and the light gets stuck on red, forever... but the power is supposed to be off? How the f...? Oh! We forgot to do cleanup on this particular set off lights... #VintageCurry Of course this is just a silly example that a quick band-aid fix can sort out. However in more complex work it is not always so trivial to 1. know what the last state was and 2. return to the Null-state. The alternative practice: Build the termination procedure into the script instead and allow for a graceful shutdown. Define variables and conditions that will trigger termination and use those to make sure the script terminates gracefully when the time comes. More work I know but not that much, and besides, it keeps things self-contained, reusable and reduces the risk for bugs to sneak in. Super-simple example of the alternative: Spoiler The script: /* This code assumes a call from addAction but can in essence be used anywhere as long as you provide a neat and isolated place to store the data. Object variable spaces are usually the best in my experience. In this case the kill-switch variable is stored in the _target's variable space */ params ["_target", "_caller", "_id", "_args"]; //Set up the kill-switch _target setVariable ["TAG_arbitraryVarName", true]; //Run ze loop while { _target getVariable "TAG_arbitraryVarName" } do { //Light goes Green //Light goes Yellow //Light goes Red }; //Here you can clean up after yourself in a nice controllable fashion. No need for a R.U.D. //Light goes Black To cancel the script: object setVariable ["TAG_arbitraryVarName", false]; Now don't get me wrong, terminate still has it uses. If there's no cleanup needed or the script in question is simple it can be a shortcut that saves a few cycles, or if something's gone horribly wrong terminate can save the day. Anyway... *end rant* 3 Share this post Link to post Share on other sites
Ninjaisfast 0 Posted July 1, 2019 5 hours ago, mrcurry said: Speaking of robustness. I wouldn't recommend the use of terminate, at least not as the go to make-awesome-script-go-stop tool. ... The alternative practice: Build the termination procedure into the script instead and allow for a graceful shutdown. Define variables and conditions that will trigger termination and use those to make sure the script terminates gracefully when the time comes. You knew exactly the problems I would run into before I ran into them. What I hard worked fine if I did things exactly as I wanted a person to, but once I started behaving more randomly, errors snuck in due to terminate not working how I wanted it to. I ended up doing things pretty similar to how you recommended. My new cancel action sets a global variable tripCancelled to true, which is checked in every loop of the other script. If its true, it cancels things gracefully. The cancel action also resets the tripCancelled variable back to false a few seconds later, to stop issues if someone were to try to cancel before running the actual script. On another note, terminate seems really weird. If a player runs the same looping script twice (lets just say a countdown from 100), then terminates the script handle, it seems to only terminate the last instance of it being run, and even scriptDone shows that the script is complete, even though the first instance is still running (visibly still counting down). Does a script handle change if its used twice, or something that I'm not grasping? Share this post Link to post Share on other sites
sarogahtyp 1108 Posted July 1, 2019 a script handle is unique for each script instance. this means u need a different script handle variable (or better an array) for each started script instance... terminate is not weird. it just does what you order ... 1 Share this post Link to post Share on other sites
pierremgi 4850 Posted July 1, 2019 sure. And it will not end all spawned sub-scripts inside the one you want to terminate. They have their own "life" (in parallel). 1 Share this post Link to post Share on other sites
Dedmen 2692 Posted July 2, 2019 19 hours ago, Ninjaisfast said: If a player runs the same looping script twice If you put the handle into a variable you will OVERWRITE the variable when you put the second handle into it. A variable can't know what values it might've had in the past. So your first handle is just gone. 1 Share this post Link to post Share on other sites
Ninjaisfast 0 Posted July 2, 2019 That makes a lot more sense now, thanks everyone. Share this post Link to post Share on other sites