Jump to content
Heavensrevenger

Run loop in init field with suspension

Recommended Posts

I know .sqf is generally better but i would like to save the props as a composition so i can just place it down in different missions. Is there a way to run loops in the init field WITH suspension. Sleep doesnt seem to work.

Share this post


Link to post
Share on other sites

The spawned code seems to have trouble running local variables.

_attach = nearestObject [this, "B_Plane_CAS_01_F"];
x = true;

nul = [] spawn {
 while {x} do {
  sleep 1;
  if (!alive _attach) then {
   deletevehicle _attach; 
   this setDamage 1; 
  };
 };
};

how can I define them in the code? If i put the definition in the spawned code it tells me that "this" is not defined, but how do I define "this" without knowing the location of the object?

Share this post


Link to post
Share on other sites

youve defined _attach outside of the spawns scope so it doesnt know what it is. needs to be passed as an argument
Without testing... you might need to pass 'this' on the same way. I cant remember
 

_attach = nearestObject [this, "B_Plane_CAS_01_F"];
x= true;

nul = _attach spawn {
 while {x} do {
  sleep 1;
  if (!alive _this) then {
   deletevehicle _this; 
   this setDamage 1; 
  };
 };
};

now any time '_this' is listed after spawn it represents all the arguments given to the 'spawn' command. Since youre ONLY passing '_attach'. it means _this == _attach.
 

Share this post


Link to post
Share on other sites

_this is refering to a different object than _attach, how do i pass _this aswell as _attach to the code?
Edit: or rather, how do i pass 2 different local variables to the code?

Share this post


Link to post
Share on other sites

You can either give your editor object a variable name, in which case you don't need to pass it (it is global) - for this example I will use "myObject":

_attach = nearestObject [myObject, "B_Plane_CAS_01_F"];
x = true;

nul = _attach spawn {
	while {x} do {
		sleep 1;
		if (!alive _attach) then {
			deletevehicle _attach; 
			myObject setDamage 1;
			x = false;
		};
	};
};

...or you can assign it a local variable and pass both local vars in an array:

_myObject = this;
_attach = nearestObject [_myObject, "B_Plane_CAS_01_F"];
x = true;

nul = [_myObject, _attach] spawn {
	params ["_myObject","_attach"];
	while {x} do {
		sleep 1;
		if (!alive _attach) then {
			deletevehicle _attach; 
			_myObject setDamage 1;
			x = false;
		};
	};
};

I have also set your var "x" to false when the loop's inner condition is met, otherwise it will continue running after the objects are detached/deleted.

  • Like 1

Share this post


Link to post
Share on other sites

also, unless you need to set 'x' from outside the script, you can do this instead
 

_myObject = this;
_attach = nearestObject [_myObject, "B_Plane_CAS_01_F"];

nul = [_myObject, _attach] spawn {
	params ["_myObject","_attach"];
	waitUntil{!alive _attach};
    deletevehicle _attach; 
    _myObject setDamage 1;
};

 

  • Like 1

Share this post


Link to post
Share on other sites
On 12/22/2023 at 4:54 PM, j0nes said:

nul = [_myObject, _attach] spawn { params ["_myObject","_attach"]; waitUntil{!alive _attach}; deletevehicle _attach; _myObject setDamage 1; };


so this isnt exactly the same as the script I made the topic for but still very similar so I figured Id just ask:
when changing  _myObject inside the called script is there a way to pass the variable back to the original script?

for instance with this code

private _maxradius = 1000; 
private _increaseradius = 10; 
private _radius = 0;

nul = [_maxradius, _increaseradius, _radius] spawn { 
 params ["_maxradius", "_increaseradius", "_radius"]; 
 _increaseradius = _maxradius / _increaseradius / 10;
 while { _radius < _maxradius } do {
  _radius = _radius + _increaseradius;
  sleep 0.1;
 };
};

nul = [_maxradius, _increaseradius, _radius] spawn { 
 params ["_maxradius", "_increaseradius", "_radius"]; 
 sleep 4;
 hint str _radius;
};

how can I, in a seperately spawned script, find out the _radius after 4 seconds?

Share this post


Link to post
Share on other sites

Im a little confused on what youre asking. You want to check what _myObject is every 4 seconds?

Share this post


Link to post
Share on other sites
11 hours ago, Heavensrevenger said:


so this isnt exactly the same as the script I made the topic for but still very similar so I figured Id just ask:
when changing  _myObject inside the called script is there a way to pass the variable back to the original script?

for instance with this code


private _maxradius = 1000; 
private _increaseradius = 10; 
private _radius = 0;

nul = [_maxradius, _increaseradius, _radius] spawn { 
 params ["_maxradius", "_increaseradius", "_radius"]; 
 _increaseradius = _maxradius / _increaseradius / 10;
 while { _radius < _maxradius } do {
  _radius = _radius + _increaseradius;
  sleep 0.1;
 };
};

nul = [_maxradius, _increaseradius, _radius] spawn { 
 params ["_maxradius", "_increaseradius", "_radius"]; 
 sleep 4;
 hint str _radius;
};

how can I, in a seperately spawned script, find out the _radius after 4 seconds?

 

Use global variable  (myRadius instead of _myRadius)

but the question is: what do you want to do, exactly? I bet there is a better solution than running loop(s) for something in init field of an object, but who knows? could you explain your goal?

 

Perhaps, you are referring to Eden_Editor:_Custom_Composition ?

especially the Automating_Composition_Creation

This code works in editor only, if you create specific layers with a specific names (here all layers with  "SPE_Comp_" in name, case sensitive).  You can't use it in a init field (run at start, not in editor), but straight in console.

 

In game, there is no command/function for composition.

 

 

  • Like 1

Share this post


Link to post
Share on other sites
10 hours ago, j0nes said:

Im a little confused on what youre asking. You want to check what _myObject is every 4 seconds?

 

Yes and no, in the code i posted _myObject is _radius and i want to check that after 4 seconds, but i want to check it in a different spawned code. So as the code is right now it will say _radius is 0 becasue thats what i defined it as at the start but i want it to tell me what _radius is after 4 seconds of running the first spawned code.
 

10 hours ago, pierremgi said:

Use global variable  (myRadius instead of _myRadius)

 

This would work by simply using a global variable, however i want to copy the prop im using so that would break the code. (If what im trying to do isnt possible global variables will have to do)

 

10 hours ago, pierremgi said:

Perhaps, you are referring to Eden_Editor:_Custom_Composition ?

especially the Automating_Composition_Creation

 

Im not sure what you mean, but I dont want to spawn a composition in a running mission if thats what youre getting at

PS: for clarity, the code i want to make is basically increasing a circle beginning from an object and then checking for anyone in the circle / damage them, i may be able to make it work within one spawned code however as the codes have to run at the same time (increasing radius and damaging player) i figured itd be tidier to have multiple spawned codes that each have their own purposes (one spawned code increases radius the other spawned code damages units)
Then why not simply increase the radius after damaging the units and use just one single code? Because im still unsure wheter or not i will need waitUntil or run more loops within the codes which would then offset the expansion of the circle.


Also should I start a new topic for this or change the title?

Share this post


Link to post
Share on other sites

Ok I have more questions. do you want to simulate a bomb blast that radiates outwards very quickly? or do you just want to increase the radius every 4 seconds?
if its just every 4 seconds (untested) do this:
 

nul = [_myObject, _attach] spawn {
	params ["_myObject","_attach"];
	waitUntil{!alive _attach};
	deletevehicle _attach;
	_myObject setDamage 1;
	[getPos _myObject]spawn
	{
		params["_center"];
		_radius = 100; //end radius
		_inc = 25; //how much to increase the radius by each loop
		_delta = 4; //how much time to wait between each loop
		_totalLoops = ceil(_radius/_inc);
		for "_i" from 1 to _totalLoops do
		{
			_currRad = (_inc*_i) min _radius;
			_nearSoldiers = nearestObjects [_center,["man"],_currRad];
			{
				_x setDamage 1;
			}forEach _nearSoldiers;
			sleep _delta;
		};
	};
};


 

Share this post


Link to post
Share on other sites

more like a bomb blast as youve coded however i want the soldiers taking damage to linger forever while the radius stays the same eventually. For that you can just do another loop after the "for "_i" from 1 to _totalLoops do" loop but what i was originally getting at is that you pass the _currRad variable outward to a different spawned code (so basically having 2 nul = [_myObject, _attach] spawn {}; that share the _currRad variable). I hope I made understandable what im looking for

Also im sorry for probably causing alot of confusion by not starting a new topic. The code im making is different from the original code that uses _myObject and _attach but i thought since it's this thread that taught me to spawn code and pass local variable into said spawned code, itd make sense to ask how to pass local variables back out of spawned code.

Share this post


Link to post
Share on other sites
43 minutes ago, Heavensrevenger said:

i want the soldiers taking damage to linger forever

hmmmm not sure exactly what you mean by this. Can you tell us more generally what this script is going to do? like what part of the mission its for? (e.g. A plane drops a radioactive bomb and as long as the bomb is alive, anyone in that radius takes damage)

Share this post


Link to post
Share on other sites

I dont really want to make a certain campaign or anything i just want to write to script to run it and be proud when it works, also to get better at scripting obviously. The plan is to make something radioactive in gerneral. A zone slowly expands around an object and anyone inside takes damage. The zone eventually stops increasing in size but soldiers who enter the zone should obvously still die. Add to that maybe some visual effect and buidings also taking damage but only till they are 50% down to simulate like corrosion or something. I havent started coding yet but i know its doable and i could do it , but i wanted to know if i can have seperate codes running simultaneously to keep things more organized i guess. As in the 1. Spawned Code expands the circle, then the 2. Spawned code checks for units in the circle and deals damage and the 3. spawned code deals damage to buildings. This would work with global variables as the 2nd spawned code could "ask" the first how large the circle is but using global variables would mean that I cant copy and paste the object without also going into the code and adding a number behind each global variable (The circle around one radioactive zone may not be as big as the one of a different zone). So my idea was that there might be a way to pass the local variable from the first spawned code to the second. If there is none then i will have to run the code in a single spawned code which would also work.
This was really just me thinking in advance hoping to have a tidier / more segmented code.
I feel like its still pretty badly explained so ill try to create a problem i might run into:
If the soldier only takes 0.1 damage and the time between being damaged is random, you could something like sleep random 10;  however i also want to keep expanding the overall radius of the radiation at a steady pace. In this case running 2 codes at the same time would be useful.
You could also create a random number _x and then add 1 to _y everytime the code runs and the soldier takes damage if _y is greater than _x. That would mean the code has no suspension and the radius expanison at the beginning of the loop continues at a steady pace. 
Idk to be honest. I just want to run 2 codes at the same time that share a local variable. Im gonna post this because I wrote it all and dont want to delete it but i will probably just start writing the code and then make a new topic if i run into a problem, that way there is a good example of what i mean to solve.

Share this post


Link to post
Share on other sites

Ok, last effort because I think I know how to communitcate what I need 😅
I don't need to know how to code the radiation or if its possible because I know it is and I know how. But I was speculating that there was a better way to do things

Basic example code, where I want to know _radius after 4 seconds:

Option A: The one where I know it works however the code to announce the radius after 4 seconds is inside the code that increases the radius (Somewhat untidy, can get confusing with longer code)
 

private _maxradius = 1000; 
private _radius = 1;

nul = [_maxradius, _radius] spawn { 
 params ["_maxradius", "_radius"];
 _x = 0;
 while { _radius < _maxradius } do {
  _radius = _radius * 2;
  if (_x == 4) then {
   hint str _radius;
  };
  _x = _x + 1;
  sleep 1;
 };
};

 


Option B: The way it is right now it doesn't work but it would be more tidy and compact as the code to announce the radius is separated from the code increasing the radius
 

private _maxradius = 1000; 
private _radius = 1;

nul = [_maxradius, _radius] spawn { 
 params ["_maxradius", "_radius"]; 
 while { _radius < _maxradius } do {
  _radius = _radius * 2;
  sleep 1;
 };
};

nul = [_maxradius, _radius] spawn { 
 params ["_maxradius", "_radius"]; 
 sleep 4;
 hint str _radius;
};


Code A would hint I believe "32" while code B would say "1", I know A works but what I'm looking for is a way to make code B also say "32" without using global variables or calculating the radius inside the second spawned code / use hint in the first spawned code.
I think/hope this is more understandable.

Share this post


Link to post
Share on other sites
13 hours ago, Heavensrevenger said:

Ok, last effort because I think I know how to communitcate what I need 😅
I don't need to know how to code the radiation or if its possible because I know it is and I know how. But I was speculating that there was a better way to do things

Basic example code, where I want to know _radius after 4 seconds:

Option A: The one where I know it works however the code to announce the radius after 4 seconds is inside the code that increases the radius (Somewhat untidy, can get confusing with longer code)
 


private _maxradius = 1000; 
private _radius = 1;

nul = [_maxradius, _radius] spawn { 
 params ["_maxradius", "_radius"];
 _x = 0;
 while { _radius < _maxradius } do {
  _radius = _radius * 2;
  if (_x == 4) then {
   hint str _radius;
  };
  _x = _x + 1;
  sleep 1;
 };
};

 


Option B: The way it is right now it doesn't work but it would be more tidy and compact as the code to announce the radius is separated from the code increasing the radius
 


private _maxradius = 1000; 
private _radius = 1;

nul = [_maxradius, _radius] spawn { 
 params ["_maxradius", "_radius"]; 
 while { _radius < _maxradius } do {
  _radius = _radius * 2;
  sleep 1;
 };
};

nul = [_maxradius, _radius] spawn { 
 params ["_maxradius", "_radius"]; 
 sleep 4;
 hint str _radius;
};


Code A would hint I believe "32" while code B would say "1", I know A works but what I'm looking for is a way to make code B also say "32" without using global variables or calculating the radius inside the second spawned code / use hint in the first spawned code.
I think/hope this is more understandable.

 

You can't. The principle of a local variable is to be local, so defined inside a scope and nowhere else.

 

Each time you open a   [...] spawn {...}; you open a new scope (roughly code between {}).

Scopes can be inside scopes: [...] spawn {  if (...) then { inner scope here...}; while {..} do {other inner scope here...}... };

If your local variable is passed as params or defined at scope entry (in blue spawn here), you can use it in inner scopes (but never out of the spawn, in another spawn or sqf).

If you define your variable in an inner scope (say red), this variable is not defined elsewhere (green or blue scopes).

 

As I said, global variables don't hurt. Sometimes, you need to broadcast them in MP... they are called public variables.
 

If you need to work with a variable in different cases, you can attribute this variable to an object, a projectile (recently), a group, a task, a control...

setVariable

Now, name spaces:

As explained, a generic global variable such as myCar =...;  is same as missionNameSpace setVariable ["myCar",...];
 

You can also define (global) variables for name spaces. You can read what for. very interesting for saving data on profiles or working on player's displays.

 

NOTE: never use magic variables (as _x) out of their context.

 

 

  • Thanks 1

Share this post


Link to post
Share on other sites

Thank you very much thats what I was looking for. So for clarity, from what I understand I can use global variables (but that means i cant copy and paste the object anymore, because maybe the radius of the 2nd object is supposed to have different values (in this case i would have to change the global variable  to i.e. radius2 for one of the props)) or I write the code within one scope instead of two.

Share this post


Link to post
Share on other sites
2 hours ago, Heavensrevenger said:

Thank you very much thats what I was looking for. So for clarity, from what I understand I can use global variables (but that means i cant copy and paste the object anymore, because maybe the radius of the 2nd object is supposed to have different values (in this case i would have to change the global variable  to i.e. radius2 for one of the props)) or I write the code within one scope instead of two.

 

I gave you the magic variables. Use (example):

this spawn { params ["_object"]; waitUntil {damage _object > 0.1}; systemChat format ["the %1, located at %2 took damage",typeOf _object,getpos _object]};

in init field of any object you want to copy.

The specific variable this is your friend.

 

You can even add (similar) variables on these objects (here variable "ldOut" for every objects you want, running independently but "linked" to the object as a variable container:

for example for units:

this setVariable ["ldOut", getUnitLoadout this];

Then in preview, debug console, in a watch line, test : cursorObject getVariable ["ldOut",[]];

 

  • Like 1

Share this post


Link to post
Share on other sites

ok i dont quite understand, maybe im too new to code and this is above my experience, so please excuse if what im about to say doesnt make sense.
 

3 hours ago, pierremgi said:

this spawn { params ["_object"]; waitUntil {damage _object > 0.1}; systemChat format ["the %1, located at %2 took damage",typeOf _object,getpos _object]};


This code just passes a local variable into a spawned code, i think? my problem was more like passing the variable back out  but there seems to be no function for that other than global variables
 

 

3 hours ago, pierremgi said:

this setVariable ["ldOut", getUnitLoadout this];


And this code will output me the loadout of the units i put the code on? It didnt work for me it just said [] but if thats what i should do then that also doesnt answer the question i had. 

At this point I dont know anymore, so ill just do the code in a single spawned script

Share this post


Link to post
Share on other sites
On 1/5/2024 at 1:23 PM, pierremgi said:

If you need to work with a variable in different cases, you can attribute this variable to an object, a projectile (recently), a group, a task, a control...

setVariable

this... is exactly what i was looking for

Share this post


Link to post
Share on other sites

I understand you are looking to learn the code but for the record I'll add that any time you are working with areas of effect, triggers are usually the go-to tool. They are highly customizable and can be placed, spawned or added to compositions.  

 

Example init-ready code which spawns a trigger with 5 m radius expanding into 30 m over 60 seconds which kills any player which enters it:

[this, 5, 30, 60, 1] spawn {

     _source = _this select 0;

     _initialSize = _this select 1;

     _finalSize = _this select 2;

     _duration = _this select 3;

     _tickTime = _this select 4;

 

     _trg = createTrigger ["EmptyDetector", getPos _source];

     _trg  attachTo [_source];

     _trg setTriggerActivation ["ANYPLAYER", "PRESENT", true];

     _trg setTriggerArea [_initialSize, _initialSize, 0, false];

     _trg setTriggerStatements [

             "this",

             "{ _x setDamage 1; } forEach thisList",

             ""

      ];

      

      _source setVariable [ "death_trigger", _trg ];

      _source addEventHandler [

              "Deleted",

              {

                         params ["_obj"];

                         detach ( _obj getVariable "death_trigger" );

                         deleteVehicle ( _obj getVariable "death_trigger" );

              }

      ];

      

      for "_i" from _tickTime to _duration step _tickTime do {

            sleep _tickTime;

 

            _size = linearConversion  [0, _duration, _i, _initialSize, _finalSize, true];

            _trg setTriggerArea [ _size, _size, 0, false ];

      };

};

 

 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

I see. I've got most the code down now, it's really just bugfixing but ill make a mental note for next time or if i decide to overhaul the code for efficiendy or something
 thank you

  • Like 1

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

×