Jump to content
thedubl

Looking for some advice and help on first eventhandler

Recommended Posts

Hello, I am working on my first eventhandler and want to just ask if this thinking will work. I want to create a teamkill timeout for a dedicated server coop mission.

 

I was going to add this to  playable init

null = [this]execVM "tkpunish.sqf";

 

 

Here is the tkpunish.sqf

 

/********************************************************************************
Teamkiller punishment

thedubl 9-15-2015

https://community.bistudio.com/wiki/Arma_3_Respawn
https://community.bistudio.com/wiki/Arma_3:_Event_Handlers

 

setup playable init:
null = [this]execVM "tkpunish.sqf";
*********************************************************************************/
if (isServer) then{

_time = 100;
_unit = (_this select 0);

_unit addEventHandler ["killed",{

_unit= (_this select 0); //unit that was killed
_killer=(_this select 1);//unit that did the killing

if(isPlayer _killer && side _unit == west) then { //if _killer is an actual player and kill a player on the west

titleText ["Teamkill punishment!", "BLACK FADED", 2]; //fade to black

_killer setDamage 1; //kill the offender
disableUserInput true; // disable player controls

while {_time > 0} do
{

titleText [format["Time Left: %1",_time], "BLACK FADED", 2];
_time = _time - 1;
sleep 1;
};

disableUserInput false; //enable controls

//respawn the offender.
forceRespawn _killer;

};

}];
};

Is this an ok approach? This untested, but will it work calling adding the
null = [this]execVM "tkpunish.sqf"; in the playable init to call the eventhandler? Does anyone have suggestions on a different way that could be more efficient or correct?

 

dubl

Share this post


Link to post
Share on other sites

You could execute the script via initPlayerLocal.sqf, you would not need to put it into the init of every possible player unit. Other than that it looks fine at first glance.

 

 

You don't need to use backets here, they are obsolete

_unit = (_this select 0);

In addition you could check if the killer's side it equal to the victim's side, therfore the script would not only work for blufor unit in future missions

if(isPlayer _killer && (side _unit == _side _killer))

Share this post


Link to post
Share on other sites

You also may want to devise a breakout for your while loop (just in case Arma happens :p), and re-enable user input with that breakout.

And I may have just woken up and I'm not reading it properly, but wouldn't disabling user input happen to the unit that was TKed, not the killer?

Share this post


Link to post
Share on other sites

R3vo, I localplayerint...ok! Great suggestion on the if(isPlayer _killer && (side _unit == _side _killer)) bit.

 

jshock, Um... yeah. I guess it would disable the worng players controls. I guess I could call another script to pass the killer a parameter to disable the killers controls before the while loop and disable the controls and enable after. What do you think?

 

Killzone_kid, I would assume the same setup and stucture applies the to MPkilled and addMPEventhandler and would be a better option since it is the meant for mulitplayer mission, correct?

 

Thanks,

dubl

Share this post


Link to post
Share on other sites

Be careful with punishing for kills.

 

The effective commander of a vehicle will get punished if the gunners/driver kill a teammate.

 

Also if my controls were locked for an unintentional FF event, I would leave the server at first opportunity and not return, though that may just be me.

 

Still, the intention is good and this looks like a good start, hope all goes well with few script errors :)

 

Once you've got that part down, I would start filtering out false positives such as vehicle-related kills where both killer and killed are in the same vehicle. Happens frequently a heli goes down and a pilot is awarded friendly fire kills for all the passengers.

 

example filter:

 

// somewhere near the top
if ((vehicle _killer) isEqualTo (vehicle _killed)) exitWith {};

Share this post


Link to post
Share on other sites

Hey mdcclxxvi, Ok and noted. I was thinking that this might help with the rambo type people that go crazy just firing away without any thought. I am not trying to kick or ban, but make people listen to the commander and think. I was going to make sure it working properly before implementation. I do appreciate all the comments and assitance.

 

Thanks,

dubl

Share this post


Link to post
Share on other sites

FF OFF

//initPlayerLocal
player addEventHandler["HandleDamage", {
_source = _this select 3;
if (
  side group _source == side group player
  && _source != player
) then {0};
}];
  • Like 1

Share this post


Link to post
Share on other sites

Hey there! One problem I am having is that the time value is return an "any" value. I cant seem to set it. Ideas? If take the while loop and place it before the handler it does run. It is as if I can't access the variable in the scope of the eventhandler.

Problem 2. I can't seem to get the "side" test to work in the if. I have no idea about that one. if(isPlayer _killer && (side _unit == _side _killer)) for now I took it out.

 

dubl

 

/********************************************************************************
Teamkiller punishment

thedubl

null = [this]execVM "tkpunish.sqf";
*********************************************************************************/

_unit = (_this select 0);
_time = 99;


_unit addEventHandler ["killed",{

_unit= (_this select 0); //unit that was killed
_killer=(_this select 1);//unit that did the killing

//if(vehicle _killer) isEqualTo (vehicle _killed) exit with{}; //ie. exit if heli goes down and kills everyone

if(isPlayer _killer) then { //if _killer is an actual player and kill a player on the same side

titleText ["Teamkill punishment!", "PLAIN", 2]; //fade to black
sleep 2;


_killer setcaptive true;
_killer switchMove "AinjPpneMstpSnonWrflDnon";

//disableUserInput true; // disable player controls

while {_time > 0} do
{

titleText [format["Time Left: %1",_time], "PLAIN"];
_time = _time - 1;
sleep 1;
};

_killer setcaptive false;
disableUserInput false; //enable controls

//_killer setDamage 1; //kill the offender

forceRespawn _killer;

};

}];

Share this post


Link to post
Share on other sites

One problem I am having is that the time value is return an "any" value. [...] It is as if I can't access the variable in the scope of the eventhandler.

 

Right. An event handler is only a setup of something which should happen in some case. It's not immediatly executed code, so of course the EH code can't access local variables from the surrounding script.

 

But if you want to give an initial time value, use a #define which you call TIME_START for instance and initialize your EH's _time variable with that value:

//outside the EH
#define TIME_START 99

//inside the EH
_time = TIME_START;
while {_time > 0} do
{
    titleText [format["Time Left: %1",_time], "PLAIN"];
    _time = _time - 1;
    sleep 1;
};

Share this post


Link to post
Share on other sites

Johnny, Awesome, thanks for the great explanation! Still not working, but I will keep playing around with it tonight. It displayed "Time Left 1" as the message  for a second and continued to run the script.

 

thanks,

dubl

Share this post


Link to post
Share on other sites

To make the "Time Left 1" message disappear, simply put a hintSilent ""; right after the while loop.

 

If you want the loop to end with "Time Left 0", then swap your first two lines in the while loop and start _time with 100 instead of 99.

Share this post


Link to post
Share on other sites

Thanks, I should have been more clear. The messages displays for 1 second and disappears. What I want was the count down message to display for the entire countdown of 99 seconds (ie, time left 99...time left 98...time left 97). The loop never actually does the count down. Display quickly and continues on. I guess I just missing something.

 

dubl

Share this post


Link to post
Share on other sites

Telling by your pasted code above, you invoke the script with

null = [this] execVM "tkpunish.sqf";

 

I can't test right now, but I was assuming execVM runs in scheduled environment. Either way, wrap the while loop into a spawned code block:

[] spawn {
	_time = TIME_START;
	while {_time > 0} do
	{
		titleText [format["Time Left: %1",_time], "PLAIN"];
		_time = _time - 1;
		sleep 1;
	};
};

And if that doesn't work, I'd be confused. ^_^

 

Btw, in Steam, set the startup parameter -showScriptErrors to get notified when a script error occurs.

Share this post


Link to post
Share on other sites

OK, I will give it a go tonight after work and give an update!

 

Thanks,

dubl

Share this post


Link to post
Share on other sites

Not sure if already addressed but

 

if(isPlayer _killer && (side _unit == _side _killer))

 

_side _killer is wrong.

 

should just be

 

side _killer

  • Like 1

Share this post


Link to post
Share on other sites

OK, I will give it a go tonight after work and give an update!

 

Thanks,

dubl

 

What might be important to mention is that spawning a function lets the rest of the script continue normally, so both - the "outer" script and the spawned function will run parallel.

For that to resolve, you could either spawn the whole script or split the "outer" script in half resp. two functions.

 

The first half can run in unscheduled environment and will run until the spawn.

The second half will be called inside the spawned function after the while loop is finished. But that second half will still run in scheduled environment though, because it's called inside a spawned function.

 

For detailed information about scheduled and unscheduled environment, read up the first note in the BIKI page for call.

Share this post


Link to post
Share on other sites

OK, well it stops at 2 seconds left and hangs. Ill keep working on it.

 

[] spawn {

        titleText ["Teamkill punishment!", "PLAIN", 2]; //fade to black
        sleep 3;
 
        _time = TIME_START;

        while {_time > 0} do
         {

             _time = _time - 1;
            sleep 1;
            titleText [format["Time Left: %1",_time], "PLAIN"];
            
        
         };
       

    };//end spawn
 

Share this post


Link to post
Share on other sites

Well, I just tested it with the script below and it counted down to 0 just fine. I invoked the script with _unit execVM "tkpunish.sqf". The only thing that didn't work for me was the disableUserInput, but I know it worked in the past and I don't know if it's got to do with the fact that I'm in the experimental branch.

 

#define TIME_START 10

if (isServer) then {
	_unit = _this;

	_unit addEventHandler ["killed", {
		_unit= (_this select 0); //unit that was killed
		_killer=(_this select 1);//unit that did the killing

		if (isPlayer _killer) then { //if _killer is an actual player and kill a player on the west
			titleText ["Teamkill punishment!", "BLACK FADED", 2]; //fade to black

			// _killer setDamage 1; //kill the offender
			disableUserInput true; // disable player controls

			[] spawn {	
				titleText ["Teamkill punishment!", "PLAIN", 2]; //fade to black
				sleep 3;
		 
				_time = TIME_START;
				while {_time > 0} do {
					_time = _time - 1;
					sleep 1;
					titleText [format["Time Left: %1",_time], "PLAIN"];
				};
				disableUserInput false; //enable controls
				
				//respawn the offender.
				// forceRespawn _killer;
			};//end spawn
		};
	}];
	systemChat "created";
};

Share this post


Link to post
Share on other sites

Hmmm...interesting. Ok. Maybe because I am running it locally on the computer and not on the server (commented out the isserver bit )? I guess I can just stick in a for a few minutes and give it a go. I will update tomorrow.

 

 

 

 

/********************************************************************************
Teamkiller punishment

thedubl

null = [this]execVM "tkpunish.sqf";
*********************************************************************************/

#define TIME_START 10

//if (isServer) then {
_unit = (_this select 0);

_unit addEventHandler ["killed", {
_unit= (_this select 0); //unit that was killed
_killer=(_this select 1);//unit that did the killing


//if(vehicle _killer) isEqualTo (vehicle _killed) exit with{}; //exit if heli goes down and kills everyone **NOT WORKING COME BACK**
if (isPlayer _killer) then { //if _killer is an actual player and kill a player on the west && (side _unit == side _killer) **side

disableUserInput true; // disable player controls


_killer setcaptive true; //no damage
_killer switchMove "AinjPpneMstpSnonWrflDnon"; //go floppy

[_killer] spawn {
titleText ["Teamkill punishment!", "PLAIN", 2]; //fade to black
sleep 3;

_time = TIME_START;
while {_time > 0} do {
_time = _time - 1;
sleep 1;
titleText [format["Time Left: %1",_time], "PLAIN"];

//Stops here and nothing does not execute the rest below. It is counting to zero.
};
disableUserInput false; //enable controls

_killer setcaptive false; //allow damage
forceRespawn _killer; //force the player to respwan

};//end spawn
};
}];

//};

dubl

Share this post


Link to post
Share on other sites

I also tested in Singleplayer, ingame editor to be precise, but anyway, that can't be it. Do you run any additional addons beside the vanilla DLCs? Because I don't.

 

Maybe put the _time into the diag_log in the while loop and keep an eye on the logs to see if something strange happens. The logs can be found here:

C:\Users\[Your username]\AppData\Local\Arma 3

Share this post


Link to post
Share on other sites

Hey Johnny! No mods... all vanilla. If i do not use the while loop in forcerespawn and everything else seems to work fine. When I add the while loop back in, it counts down to zero now but stops. I am going to try using []call (schedule bit) as you recommended yesterday once I get a minute tonight. I wil try the logging too. Let me ask you. Did you have it count to zero and have the forcerespawn work? Below is exaclty what I was using. I noted the some things in red.

 

Thanks!

dubl

 

/********************************************************************************
Teamkiller punishment

thedubl

null = [this]execVM "tkpunish.sqf";
*********************************************************************************/

#define TIME_START 10

//if (isServer) then {
_unit = (_this select 0);

_unit addEventHandler ["killed", {
_unit= (_this select 0); //unit that was killed
_killer=(_this select 1);//unit that did the killing


//if(vehicle _killer) isEqualTo (vehicle _killed) exit with{}; //exit if heli goes down and kills everyone **NOT WORKING COME BACK TO THIS LATER**
if (isPlayer _killer) then { //if _killer is an actual player and kill a player on the west && (side _unit == side _killer) **side bit not working***

disableUserInput true; // disable player controls


_killer setcaptive true; //no damage
_killer switchMove "AinjPpneMstpSnonWrflDnon"; //go floppy

[_killer] spawn {
titleText ["Teamkill punishment!", "PLAIN", 2]; //fade to black
sleep 3;

_time = TIME_START;
while {_time > 0} do {
_time = _time - 1;
sleep 1;
titleText [format["Time Left: %1",_time], "PLAIN"];

//Stops here and nothing does not execute user input, captive, frocerespawn. It is counting to zero though.
};

disableUserInput false; //enable controls

_killer setcaptive false; //allow damage
forceRespawn _killer; //force the player to respwan

};//end spawn
};
}];

//};

Share this post


Link to post
Share on other sites
//if(vehicle _killer) isEqualTo (vehicle _killed) exit with{}; //exit if heli goes down and kills everyone **NOT WORKING COME BACK TO THIS LATER**

 

change _killed to _unit.

 

_killed not previously defined, its just what i use to define (_this select 0) in Killed event handler. _unit works too.

 

turn on -showScriptErrors in your launcher options, will pick up all these things related to undefined variables.

  • Like 1

Share this post


Link to post
Share on other sites

TIME_START = 10;

TAG_fnc_teamKill = {

disableUserInput true;

//We can use player as we are now on the clients machine that killed

player setCaptive true;

player switchMove "AinjPpneMstpSnonWrflDnon";

titleText ["Teamkill punishment!", "PLAIN", 2];

sleep 3;

_time = TIME_START;

while {_time > 0} do {

_time = _time - 1;

sleep 1;

titleText [format["Time Left: %1",_time], "PLAIN"];

};

disableUserInput false;

player setCaptive false;

forceRespawn player;

};

this addEventHandler ["killed", {

_unit= (_this select 0);

_killer=(_this select 1);

//If we are a vehicle death exit ( your brackets did not enclose the condition )

if(vehicle _killer isEqualTo vehicle _unit) exitWith{};

//Killed by player and side group killed ( a killed unit is placed on side CIV so you need to query his groups side )

if (isPlayer _killer && { side group _unit isEqualTo side _killer } ) then {

//moved thread to its own function so it can be called remotely on the killers machine

//Otherwise things like disableUserInput would of happened on the killed client

[] remoteExec [ "TAG_fnc_teamKill", _killer ];

};

}];

Fixes in the comments.

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

×