Jump to content
Sign in to follow this  
ArmaMan360

hint at each kill not working

Recommended Posts

_sidepos = getMarkerPos "m1";
_side = createCenter west;

sleep 1;

// Add task
//Task ID-Task name-Task description and some other options
["Task9",true,["Some snipers have wandered in this area. Finish them","Snipers Spotted!", "Snipers Spotted!"],
_sidepos, "AUTOASSIGNED",6,true,true] call BIS_fnc_setTask;

// Spawn enemy officer
for "_i" from 3 to (5 + floor(random 3)) do {
_newpos = [_sidepos, [5,15], random 360, 0] call SHK_pos;
_groupHVT = createGroup west;
_veh = _groupHVT createUnit ["B_sniper_F", _newpos, [], 0, "NONE"];
_veh setRank "COLONEL";
_veh setSkill 1;
_groupHVT setBehaviour "SAFE";
[_groupHVT, _sidepos, 20] call BIS_fnc_taskPatrol;

sleep 0.6;

};

sleep 1;

_enmc = {alive _x and side _x == west} count allUnits;
while (enmc > 1) do {
	{
	_x addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then {
	hintsilent format["Enemy remaining : %1",_enmc]}}]
	} foreach allunits;
	sleep 0.4;
};

// task complete hint
["Task9","Succeeded"] call BIS_fnc_taskSetState;

Fix it please :)

Share this post


Link to post
Share on other sites

Adding an eventHandler via a while loop is probably not the best idea. I'd suggest you put all the units which need an killed eventHandler into an array first. In addition,

while (enmc > 1) do {
    {
    _x addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then {
    hintsilent format["Enemy remaining : %1",_enmc]}}]
    } foreach allunits;
    sleep 0.4;
};

This part is pretty hard to read, you should work on your formatting (just my opinion).

Share this post


Link to post
Share on other sites

Thanks R3vo,

Lol yeah im between noob and intermediate :P

But I am running an "i" loop to spawn them to randomise their number, how do i put them in an array?

Edit: oh do you mean in this case it will be "....} foreach _veh" ?

Share this post


Link to post
Share on other sites

I would already add an eventHandler to the units just after you spawned them.

 

 

_veh = _groupHVT createUnit ["B_sniper_F", _newpos, [], 0, "NONE"];

 

_veh addEventhandler....

 

In addition, you can use the for loop to create an array with all the freshly spawned units. Use the following command for that.

 

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

Share this post


Link to post
Share on other sites

I would already add an eventHandler to the units just after you spawned them.

 

 

_veh = _groupHVT createUnit ["B_sniper_F", _newpos, [], 0, "NONE"];

 

_veh addEventhandler....

 

In addition, you can use the for loop to create an array with all the freshly spawned units. Use the following command for that.

 

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

 

Dear R3vo, your answer is a piece of art.

 

Is this correct?

for "_i" from 3 to (5 + floor(random 3)) do {
_newpos = [_sidepos, [5,15], random 360, 0] call SHK_pos;
_groupHVT = createGroup west;
_veh = _groupHVT createUnit ["B_sniper_F", _newpos, [], 0, "NONE"];
_veh setRank "COLONEL";
_veh setSkill 1;
_groupHVT setBehaviour "SAFE";
[_groupHVT, _sidepos, 20] call BIS_fnc_taskPatrol;
_veh pushBack _i;

_enmc = {alive _veh and side _veh == west} count allUnits;
while (enmc > 1) do {
{
_veh addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then {
hintsilent format["Enemy remaining : %1",_enmc]}}]
} foreach allunits;
sleep 0.4;
};

_veh addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then {
    hintsilent format["Enemy remaining : %1",_enmc]}}]

sleep 0.6;

};

Share this post


Link to post
Share on other sites
while (enmc > 1) do {{_veh addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then {hintsilent format["Enemy remaining : %1",_enmc]}}]} foreach allunits;sleep 0.4;};
I think R3vo is suggesting to take this part out completely.

Event handlers are persistant. You add it once and it will (with a few exceptions in multiplayer) remain until it is removed. Running that code will add an endless amount of the same event handler to each until until killed. Additionally, you will be adding that event handler to ALL units in the mission, regardless of side.

Just add this code immediately after the "setSkill" call and before the "_groupHVT setBehaviour " call:

_veh addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then {    hintsilent format["Enemy remaining : %1",_enmc]}}];
Additionally, note that in your script example, the above line was missing an ending semi-colon. Also, this event handler will fail anyway because the variable "_enmc" is a local variable to the script you are running. "_enmc" needs to be declared as a public variable so it can be accessed outside of the scope of your script.

Share this post


Link to post
Share on other sites

I think R3vo is suggesting to take this part out completely.

Event handlers are persistant. You add it once and it will (with a few exceptions in multiplayer) remain until it is removed. Running that code will add an endless amount of the same event handler to each until until killed. Additionally, you will be adding that event handler to ALL units in the mission, regardless of side.

Just add this code immediately after the "setSkill" call and before the "_groupHVT setBehaviour " call:

_veh addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then {    hintsilent format["Enemy remaining : %1",_enmc]}}];
Additionally, note that in your script example, the above line was missing an ending semi-colon. Also, this event handler will fail anyway because the variable "_enmc" is a local variable to the script you are running. "_enmc" needs to be declared as a public variable so it can be accessed outside of the scope of your script.

 

Thank you Tyger, yeah I just copy pasted that line without removing the original.

 

So I will add that line right after setskill as you mentioned, but I am sorry to bug you, how do I achieve turning _enmc as a local variable? Should I add this at the start of the script?:

_enmc = _this select 0;

P.S.: This is being utilized in a purely SP environment. If this is way too complicated than how you could have achieved then please give me an alternate line of codes. I am more than willing to adapt. In this side mission, no enemy will be spawned other than random number of snipers.

Share this post


Link to post
Share on other sites

P.S.: This is being utilized in a purely SP environment. If this is way too complicated than how you could have achieved then please give me an alternate line of codes. I am more than willing to adapt. In this side mission, no enemy will be spawned other than random number of snipers.

 

 

In an SP environment you don't need to care much about local and global variables as long as they have an unique name. So simply change _enmc to enmc in order to make it global.

 

In addition, I just noticed that you are counting from 3 to (5 + floor(random 3)). That makes not much sense.

 

You could count from 1 to (3 +(floor random 3))

 

The variable _i will then have the exact number of units you've spawned. I'd then use this variable to declare enmc.

enmc = _i; //inside the for loop

I changed all the things I mentioned above, and it works now, I can post the script here I case you can't get it to work. But try it yourself first. ;)

Share this post


Link to post
Share on other sites

Thank you Tyger, yeah I just copy pasted that line without removing the original.

So I will add that line right after setskill as you mentioned, but I am sorry to bug you, how do I achieve turning _enmc as a local variable? Should I add this at the start of the script?:

_enmc = _this select 0;
P.S.: This is being utilized in a purely SP environment. If this is way too complicated than how you could have achieved then please give me an alternate line of codes. I am more than willing to adapt. In this side mission, no enemy will be spawned other than random number of snipers.
R3vo has you covered for fixing the variable scope issue, but a little reading on the BIKI to help clarify can be found on this page. If you scroll down to Para. 4 - Namespace, it covers locality in ArmA scripting.

Share this post


Link to post
Share on other sites

In addition, I just noticed that you are counting from 3 to (5 + floor(random 3)). That makes not much sense.

 

You could count from 1 to (3 +(floor random 3))

 

LOLLLL I cannot stop laughing after this. You are so right. I was trying to achieve minimum 3 units and bang you are so on target. My poor skills. lol

 

 

Yes I will try sure Thanks. However I was always of the impression that any variable inside a script needs to be with an underscore if it is not already a previously defined function. Honestly, I tend to stay away from the function defining process as I find it soo mind boggling with all the { class tag .... thing going around, lol.

 

I only play SP and I am happy with such intermediate scripting achieving my goals :D

I will publish the mission for all asap. Its based on Altis and is 95% completed with 11 different random missions in all. More than 50 random locations possible. Its got logistics, a mobile HQ, a base, random start time, AI recruitment, and maybe even a small cutscene at the start :P

 

And heck lot of SP fun ^^

Share this post


Link to post
Share on other sites

However I was always of the impression that any variable inside a script needs to be with an underscore if it is not already a previously defined function.

 

 

The issue here is way more complex, because there are also different scopes inside a script. Usually it works if you use local variable e.g _variable, however, sometimes it's necessary to work with global variables. Since you're only scripting in SP I'd not worry too much about it.

Share this post


Link to post
Share on other sites

The issue here is way more complex, because there are also different scopes inside a script. Usually it works if you use local variable e.g _variable, however, sometimes it's necessary to work with global variables. Since you're only scripting in SP I'd not worry too much about it.

Egg-xactly ! ^^

Share this post


Link to post
Share on other sites

OK this is not working:

 

call compile preprocessfile "SHK_pos\shk_pos_init.sqf";

sleep 1;

_sidepos = getMarkerPos "m1";
_side = createCenter west;

sleep 2;

// Add task
//Task ID-Task name-Task description and some other options
["Task9",true,["Some snipers have wandered in this area. Finish them","Snipers Spotted!", "Snipers Spotted!"],
_sidepos, "AUTOASSIGNED",6,true,true] call BIS_fnc_setTask;

// Spawn enemy officer
for "_i" from 1 to (3 + floor(random 5)) do {
_newpos = [_sidepos, [5,15], random 360, 0] call SHK_pos;
_groupHVT = createGroup west;
_veh = _groupHVT createUnit ["B_sniper_F", _newpos, [], 0, "NONE"];
_veh setRank "COLONEL";
_veh setSkill 1;
_enmc = _i;
_veh addEventHandler ["killed", {_enmc = _enmc -1; if (_enmc != 0) then { hintsilent format["Enemy remaining : %1",_enmc]}}];
_groupHVT setBehaviour "SAFE";
[_groupHVT, _sidepos, 300] call BIS_fnc_taskPatrol;
sleep 0.6;
};

sleep 1;

Share this post


Link to post
Share on other sites

Any error message?

Share this post


Link to post
Share on other sites

Any error message?

They spawn, and I kill them. No hint or error message what soever O.o

Share this post


Link to post
Share on other sites

Guess we have some kind of scope error here. Replace _enmc with enmc and it works.

 

 

Edit:

 

Yet again, KK has got a great resource on his blog page.

 

http://killzonekid.com/arma-scripting-tutorials-variables-part-1/

http://killzonekid.com/arma-scripting-tutorials-scopes/

 

If I understood correctly what KK wrote in his blog, then addEventHandler adds a complete new scope, which can't inherit from a parent scope. Similar to the following example.

_parentVar = 123;
call {
    hint str isNil "_parentVar"; //false
    _childVar = 456;
};
if true then {
    hint str isNil "_parentVar"; //false
    _childVar = 456;
};
_null = [] spawn {
    hint str isNil "_parentVar"; //true
    _childVar = 456;
};
hint str isNil "_childVar"; //true

Please take all this with a grain of salt since this is fairly new to me too.

Share this post


Link to post
Share on other sites

R3vo you are correct. Basically, any code block creates a new scope.

So, you should be able to have the following code:

{
    _a = 2;
    {
        _a = 4;
        hint _a; // displays 4
    };
    hint _a; // displays 2
};
Since the code to execute in an addEventHandler call is a code block, it creates its own scope.

Share this post


Link to post
Share on other sites

R3vo you are correct. Basically, any code block creates a new scope.

So, you should be able to have the following code:

{
    _a = 2;
    {
        _a = 4;
        hint _a; // displays 4
    };
    hint _a; // displays 2
};
Since the code to execute in an addEventHandler call is a code block, it creates its own scope.

 

Thanks for clarification. At first glance I thought the for loop was the parent scope and therefore the eh scope could inherit variables. But that's not the case.

Share this post


Link to post
Share on other sites

Thanks to you too i'll get back with results later today.... :)

Share this post


Link to post
Share on other sites

Edit: Superrrrr R3vo.. thanks man :D

Although i am still confused as to why underscore isnt needed before enmc ?

Ill read yours and tyger's reference links..:D

Share this post


Link to post
Share on other sites

Edit: Superrrrr R3vo.. thanks man :D

Although i am still confused as to why underscore isnt needed before enmc ?

Ill read yours and tyger's reference links.. :D

 

Well, because addEvenhandler creats its own scope, and it cannot inherit variables which where defined before that e.g defined in the for loop. Therfore you have to work with global local variables to make it work. But all that is very well explained in KK's blogs. Ready them and you'll understand it...at least a little bit, like me xD

Share this post


Link to post
Share on other sites

Well, because addEvenhandler creats its own scope, and it cannot inherit variables which where defined before that e.g defined in the for loop. Therfore you have to work with global local variables to make it work. But all that is very well explained in KK's blogs. Ready them and you'll understand it...at least a little bit, like me xD

Thanks m8... Appreciate it..

Share this post


Link to post
Share on other sites

Part of the issue with event handlers is the scope in which they are executed.

In a script, the for loop is executed in the script's namespace. It can inherit variables from the script's namespace, or overload variables within it's own namespace.

In an event handler, the event interupt for the event handler is added to the specified target in the script namespace, but the event handler's code does not execute yet. Later, once the event sends the interupt signal during the mission, the code in the event handler's code is executed in the mission namespace. Therefore, it can't inherit any local variables, as there are none to inherit.

Maybe this code example can help:

_unit = MY_UNIT;
_someVariable = "ABC";

// Create our "event handler" for the unit being killed
[_unit] spawn {
    _unit = _this select 0;
    waitUntil { !(alive _unit) };

    // Do some stuff
    hint _someVariable; // _someVariable not defined here
};
I hope this helps clarify?

EDIT: Just as a side note, you should see similar behavior with addAction, as the scope of the code in the addAction command is not executed when the action is added, but later, upon selection. Hence, inheritance of variables is not possible for an addAction command either.

Share this post


Link to post
Share on other sites

Part of the issue with event handlers is the scope in which they are executed.

In a script, the for loop is executed in the script's namespace. It can inherit variables from the script's namespace, or overload variables within it's own namespace.

In an event handler, the event interupt for the event handler is added to the specified target in the script namespace, but the event handler's code does not execute yet. Later, once the event sends the interupt signal during the mission, the code in the event handler's code is executed in the mission namespace. Therefore, it can't inherit any local variables, as there are none to inherit.

Maybe this code example can help:

_unit = MY_UNIT;
_someVariable = "ABC";

// Create our "event handler" for the unit being killed
[_unit] spawn {
    _unit = _this select 0;
    waitUntil { !(alive _unit) };

    // Do some stuff
    hint _someVariable; // _someVariable not defined here
};
I hope this helps clarify?

EDIT: Just as a side note, you should see similar behavior with addAction, as the scope of the code in the addAction command is not executed when the action is added, but later, upon selection. Hence, inheritance of variables is not possible for an addAction command either.

Thanks tyger for the detailed explanation. Surely removes a lot of doubts :D

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  

×