bangabob 41 Posted July 18, 2013 _addactionUser = (_this select 1); _id =(_this select 2); if (!GLB_AlphaRally) exitwith {hint "Alpha Rally is already deployed. Un-deploy Rally point to access it.";}; sleep 1; PAPABEAR sideChat format["%1 has picked up the Alpha Rally point",name _addactionUser]; hint format ["You have %1 seconds to deploy the rally point",_carrytime]; GLB_AlphaRally = false;publicVariable "GLB_AlphaRally"; GLB_AlphaRallyTake=true;publicVariable "GLB_AlphaRallyTake"; _addactionUser addAction["<t color='#ffff00'>Build Alpha Rally</t>","occupation\rallypoints\AlphaRallyBuild.sqf","",1,false,true,"","GLB_AlphaRallyTake"]; waituntil {!GLB_AlphaRallyTake}; _addactionUser removeAction _id; GLB_AlphaRally = false;publicVariable "GLB_AlphaRally"; This is some code for an addaction which gives a player a rally point. I need some code which will detect if "_addactionUser" has disconnected and then update GLB_AlphaRally = true. So the action is available again for other players. Any help appreciated. Thanks Share this post Link to post Share on other sites
kylania 567 Posted July 18, 2013 http://community.bistudio.com/wiki/onPlayerDisconnected might help? Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 http://community.bistudio.com/wiki/onPlayerDisconnected might help? I looked but the wiki does an exceptional bad job at describing how to use it. I was hoping somebody could give me an example in context Share this post Link to post Share on other sites
kylania 567 Posted July 18, 2013 There's this example here. Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 There's this example here. Hmm. I did look at that earlier. I just can't get my head around how i would use it. If i am understanding this correctly, every time a player disconnects, onplayerdisconnected gets that players name as (_this select 1). And i need to check if (_this select 1) == _addactionUser from my addaction script. But can i do that. BTW i tried several other ways. Including if (!alive _addactionUser) but that doesn't count for disconnecting. And i've even ran a timer which resets the GLB_AlphaRally = true after a set amount of time. But that doesn't work on dedicated servers because the addaction is local. Share this post Link to post Share on other sites
mikie boy 18 Posted July 18, 2013 you basically need to check ll playable units against the one disconnecting. Check first to ensure its not the __Server__ uid, then check through playable units uids to see if it is the player leaving. example... _id = _this select 0; _caller = _this select 1; _uid = _this select 2; //check if the uid given is for player or server //__server__ if (_caller != "__SERVER__") then { _player = objNull; { if (getPlayerUID _x == _uid) exitWith { _player = _x; }; } forEach playableUnits; }; basically any mention to _player is the player disconnecting. not sure how you will link it, but can try to use set variable(and true) to store anything like you want on _addactionUser. set it to something on the script above and then when _player leaves - set it to something else. have a script that gets the variable for the _player and check when it changes. if that makes sense Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 Thanks Mikie boy . I appreciate you taking the time to write a example. The thing i really have trouble with is the set/get variable command.(which is what i need to use here). I've attempted what you said but i don't understand enough to make it work. Share this post Link to post Share on other sites
mikie boy 18 Posted July 18, 2013 You need to have in the activation script _whoeveactivated setvariable ["active", 1, true]; this in effect is setting a variable to this player, specific to him and set to a value of 1. U then can call another script to regularly check the value of this player and the active variable. If its 0 then remove whatever was created with the addaction script. In the onplayerdisconnect script have _player setvariable ["ACTIVE", 0, TRUE]; THIS Is the change that the looping script will detect. Sorry on train typing on a not so smart phone Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 (edited) Great help. So this is what i've cobbled together from everything you've told me. Just a rough edit but is this what you mean? init.sqf if (isnil {GLB_AddActionUsed}) then { GLB_AddActionUsed = false;publicvariable "GLB_AddActionUsed"; }; null = [] execvm "actionCheckLoop.sqf"; onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "playerDisconnected.sqf" }; Addaction.sqf (Called using action on flagpol) // SET VARIABLE TO CHECK IF ADDACTION USER IS STILL IN GAME _whoeveactivated = (_this select 1); _actionID=(_this select 2); _whoeveactivated setvariable ["active", 1, true]; // ADD ACTION ALREADY USED if (GLB_AddActionUsed) exitwith { hint "Come back later. Addaction is already used" }; // GIVE USER ADDACTION _whoeveactivated addAction["Build Rally","createRally.sqf"]; // SET CURRENT ACTION AS USED GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed"; waituntil {createRally called}; _whoeveactivated removeAction _actionID; playerdisconnected.sqf _id = _this select 0; _caller = _this select 1; _uid = _this select 2; //check if the uid given is for player or server //__server__ if (_caller != "__SERVER__") then { _player = objNull; { if (getPlayerUID _x == _uid) exitWith { _player = _x; }; } forEach playableUnits; }; // SET PLAYER AS LEFT _player setvariable ["ACTIVE", 0, TRUE]; actionCheckLoop.sqf while {true} do {sleep 1; _aVariable = _player getVariable "ACTIVE"; if (_aVariable == 0) then { // IF ADDACTION USER DISCONNECTED THEN SET GLOBAL VAR TO ALLOW USE OF ADDACTION AGAIN GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed"; }; }; Edited July 18, 2013 by BangaBob Share this post Link to post Share on other sites
mikie boy 18 Posted July 18, 2013 yeah sort of.... playerdisconnected - _player should be inside that scope. actionCheckLoop - this wont work as you need to pass the specific player with the actual setvariable - however you could set all players to "active", 0 when they join, that way you could use this method. Remember to set _player to player if running from init.sqf other way is to run this script as a function and pass the specific player with the setvariable active to it. see how you get on and let me know - Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 (edited) yeah sort of....playerdisconnected - _player should be inside that scope. actionCheckLoop - this wont work as you need to pass the specific player with the actual setvariable - however you could set all players to "active", 0 when they join, that way you could use this method. Remember to set _player to player if running from init.sqf other way is to run this script as a function and pass the specific player with the setvariable active to it. see how you get on and let me know - Okay i have got the get/set variables set up. using a function Check_action_FNC = { _whoeveactivated = (_this select 0); //hint format ["%1",_whoeveactivated]; _aVariable = _whoeveactivated getVariable "ACTIVE"; hint format ["%1",_aVariable]; if (_aVariable == 0) then { // IF ADDACTION USER DISCONNECTED THEN SET GLOBAL VAR TO ALLOW USE OF ADDACTION AGAIN GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed"; }; }; This function is called every second inside a loop Addaction script on flag pole. // SET VARIABLE TO CHECK IF ADDACTION USER IS STILL IN GAME _whoeveactivated = (_this select 1); _actionID=(_this select 2); _whoeveactivated setvariable ["active", 1, true]; // ADD ACTION ALREADY USED if (GLB_AddActionUsed) exitwith { hint "Come back later. Addaction is already used" }; // RUN FUNCTION TO CHECK IF PLAYER DISCONNECTED [_whoeveactivated] spawn { _whoeveactivated= (_this select 0); while {true} do {sleep 1; 0=[_whoeveactivated] call Check_action_FNC; }; }; // SET CURRENT ACTION AS USED GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed"; // GIVE USER ADDACTION hint "Got rally!"; _whoeveactivated addAction["Build Rally","createRally.sqf"]; waituntil {GLB_rallyBuilt}; _whoeveactivated removeAction _actionID; GLB_AddActionUsed = false;publicvariable "GLB_AddActionUsed"; I dont understand how the onplayerdisconnected command will work. Should i call it from the init.sqf? If so i dont understand how "_player setvariable ["ACTIVE", 0, TRUE]; " will be linked to _whoeveactivated. Hope this makes sense. Sorry if im missing something obvious. Im just getting fed up of ArmA.lol Edited July 18, 2013 by BangaBob Share this post Link to post Share on other sites
mikie boy 18 Posted July 18, 2013 init.sqf player setvariable ["active", 0, true]; if (isDedicated) then { onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "OnPlayerDisconnect.sqf" }; }; when a player disconnects his id name and uid are passed to the OnPlayerDisconnect.sqf - thus it will trigger automatically. as for this [_whoeveactivated] call Check_action_FNC; ... you should call this once then have the loop in the function. let that run until it player disconnects. lets say bob is the character that joins the game. when he activates the addaction - it will be _whoeveactivated setvariable ["Active", 1, true]; which is technically...bob setvariable ["Active", 1, true]; that remains as is until it gets changed through setvariable. _player is identified by the uid - from checking each uid of all playable units, its then compared against the uid passed to the onplayerdisconnected .sqf. once this is confirmed the name/object of the identified playableunit is assigned to _player. Thus in our case bob is the player leaving, his uid will be found in the array of playable units to match that of the uid passed to the onplayerdisconnected .sqf. Thus - _player is actually bob. therefore when you change _player setvariable ["Active", 0, true]; you are actually saying bob setvariable ["active", 0, true]; now if dave leaves the game - he will become _player at the point he leaves and it will be dave setvariable ["active",0, true]; however dave never had his active variable set to 1, so it doesnt matter, and furthermore even if you changed it. Your while loop is checking bob getvariable "active" - not dave getvariable "active" - you can see it wouldnt matter. Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 Great explantion. I understand now. However it still doesn't work properly in my tests. Inside my init.sqf player setvariable ["active", 0, true]; if (isDedicated) then { onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "OnPlayerDisconnect.sqf" }; }; if (isnil {GLB_AlphaRally}) then { GLB_AlphaRally = false;publicvariable "GLB_AlphaRally"; }; null = [] execvm "Myfunction.sqf"; OnPlayerDisconnect.sqf (Where i think im going wrong) _id = _this select 0; _caller = _this select 1; _uid = _this select 2; //check if the uid given is for player or server //__server__ if (_caller != "__SERVER__") then { _player = objNull; { if (getPlayerUID _x == _uid) exitWith { _player = _x; _player setvariable ["ACTIVE", 0, TRUE]; }; } forEach playableUnits; }; Its a real pain testing onplayerdisconnected... Could it be that when i rejoin its setting "bobs" variable as 0 again. player setvariable ["active", 0, true]; Actually just realised that doesnt matter because the function would set the GLB_AddActionUsed to false anyway. Myfunction.sqf Check_action_FNC = { _whoeveactivated = (_this select 0); while {true} do {sleep 1; _aVariable = _whoeveactivated getVariable "ACTIVE"; hint format ["%1",_aVariable]; if (_aVariable == 0) then { // IF ADDACTION USER DISCONNECTED THEN SET GLOBAL VAR TO ALLOW USE OF ADDACTION AGAIN GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed"; }; }; }; Share this post Link to post Share on other sites
mikie boy 18 Posted July 18, 2013 you could try using on playerconnected much like you have done with onplayerdisconnected to set the active variable to 0 for all players. it could also be that the while loop is not returning anything as it MAY (not sure) not be getting anything for you player as he left - cant be certain on that - trying to think of a better way to do it. as this can only be used once - you could simply have a global variable to sort this out. (not at the start of the addaction script - otherwise all those who call it will override it - maybe in one of the if statements); whoeveactivated = _this select 0; PV it as well then in the onplayerdisconnected script - have if (_player == whoeveactivated) then {GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";}; Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 (edited) Thanks very much Mikie boy. I believe i have a finished product. Just need to test it with a friend to make SURE that the global variable isn't overwritten by anyone trying to access the addaction script after its called once. So incase anyone is interested this is it. This script simulates picking up a Rally point, and while its taken no one else can get a rally point. - Unless the person that picked up the rally point disconnects - The person that picked up the rally point is killed. - The final addaction (destroyRally.sqf) is used. On the map i have a flag pole a fireplace and a marker named "rallyAlpha" and a gamelogic named fob_alpha flag pole init this addAction["<t color='#ffff00'>Get Rally Point</t>", "occupation\rallypoints\collectRally.sqf"]; I also have a fireplace in the corner of the map named "rallyAlphaObject" fireplace init this addAction ["<t color='#ffff00'>Remove RallyPoint</t>", "occupation\rallypoints\DestroyRally.sqf",[rallyALPHA]]; init.sqf if (isDedicated) then { onPlayerDisconnected { [_id, _name, _uid] call compile preprocessfilelinenumbers "occupation\rallypoints\OnPlayerDisconnect.sqf" }; }; PAPABEAR=[independent,"HQ"]; if (isnil {GLB_AddActionUsed}) then { GLB_AddActionUsed = false;publicvariable "GLB_AddActionUsed"; }; collectRally.sqf _whoeveactivated = (_this select 1); _actionID=(_this select 2); // CHECK IF RALLY POINT IS TAKEN if (GLB_AddActionUsed) exitwith { hint "Come back later. Rally point is already taken"; }; // RALLY POINT TAKER IS IN GLOBAL VARIABLE. IF HE DISCONNECTS THEN SET RALLY AS NOT TAKEN GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed"; whoeveactivated = _this select 1;publicvariable "whoeveactivated"; // RALLY POINT IS READY TO BE PLACED GLB_PLANTRALLY=true;publicvariable "GLB_PLANTRALLY"; // COLLECT RALLY POINT (Add backpack) whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon";sleep 1.3; whoeveactivated addbackpack "B_Carryall_Base"; // ALERT PLAYERS THAT RALLY POINT IS TAKEN hint "You have the Rally Point"; PAPABEAR sideChat format["%1 has Collected the rally point from base.",name whoeveactivated]; whoeveactivated addAction["<t color='#ffff00'>Build Rally point</t>","occupation\rallypoints\createRally.sqf","",1,false,true,"","GLB_PLANTRALLY"]; // LOOP CHECK IF RALLY POINT TAKER DIES [] spawn { waituntil {GLB_AddActionUsed}; while {GLB_PLANTRALLY} do {sleep 1; if (!alive whoeveactivated) exitwith { PAPABEAR sideChat format["%1 has being killed. Rally point available at base.",name whoeveactivated]; GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";removeBackpack whoeveactivated; }; }; }; // REMOVE ACTION waituntil {!GLB_AddActionUsed}; whoeveactivated removeAction _actionID; createRally.sqf _RallypointCarrier=(_this select 0); _whoeveactivated = (_this select 1); _actionID=(_this select 2); if (!(_whoeveactivated ==_RallypointCarrier)) exitwith {hint "You are not carrying the Rally point"}; _whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon"; sleep 1.3; removeBackpack _whoeveactivated; hint "Rally point Deployed"; PAPABEAR sideChat format["%1 deployed the Rally point. Use it to re-deploy.",name _whoeveactivated]; rallyALPHA setpos(getpos _whoeveactivated); _degrees = getDir _whoeveactivated; _spawnPos = [getpos _whoeveactivated, 2, _degrees] call BIS_fnc_relPos; "rallyAlpha" setmarkerpos _spawnPos; rallyAlphaObject setpos _spawnPos; [rallyALPHA] join basesquad; GLB_PLANTRALLY=false;publicvariable "GLB_PLANTRALLY"; DestroyRally.sqf private ["_whoeveactivated","_rallyArray","_fireplace","_rallypoint"]; _fireplace = _this select 0; _whoeveactivated = _this select 1; _rallyArray = _this select 3; _rallypoint = _rallyArray select 0; _whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon"; sleep 1.3; hint "Rally point removed"; PAPABEAR sideChat format["%1 has removed the Rally point. It is now available at base.",name _whoeveactivated]; _fireplace setpos [0,0,0]; [_rallypoint] join grpNull; "rallyAlpha" setmarkerpos (getpos BTC_base_flag_east); GLB_AddActionUsed =false;publicVariable "GLB_AddActionUsed"; onplayerdisconnected.sqf _id = _this select 0; _caller = _this select 1; _uid = _this select 2; //check if the uid given is for player or server //__server__ if (_caller != "__SERVER__") then { _player = objNull; { if (getPlayerUID _x == _uid) exitWith { _player = _x; if ((_player == whoeveactivated)and GLB_PLANTRALLY) then {GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed"; PAPABEAR sideChat format["%1 has disconnected. Rally point is back at base.",name whoeveactivated];}; }; } forEach playableUnits; }; NOTE: The codes referring to groups is something to do with my teleport script. Hope somebody finds this useful Edited July 18, 2013 by BangaBob Share this post Link to post Share on other sites
mikie boy 18 Posted July 18, 2013 i dont think that will work in its current state - forexample - if (GLB_AddActionUsed) exitwith generally doesnt exit the script it only exits the scope so it will always set whoeveactivated as who ever uses the add action - even though it may be in place - try re-working the if statement section of when its active to ensure it doesnt get over written... if (GLB_AddActionUsed) then { hint "Come back later. Rally point is already taken"; } else { GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed"; whoeveactivated = _this select 1;publicvariable "whoeveactivated"; }; Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 i dont think that will work in its current state - forexample - if (GLB_AddActionUsed) exitwith generally doesnt exit the script it only exits the scope so it will always set whoeveactivated as who ever uses the add action - even though it may be in place - try re-working the if statement section of when its active to ensure it doesnt get over written... if (GLB_AddActionUsed) then { hint "Come back later. Rally point is already taken"; } else { GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed"; whoeveactivated = _this select 1;publicvariable "whoeveactivated"; }; That was my main concern. I will look at it again tomorrow with a fresh perspective. Any ideas on how to prevent my global variable being overwritten? Share this post Link to post Share on other sites
mikie boy 18 Posted July 18, 2013 as ive detailed above - should do the trick... give it ago and then let me know. you could even try and prevent the addaction being run by more than two people accidentally at one time - just a condition at start Share this post Link to post Share on other sites
bangabob 41 Posted July 18, 2013 as ive detailed above - should do the trick... give it ago and then let me know.you could even try and prevent the addaction being run by more than two people accidentally at one time - just a condition at start Yes I just realised that. If your if command works(which im sure it will anyway)then I'll stick with my current system else I'll just use a condition on the addaction itself Share this post Link to post Share on other sites
bangabob 41 Posted July 19, 2013 Just in-case you were wondering my original script works just fine, Tested it on a dedicated with a friend and didn't get any conflicts. I tried your if command too but when the person that takes the rally point click on the flag pole again the hint shows about 'coming back later' but then the animation plays and i get a second 'build rally' action. Share this post Link to post Share on other sites
mikie boy 18 Posted July 19, 2013 _whoeveactivated = _this select 1; _actionID= _this select 2; // CHECK IF RALLY POINT IS TAKEN if (GLB_AddActionUsed) then { hint "Come back later. Rally point is already taken"; }else { // RALLY POINT TAKER IS IN GLOBAL VARIABLE. IF HE DISCONNECTS THEN SET RALLY AS NOT TAKEN GLB_AddActionUsed=True;publicvariable "GLB_AddActionUsed"; whoeveactivated = _this select 1; publicvariable "whoeveactivated"; // RALLY POINT IS READY TO BE PLACED GLB_PLANTRALLY=true;publicvariable "GLB_PLANTRALLY"; // COLLECT RALLY POINT (Add backpack) whoeveactivated playmove "AinvPercMstpSnonWnonDnon_AmovPercMstpSnonWnonDnon"; sleep 1.3; whoeveactivated addbackpack "B_Carryall_Base"; // ALERT PLAYERS THAT RALLY POINT IS TAKEN hint "You have the Rally Point"; PAPABEAR sideChat format["%1 has Collected the rally point from base.",name whoeveactivated]; whoeveactivated addAction["<t color='#ffff00'>Build Rally point</t>","occupation\rallypoints\createRally.sqf","",1,false,true,"","GLB_PLANTRALLY"]; // LOOP CHECK IF RALLY POINT TAKER DIES [] spawn { waituntil {GLB_AddActionUsed}; while {GLB_PLANTRALLY} do { sleep 1; if (!alive whoeveactivated) exitwith { PAPABEAR sideChat format["%1 has being killed. Rally point available at base.",name whoeveactivated]; GLB_AddActionUsed=false;publicvariable "GLB_AddActionUsed";removeBackpack whoeveactivated; }; }; }; // REMOVE ACTION waituntil {!GLB_AddActionUsed}; whoeveactivated removeAction _actionID; };//else http://community.bistudio.com/wiki/exitWith EXITWITH Wiki... just for future reference If the result of condition is true, code is evaluated, and current block with result of code. It only exits the current scope. exitWith exits the execution of a loop defined by one of commands do, for, count or forEach. When you use exitWith not inside a loops, the behaviour is undefined - sometimes it may exit the script, sometimes some other scope, but this is not intended and designed behaviour of this command, and it is not guaranteed to work reliably. It exits the loop only, not the script. Share this post Link to post Share on other sites
bangabob 41 Posted July 19, 2013 Thanks Mikie. Its such a simple thing to put the script in a ELSE command instead of relying on the unreliable exitwith command. Gives me some more confidence that the system will work correctly. But for the sake of understanding. _whoeveactivated = (_this select 1); _actionID=(_this select 2); // CHECK IF RALLY POINT IS TAKEN if (GLB_AddActionUsed) exitwith Surely this exitwith will see the whole script as its scope? since its not nested within anymore commands? Share this post Link to post Share on other sites
mikie boy 18 Posted July 19, 2013 alas no - it will simply jump to the next line - but it can work from time to time - as the wiki states " it is not guaranteed to work reliably." So best to be safe and sure that what you have got works 100 percent :) Share this post Link to post Share on other sites