Jump to content
phronk

Sleep inside function not working

Recommended Posts

I'm writing a melee weapon script and running into an issue that is preventing me from using any sleeps in my function/script.

1. It's all in one script file and I've tried initializing it in the init.sqf as either

[]call compile preProcessFileLineNumbers "myScript.sqf"

or

#include "myScript.sqf";

2. It is called via an object init field, such as an axe, like this:

PickupWeaponAct=this addAction["Take axe",{

call pickupWeapon;

(_this select 0)removeAction DropWeaponAct;

(_this select 0)removeAction PickupWeaponAct;}];

3. When the weapon is picked up, aside from other code, it includes this displayEventHandler:

swingEH=(findDisplay 46)displayAddEventHandler["MouseButtonDown",{[player]call swing}];//replace player with custom variable?

4. In the swing function, no matter where I put the sleep, I always get a script error when I swing the weapon (it still carries out the whole script) such as #sleep, implying the sleep is incompatible or misplaced. Adding the sleep into the EH also doesn't work.

5. I've tried these sleep methods:

sleep 3;

[]spawn{sleep 3};

uiSleep 3;

What I'm trying to do is simply add a sleep when the swing animation is played, before distributing damage to the target, instead of instantaneously. I'm sure I'm overlooking something or separate the functions into their own .sqf files, but just want to make sure. Thanks!

Edited by phronk

Share this post


Link to post
Share on other sites

I forgot to mention I also tried that.

Share this post


Link to post
Share on other sites
Guest

Weird. I have no ploblems running sleeps in EH.

Btw spawn does nothing but spawning a useless "thread". (It does not sleep anything as it is a different " thread")

With mine the fonctions are separated into their own files. Maybe it comes from the way you define or call the function.

Share this post


Link to post
Share on other sites

Sleep seems to be not allowed in the context of EH code block, thus the error, when you call the function with it. Spawn instead of call - different thread, no longer EH code block context, thus sleep allowed. Or spawn in the function's code only the part, where sleep is, and what's should be executed after it. Spawning sleep line alone is pointless (should be error-free though), since spawn generates parallel thread, and rest of the code will not wait for it. For example:

swingEH = (findDisplay 46) displayAddEventHandler ["MouseButtonDown",{[player] spawn swing}];

or, as I did in old Arma 2 melee code, second way:

waitUntil {not (isNull(findDisplay 46))}; 

(findDisplay 46) displayAddEventHandler ["MouseButtonDown", "_this call RYD_MeleePlayer"]; 

and the function was like this:

 

RYD_MeleePlayer = 
	{
	private ["_btn","_stroke","_anim","_fat","_speedF","_delay","_hit","_animS","_SFF"];

	_btn = _this select 1;

	_stroke = player getVariable ("Stroke" + (str player));

	_hit = player getVariable ("Hit" + (str player));

	if ((not (_btn == 0)) or (_stroke) or (_hit)) exitwith {};
	player setVariable [("Stroke" + (str player)),true];
	_speedF = player skill "Endurance";
	_fat = player getVariable ("Fatigue" + (str player));

	_SFF = (10 * _speedF) - _fat;
	if (_SFF < 0) then {_SFF = 0};
	_animS = ML_MAnims_M;

	switch (true) do
		{
		case (_SFF < 3.3) : {_animS = ML_MAnims_S};
		case ((_SFF >= 3.3) and (_SFF < 6.7)) : {_animS = ML_MAnims_M};
		case (_SFF >= 6.7) : {_animS = ML_MAnims_H};
		};

	_anim = _animS select (floor (random (count _animS)));


	_delay = (2 + (random _fat)/1.5)/(_speedF + 0.5);

	player switchMove _anim;

	player setVariable [("Fatigue" + (str player)),_fat + ((0.1 + (random 0.1))/(2 * (_speedF + 1)))];
	_fat = player getVariable ("Fatigue" + (str player));
	if (_fat > 5) then {player setVariable [("Fatigue" + (str player)),5]};

	[_delay,_anim] spawn 
		{
		private ["_delay","_enemy","_dst","_dir","_inFront","_pU","_pE","_pDir","_snd","_anim"];
		
		_delay = _this select 0;
		_anim = _this select 1;

		_enemy = player findNearestEnemy player;

		_dst = 1000;
		_dir = 0;
		_inFront = false;

		if not (isNull _enemy) then 
			{
			_dst = player distance _enemy;
			_pU = position player;
			_pE = position _enemy;
			_pDir = getDir player;
			_dir = [_pU,_pE,0] call RYD_AngTowardsPositive;

			if ((abs (_dir - _pDir)) <= 25) then {_inFront = true};
			};

		if ((_dst <= 3) and (_inFront)) then
			 {
			 if ((random 100) > 85) then
				{
				_snd = ML_INsounds select (floor (random (count ML_INsounds)));
				player say3D _snd;
				};
			
			[_enemy,_anim] spawn
				{
				private ["_enemy","_anim","_pause","_spd"];

				_enemy = _this select 0;	
				_anim = _this select 1;

				_spd = 0.9;
				if (_anim in ML_MAnims_S) then {_spd = 1.2};
				if (_anim in ML_MAnims_H) then {_spd = 0.7};

				_pause = 1;
				if (_anim in ["amelpercmstpsnonwnondnon_amateruder2_SLOW","amelpercmstpsnonwnondnon_amateruder2_MEDIUM","amelpercmstpsnonwnondnon_amateruder2_HIGH"]) then {_pause = 0.7};

				sleep (_pause * _spd);
				[player,_enemy] call RYD_MeleeStrike
				};
			 };

		sleep _delay;

		player setVariable [("Stroke" + (str player)),false];
		}
	};
 

(don't ask about details of it - it was long ago and I likely don't remember :) as you can see, the function is called, but there's spawned part within containing some sleeps)

 

AFAIK thing is, code called inside EH code block scope, as integral part of it, has to be executed immediately, within single frame, out of scheduling queue (except for code spawned/execVM-ed inside this function), because that's how EH code is executed. While code spawned in the EH is only spawned immediately, and all the rest inside can be suspended but, as scheduled, in some circumstancies their execution may be delayed. Some useful command:

 

https://community.bistudio.com/wiki/canSuspend

 

and some info:

 

http://ace3mod.com/wiki/development/arma-3-scheduler-and-our-practices.html

  • Like 1

Share this post


Link to post
Share on other sites

in plain english,

A "call" cannot use a sleep or waituntil command

If you "spawned" the function instead of calling it, this would work

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for the helpful input guys. I'm separating each function (pickup, drop, swing, etc.) into their own .sqf (is that even necessary? Or can I just have one .sqf full of functions?). Also, using spawn instead of call is helping, so I'll edit this post once I'm done to share the results.

Share this post


Link to post
Share on other sites
I'm separating each function (pickup, drop, swing, etc.) into their own .sqf (is that even necessary? Or can I just have one .sqf full of functions?)

 

 

 

Not necessary. Whichever you prefer for smoother workflow/better code clarity. I for example tend to use one file full of defined as global variables functions (like in the pasted above example, or few files, each for functions of other category), but also I know experienced scripters using one sqf per each function. 

Share this post


Link to post
Share on other sites

I also prefer working with a single .sqf to prevent script clutter in missions that use a lot of other scripts. Either way, it's nice to know it's not a big deal.

Also, the sleep works! I think the use of spawn instead of call made a big difference. I decided to add a check for the player's animationState in the eventHandler to prevent spam clicking (which would spam damage on the target mid animation or instantaneously without the protection).

Here's the new EH:

waitUntil{not(isNull(findDisplay 46))};

swingEH=(findDisplay 46)displayAddEventHandler["MouseButtonDown",{

_anim0="AwopPercMstpSgthWnonDnon_start";

_anim1="AwopPercMstpSgthWnonDnon_throw";

_anim2="AwopPercMstpSgthWnonDnon_end";

if((animationState player==_anim0)||{(animationState player==_anim1)||(animationState player==_anim2)})exitWith{};

[player]spawn swing}];

My issue is resolved. Thank you all very much!

Share this post


Link to post
Share on other sites

in plain english,

A "call" cannot use a sleep or waituntil command

...when the call is made from unscheduled environment.
  • Like 1

Share this post


Link to post
Share on other sites
Guest

Impossible. EHs are unscheduled.

You are right indeed, the sleeps are in functions called by the EH. Maybe I didn't use the right words.

Share this post


Link to post
Share on other sites

Sorry to be picky but just to save confusion..

You are right indeed, the sleeps are in functions called by the EH.

Still impossible as a called function would still be unscheduled as per Greenfist's post. Unless you mean spawn/execVM -ed.

Share this post


Link to post
Share on other sites
Guest

Sorry to be picky but just to save confusion..

Still impossible as a called function would still be unscheduled as per Greenfist's post. Unless you mean spawn/execVM -ed.

And again ^^. You have the right words. I'm not native english but I coukld have paid attention to that one. Thanks for the clarification (the function is still indeed called but in another "thread")

Share this post


Link to post
Share on other sites
player addEventHandler ["Fired", {call fn_fired}];
fn_fired = {
[] spawn {
	_TRG42list = ["bnae_TRG42_virtual","bnae_trg42_virtual_camo3","bnae_trg42_f_virtual","bnae_trg42_f_virtual_camo3"];
	_unit = player;
	_primary = currentWeapon _unit;
	sleep 1;
	if (_primary in _TRG42list) then {_unit playActionNow "GestureFiredTRG42"};
	};
};

How i do it

Share this post


Link to post
Share on other sites
Guest

Read the thread. Not call fn_fired but spawn fn_fired.

Share this post


Link to post
Share on other sites

Read the thread. Not call fn_fired but spawn fn_fired.

 

I did read it, problem was that he tried to call function from EventHandler and didn't get the sleep command to work. I posted a simple solution that i use.

Share this post


Link to post
Share on other sites
Guest

Still useless to call a spawn since you can directly spawn the function.

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

×