thedubl 43 Posted September 15, 2015 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 punishmentthedubl 9-15-2015https://community.bistudio.com/wiki/Arma_3_Respawnhttps://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 killingif(isPlayer _killer && side _unit == west) then { //if _killer is an actual player and kill a player on the westtitleText ["Teamkill punishment!", "BLACK FADED", 2]; //fade to black_killer setDamage 1; //kill the offenderdisableUserInput true; // disable player controlswhile {_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 thenull = [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
R3vo 2652 Posted September 15, 2015 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
jshock 512 Posted September 15, 2015 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
killzone_kid 1326 Posted September 15, 2015 Use MPKilled and addMPEventHandler 1 Share this post Link to post Share on other sites
thedubl 43 Posted September 15, 2015 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
fn_Quiksilver 1634 Posted September 15, 2015 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
thedubl 43 Posted September 15, 2015 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
killzone_kid 1326 Posted September 15, 2015 FF OFF //initPlayerLocal player addEventHandler["HandleDamage", { _source = _this select 3; if ( side group _source == side group player && _source != player ) then {0}; }]; 1 Share this post Link to post Share on other sites
thedubl 43 Posted September 16, 2015 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 punishmentthedublnull = [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 everyoneif(isPlayer _killer) then { //if _killer is an actual player and kill a player on the same sidetitleText ["Teamkill punishment!", "PLAIN", 2]; //fade to blacksleep 2;_killer setcaptive true;_killer switchMove "AinjPpneMstpSnonWrflDnon";//disableUserInput true; // disable player controlswhile {_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 offenderforceRespawn _killer;};}]; Share this post Link to post Share on other sites
Heeeere's johnny! 51 Posted September 16, 2015 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
thedubl 43 Posted September 16, 2015 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
Heeeere's johnny! 51 Posted September 16, 2015 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
thedubl 43 Posted September 16, 2015 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
Heeeere's johnny! 51 Posted September 16, 2015 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
thedubl 43 Posted September 16, 2015 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
fn_Quiksilver 1634 Posted September 16, 2015 Not sure if already addressed but if(isPlayer _killer && (side _unit == _side _killer)) _side _killer is wrong. should just be side _killer 1 Share this post Link to post Share on other sites
Heeeere's johnny! 51 Posted September 16, 2015 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
thedubl 43 Posted September 16, 2015 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
Heeeere's johnny! 51 Posted September 16, 2015 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
thedubl 43 Posted September 16, 2015 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 punishmentthedublnull = [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) **sidedisableUserInput true; // disable player controls_killer setcaptive true; //no damage_killer switchMove "AinjPpneMstpSnonWrflDnon"; //go floppy[_killer] spawn {titleText ["Teamkill punishment!", "PLAIN", 2]; //fade to blacksleep 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 damageforceRespawn _killer; //force the player to respwan};//end spawn};}];//}; dubl Share this post Link to post Share on other sites
Heeeere's johnny! 51 Posted September 17, 2015 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
thedubl 43 Posted September 17, 2015 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 punishmentthedublnull = [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 blacksleep 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 damageforceRespawn _killer; //force the player to respwan};//end spawn};}];//}; Share this post Link to post Share on other sites
fn_Quiksilver 1634 Posted September 17, 2015 //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. 1 Share this post Link to post Share on other sites
thedubl 43 Posted September 17, 2015 mdcclxxvi, Thanks! will do. dubl Share this post Link to post Share on other sites
Larrow 2810 Posted September 17, 2015 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