Jump to content
Doggifast

[Help] Action cooldown with sqf activation instead of code

Recommended Posts

In the MediBOT's INIT:

this addAction
[
  "<t color='#A52A2A'>Heal all nearby units</t>",
  "MediBOT.sqf",
  nil,
  10,
  true,
  false,
  "",
  "_this isEqualTo _originalTarget",
  5,
  false
];


the MediBOT.sqf in the mission file:
 

 params ["_target", "_caller", "_actionId", "_arguments"];
_position = getPosASL _caller;
_radius = 25;
_list = (ASLToAGL _position) nearEntities [["Man"], _radius];
//heal 
{   _x setVariable ["ace_fire_intensity", 0, true];
        ["ace_medical_treatment_fullHealLocal", [_x], _x] call CBA_fnc_targetEvent;
        _x setDamage 0;
    } forEach _list;

My point was to create a playable mediBOT that will reset player's damage around the medibot back to 0, compatitable with ace.
I did what i wanted and it works well, but i need to add a cooldown to it.
Please help.

Share this post


Link to post
Share on other sites

You could set a simple boolean condition for the action - set to false at the top of your script then back to true after your desired interval:

myBooleanVariable = true;

this addAction
[
  "<t color='#A52A2A'>Heal all nearby units</t>",
  "MediBOT.sqf",
  nil,
  10,
  true,
  false,
  "",
  "(_this isEqualTo _originalTarget) && myBooleanVariable",
  5,
  false
];
params ["_target", "_caller", "_actionId", "_arguments"];

myBooleanVariable = false;

_position = getPosASL _caller;
_radius = 25;
_list = (ASLToAGL _position) nearEntities [["Man"], _radius];
//heal 
{
	_x setVariable ["ace_fire_intensity", 0, true];
	["ace_medical_treatment_fullHealLocal", [_x], _x] call CBA_fnc_targetEvent;
	_x setDamage 0;
} forEach _list;

sleep 10;

myBooleanVariable = true;

 

~OR~

 

you could remove the action and re-add it after the interval:

this addAction
[
  "<t color='#A52A2A'>Heal all nearby units</t>",
  "MediBOT.sqf",
  nil,
  10,
  true,
  false,
  "",
  "_this isEqualTo _originalTarget,
  5,
  false
];
params ["_target", "_caller", "_actionId", "_arguments"];

_target removeAction _actionId;

_position = getPosASL _caller;
_radius = 25;
_list = (ASLToAGL _position) nearEntities [["Man"], _radius];
//heal 
{
	_x setVariable ["ace_fire_intensity", 0, true];
	["ace_medical_treatment_fullHealLocal", [_x], _x] call CBA_fnc_targetEvent;
	_x setDamage 0;
} forEach _list;

sleep 10;

mediBot addAction  //  assuming variable name "mediBot"
[
  "<t color='#A52A2A'>Heal all nearby units</t>",
  "MediBOT.sqf",
  nil,
  10,
  true,
  false,
  "",
  "_this isEqualTo _originalTarget,
  5,
  false
];

 

Nothing tested, just spitballing.

Share this post


Link to post
Share on other sites

Alright, thank you. Sorry, I got knocked out at my work desk and didn't answer. I'll try that right now.

Share this post


Link to post
Share on other sites

Also, the first way is not variable, since i got several medibots and i am not making several scripts just for them. I'll try to go with the second way of it

Share this post


Link to post
Share on other sites

Works as well as advertised, thank you very much. I've fixed some of the lines you sent, since it's _caller and not _target that needs the action removal, but it works very well. Well, it needs some more stuff to happen around the medic while he's using his ability, so I'm gonna look into that.
Here's the endcode if you want to use it.

 params ["_target", "_caller", "_actionId", "_arguments"];
_position = getPosASL _caller;
_radius = 25;
_list = (ASLToAGL _position) nearEntities [["Man"], _radius];
//heal 
{    // extinguish people on fire
        _x setVariable ["ace_fire_intensity", 0, true];
        ["ace_medical_treatment_fullHealLocal", [_x], _x] call CBA_fnc_targetEvent;
        _x setDamage 0;
    } forEach _list;
    _caller removeAction _actionId;
    sleep 20;
    _caller addAction
[
  "<t color='#A52A2A'>Heal all nearby units</t>",
  "MediBOT.sqf",
  nil,
  10,
  true,
  false,
  "",
  "_this isEqualTo _originalTarget",
  5,
  false
];

 

Share this post


Link to post
Share on other sites
On 8/10/2022 at 11:15 AM, Doggifast said:

Works as well as advertised, thank you very much. I've fixed some of the lines you sent, since it's _caller and not _target that needs the action removal, but it works very well. Well, it needs some more stuff to happen around the medic while he's using his ability, so I'm gonna look into that.
Here's the endcode if you want to use it.

 

 

All action ids are local for the clients and can be different from a client to another one, for the same action.

That means tgt addAction ["blahblah", {code}]; can pass 0 (as id) for a player, 2 for another one, depending on your scenario, addons...

When you remove an action by _actionIds param, you are removing LOCALLY the action number x where x is referring to the action the player just called. The removed action on TARGET is no more workable in game, except if you re-add it (then its number will be different, increased, because there is no search for removed action's number).

So, imho,

_caller removeAction _actionId;

as no sense as far as you want to reach the right number for the due action. If that works, that works by chance, and probably in your case because the player is also "medibot" by addAction.

 

adding/removing actions is barely a good idea, especially in MP, due to these local referencing action ids. It's not simple for reaching the right id number everywhere, and that can fail if you remoteExec that with the same id number (if players have different sum of ids, no matter still active or removed!)

 

What you can do is to add one action, don't remove it, and play consistently with the condition of this action. Don't forget you can pass a variable on the _target by setVariable . So, your code can also wait for a due value of this set variable (timer or else) for running something.

You can also change the action title by setUserActionText (locally once running the code).

Exception: Don't forget to re-add the action on player once respawned (and yes, the action id nbr may change), because this is a new unit (and removeAllActions on corpse if not deleted).

 

  • Like 1

Share this post


Link to post
Share on other sites
1 hour ago, pierremgi said:

 

All action ids are local for the clients and can be different from a client to another one, for the same action.

That means tgt addAction ["blahblah", {code}]; can pass 0 (as id) for a player, 2 for another one, depending on your scenario, addons...

When you remove an action by _actionIds param, you are removing LOCALLY the action number x where x is referring to the action the player just called. The removed action on TARGET is no more workable in game, except if you re-add it (then its number will be different, increased, because there is no search for removed action's number).

So, imho,

_caller removeAction _actionId;

as no sense as far as you want to reach the right number for the due action. If that works, that works by chance, and probably in your case because the player is also "medibot" by addAction.

 

adding/removing actions is barely a good idea, especially in MP, due to these local referencing action ids. It's not simple for reaching the right id number everywhere, and that can fail if you remoteExec that with the same id number (if players have different sum of ids, no matter still active or removed!)

 

What you can do is to add one action, don't remove it, and play consistently with the condition of this action. Don't forget you can pass a variable on the _target by setVariable . So, your code can also wait for a due value of this set variable (timer or else) for running something.

You can also change the action title by setUserActionText (locally once running the code).

Exception: Don't forget to re-add the action on player once respawned (and yes, the action id nbr may change), because this is a new unit (and removeAllActions on corpse if not deleted).

 

It's not a big problem , because action's condition states only the player that action is created on is only able to use it. That means, even if the action isn't removed for other players, they can't see it anyway.

Share this post


Link to post
Share on other sites
3 minutes ago, Doggifast said:

It's not a big problem , because action's condition states only the player that action is created on is only able to use it. That means, even if the action isn't removed for other players, they can't see it anyway.

Either way, I'll see what i can do about it.

Share this post


Link to post
Share on other sites
1 hour ago, pierremgi said:

 

All action ids are local for the clients and can be different from a client to another one, for the same action.

That means tgt addAction ["blahblah", {code}]; can pass 0 (as id) for a player, 2 for another one, depending on your scenario, addons...

When you remove an action by _actionIds param, you are removing LOCALLY the action number x where x is referring to the action the player just called. The removed action on TARGET is no more workable in game, except if you re-add it (then its number will be different, increased, because there is no search for removed action's number).

So, imho,

_caller removeAction _actionId;

as no sense as far as you want to reach the right number for the due action. If that works, that works by chance, and probably in your case because the player is also "medibot" by addAction.

 

adding/removing actions is barely a good idea, especially in MP, due to these local referencing action ids. It's not simple for reaching the right id number everywhere, and that can fail if you remoteExec that with the same id number (if players have different sum of ids, no matter still active or removed!)

 

What you can do is to add one action, don't remove it, and play consistently with the condition of this action. Don't forget you can pass a variable on the _target by setVariable . So, your code can also wait for a due value of this set variable (timer or else) for running something.

You can also change the action title by setUserActionText (locally once running the code).

Exception: Don't forget to re-add the action on player once respawned (and yes, the action id nbr may change), because this is a new unit (and removeAllActions on corpse if not deleted).

 

MediBot does not have a varName and is referenced through _caller, i simply add the first action that triggers the others. As i said before, i'll see what i can do about all the stuff. Thanks

Share this post


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

 

All action ids are local for the clients and can be different from a client to another one, for the same action.

That means tgt addAction ["blahblah", {code}]; can pass 0 (as id) for a player, 2 for another one, depending on your scenario, addons...

When you remove an action by _actionIds param, you are removing LOCALLY the action number x where x is referring to the action the player just called. The removed action on TARGET is no more workable in game, except if you re-add it (then its number will be different, increased, because there is no search for removed action's number).

So, imho,

_caller removeAction _actionId;

as no sense as far as you want to reach the right number for the due action. If that works, that works by chance, and probably in your case because the player is also "medibot" by addAction.

 

adding/removing actions is barely a good idea, especially in MP, due to these local referencing action ids. It's not simple for reaching the right id number everywhere, and that can fail if you remoteExec that with the same id number (if players have different sum of ids, no matter still active or removed!)

 

What you can do is to add one action, don't remove it, and play consistently with the condition of this action. Don't forget you can pass a variable on the _target by setVariable . So, your code can also wait for a due value of this set variable (timer or else) for running something.

You can also change the action title by setUserActionText (locally once running the code).

Exception: Don't forget to re-add the action on player once respawned (and yes, the action id nbr may change), because this is a new unit (and removeAllActions on corpse if not deleted).

 

Fixed it just like you suggested. Here's the new endcode:
Init:
 

this addAction
[
  "<t color='#A52A2A'>Heal all nearby units</t>",
  "MediBOT.sqf",
  nil,
  10,
  true,
  false,
  "",
  "_this isEqualTo _originalTarget && (_this getVariable ""CoolDownEnd"")",
  5,
  false
];
this setVariable ["IsRifleUnit", true, false];
this setVariable ["CoolDownEnd", true, true];

MediBOT.sqf:

 params ["_target", "_caller", "_actionId", "_arguments"];
 _caller setVariable ["CoolDownEnd", false, true];
_position = getPosASL _caller;
_radius = 25;
_list = (ASLToAGL _position) nearEntities [["Man"], _radius];
//heal 
{    // extinguish people on fire
        _x setVariable ["ace_fire_intensity", 0, true];
        ["ace_medical_treatment_fullHealLocal", [_x], _x] call CBA_fnc_targetEvent;
        _x setDamage 0;
    } forEach _list;
    _caller say3D "Alarm";
    "Health restored." remoteExec ["hint", _caller];
    sleep 180;
    _caller setVariable ["CoolDownEnd", true, true];
    _caller say3D "Alarm";
    "Nanobots restored." remoteExec ["hint", _caller];

Thanks for your reply. I'll modify all the other classes i created just like this one. Many thanks.
What im wondering is, can i remove all of the enemy units from the selection in //heal ?
So that the medic calls for his nanobots to only restore friendlies.

Share this post


Link to post
Share on other sites

Just a point, as you're writing for MP script:

An init field of any unit/object is run at server start and each time a player joins. It's a kind of init.sqf (but unscheduled and occurring at different moment)

That means several things:

this setVariable ["CoolDownEnd", true, true];  // will run at each JIP, no matter the previous setting of this variable, you'll set it to TRUE. Really?

 

Starting with a variable, then ignoring the JIP is : if (isServer) then {this setVariable ["CoolDownEnd", true, true]};

This way, the server sets to TRUE, broadcast the variable and JIP ignore this code but recover the value TRUE or FALSE if a player called the action before this player joins (the JIP receive the broadcast of your   _caller setVariable ["CoolDownEnd", false, true]; // or true if it's the case).

 

this setVariable ["IsRifleUnit", true, false]; // is absolutely as same as:  this setVariable ["IsRifleUnit", true]; and this is right because there is no reason for change (I guess). So JIP or not, the variable will be set locally, and same for every body.

 

 

  • Like 1

Share this post


Link to post
Share on other sites
17 minutes ago, pierremgi said:

Just a point, as you're writing for MP script:

An init field of any unit/object is run at server start and each time a player joins. It's a kind of init.sqf (but unscheduled and occurring at different moment)

That means several things:

this setVariable ["CoolDownEnd", true, true];  // will run at each JIP, no matter the previous setting of this variable, you'll set it to TRUE. Really?

 

Starting with a variable, then ignoring the JIP is : if (isServer) then {this setVariable ["CoolDownEnd", true, true]};

This way, the server sets to TRUE, broadcast the variable and JIP ignore this code but recover the value TRUE or FALSE if a player called the action before this player joins (the JIP receive the broadcast of your   _caller setVariable ["CoolDownEnd", false, true]; // or true if it's the case).

 

this setVariable ["IsRifleUnit", true, false]; // is absolutely as same as:  this setVariable ["IsRifleUnit", true]; and this is right because there is no reason for change (I guess). So JIP or not, the variable will be set locally, and same for every body.

 

 

Yes, IsRifleUnit needs to be local since it's for another script i'm doing. I just wanted to make sure that it is.
And yes, i want the CoolDownEnd set to true, meaning that one's ability is fully charged on mission start? What's wrong with it?

Share this post


Link to post
Share on other sites
28 minutes ago, Doggifast said:

Yes, IsRifleUnit needs to be local since it's for another script i'm doing. I just wanted to make sure that it is.
And yes, i want the CoolDownEnd set to true, meaning that one's ability is fully charged on mission start? What's wrong with it?

 

With your code :

this setVariable ["CoolDownEnd", true, true];

1 - server starts: CoolDowEnd is set to true on unit (and ready for broadcast on JIP because setVariable is persistent with 3rd parameter set to true.

2 - A player joins, same thing (the broadcast is useless, waste of resource)

3 - this player actions your addAction code. Then the variable temporarily shifts to FALSE locally but is broadcast (normal)

4 - a 2nd player joins before the end of the timing for this variable. This player runs your init code and set the variable to TRUE and broadcast. Bye bye your cooldown timer.

 

With my suggestion:

if (isServer) then {this setVariable ["CoolDownEnd", true, true]};

1 - server starts: CoolDowEnd is set to true on unit (and ready for broadcast on JIP because setVariable is persistent with 3rd parameter set to true.

2 - A player joins, This player doesn't run your init code, it receives the broadcast value

3 - this player actions your addAction code. Then the variable temporarily shifts to FALSE locally but is broadcast (normal)

4 - a 2nd player joins before the end of the timing for this variable. This player doesn't run your init code (server only) but he receives the current value for your variable (so the addAction is inoperant) til your ongoing code shifts again the variable to TRUE and broacast it. The cool down time works normally for every one.

 

Share this post


Link to post
Share on other sites
3 minutes ago, pierremgi said:

 

With your code :

this setVariable ["CoolDownEnd", true, true];

1 - server starts: CoolDowEnd is set to true on unit (and ready for broadcast on JIP because setVariable is persistent with 3rd parameter set to true.

2 - A player joins, same thing (the broadcast is useless, waste of resource)

3 - this player actions your addAction code. Then the variable temporarily shifts to FALSE locally but is broadcast (normal)

4 - a 2nd player joins before the end of the timing for this variable. This player runs your init code and set the variable to TRUE and broadcast. Bye bye your cooldown timer.

 

With my suggestion:

if (isServer) then {this setVariable ["CoolDownEnd", true, true]};

1 - server starts: CoolDowEnd is set to true on unit (and ready for broadcast on JIP because setVariable is persistent with 3rd parameter set to true.

2 - A player joins, it receives the broadcast value

3 - this player actions your addAction code. Then the variable temporarily shifts to FALSE locally but is broadcast (normal)

4 - a 2nd player joins before the end of the timing for this variable. This player doesn't run your init code (server only) but he receives the current value for your variable (so a addAction is inoperant) til your ongoing code shifts again the variable to TRUE et broacast it. The cool down time works normally for every one.

 

I see... But wouldn't this be fixed with just the third parameter set to false?

Share this post


Link to post
Share on other sites
1 minute ago, Doggifast said:

I see... But wouldn't this be fixed with just the third parameter set to false?

 

set to false or no 3rd parameter is same.

Yes or no, I can't say. If you remove the initial broadcast and let the variable set locally to TRUE, I can't say which of the init field or the broadcast variables will be run first or second. By chance the broadcast variable will override the init field. Not sure for this way.

Share this post


Link to post
Share on other sites
Just now, pierremgi said:

 

set to false or no 3rd parameter is same.

Yes or no, I can't say. If you remove the initial broadcast and let the variable set locally to TRUE, I can't say which of the init field or the broadcast variables will be run first or second. By chance the broadcast variable will override the init field. Not sure for this way.

Got it. One last question, how can i remove all of the enemy units from the array _list in //heal ?
So that the medic calls for his nanobots to only restore friendlies.

Share this post


Link to post
Share on other sites

private _friendlySides = _caller call BIS_fnc_friendlySides;
then

....   forEach (_list select { side _x in _friendlySides});

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

×