mikemhz 5 Posted September 8, 2013 (edited) My intention: I want to iterate through all units, setting their unique voteValue to [0,0,0,0]. I want all units to be able to change that value through my dialog (for example change theirs to [0,1,0,0] indicating they chose the second option). During the count down I want to iterate through all units, getting their voteValue to find the total votes and display that on screen. Then I will do something with the total votes once the countdown ends. The reason I'm doing it like this, is to avoid duplicate votes and a large array of players which is more complicated to code. Suggestions are welcome! My code: init.sqf: TOTAL_votes = [0,0,0,0]; execVM "countdown.sqf"; countdown.sqf _countdown = 30; while {_countdown > 0} do { TOTAL_votes = [0,0,0,0]; { [color="#FF0000"]_VoteArray = _x getVariable "_voteValue";[/color] [color="#008000"]//This is where I get an error. Undefined variable.[/color] //count votes } forEach allUnits; _NW_votes = TOTAL_votes select 0; _NE_votes = TOTAL_votes select 1; _SW_votes = TOTAL_votes select 2; _SE_votes = TOTAL_votes select 3; hint format ["%1\nNW:%2\nNE:%3\nSW:%4\nSE:%5",_countdown,_NW_votes,_NE_votes,_SW_votes,_SE_votes]; sleep 1; _countdown = _countdown - 1; } I create a multiplayer mission in the editor with an object and a player. I initialise the player with "_voteValue = [0,0,0,0];". I initialise the object ("polling booth") with an addaction which opens my voting dialog. For each option in the dialog there is a button. On each button I run this action: action = "[Player,[1,0,0,0]] execVM ""addVote.sqf"""; addVote.sqf _thePlayer = _this select 0; _theArray = _this select 1; _thePlayer setVariable ["_voteValue",_theArray]; hint format ["%1 's VoteValue = %2",_thePlayer,_thePlayer getVariable "_voteValue"]; Edited September 8, 2013 by mikemhz Share this post Link to post Share on other sites
Larrow 2804 Posted September 8, 2013 (edited) You dont want to be counting votes while your coutingDown, only do it at the end once the voting time is over. For _voteArray use the getVariable with a default e.g _VoteArray = _x getVariable ["_voteValue", [0,0,0,0]]; then if the client has not voted you get the default, also saves having to init a default value on clients. Do not use allUnits as this will be AI aswell. Use playableUnits with a check for isPlayer or (playableUnits + switchableUnits) to allow you to test in the editor/SP. Your foreach does not actually add anything up. e.g //Add all the client votes together //Reset total votes TOTAL_votes = [0,0,0,0]; //Loop around all clients { //If the client is an actual player if (isPlayer _x) then { //Get client vote value _clientVote = _x getVariable ["_voteValue",[0,0,0,0]]; //For each clients vote value { //Add client value to total votes TOTAL_votes set [_forEachIndex, ((TOTAL_votes select _forEachIndex) + (_x))]; }forEach _clientVote; //Reset clients vote to [0,0,0,0] as it has been processed _x setVariable ["_voteValue", [0,0,0,0], true]; }; }forEach (playableUnits + switchableUnits); Your countdown.sqf should be serverSide only. You could also use this to initialize a variable to allow the pollingbooth addaction (use the PVed variable in the addActions condition). e.g //Init of object on clients pollingBoothObject addAction ["VOTE!!",{createDialog ??}, [], 1, true, true, "", "pollingBoothOpen"]; //INIT server and client with pollingBoothOpen = false; //On the server when countDown starts pollingBoothOpen = true; publicVariable "pollingBoothOpen"; //This will enable the action to be seen //When countDown has finished pollingBoothOpen = false; publicVariable "pollingBoothOpen"; //The action will not be available //You could even use this PV to automatically close the dialog if the voting time is finished "pollingBoothOpen" addPublicVariableEventHandler { if (!(_this select 1)) then { closeDialog ??; }; }; No real need for the addVote script, you could just do it from the action. e.g action = "player setVariable [""_voteValue"",[1,0,0,0],true]; hintSilent ""you have voted for option 1"";" Remember to add the true param to the setVariable to broadcast it to the server. Well theres some fixes and some ideas to maybe try out Edited September 8, 2013 by Larrow Share this post Link to post Share on other sites
mikemhz 5 Posted September 9, 2013 (edited) THANKS! I do actually want to count votes while counting down. A live update for all users on the server so that they can make an informed vote and change it at any time during the countdown. If there's any special reason why this is unwise for performance or security then let me know. Also, when the mission starts, there will be no AI (they will be spawned after the vote, depending on the outcome). The idea is to have a period of voting at the start of the mission and then have the polling station deleted from the map, all the variables cleared and the appropriate script executed, which will teleport all players, initialise all props, AI and objectives. So here's the working code: init.sqf TOTAL_votes = [0,0,0,0]; execVM "countdown.sqf"; countdown.sqf //Begin countdown _countdown = 30; while {_countdown > 0} do { //Re-count votes TOTAL_votes = [0,0,0,0]; //For each client { //If client is player if (isPlayer _x) then { //Get client vote value _clientVote = _x getVariable ["_voteValue",[0,0,0,0]]; //For each clients vote value { //Add client value to total votes TOTAL_votes set [_forEachIndex, ((TOTAL_votes select _forEachIndex) + (_x))]; }forEach _clientVote; }; } forEach (playableUnits + switchableUnits); //Display current standings to all players _NW_votes = TOTAL_votes select 0; _NE_votes = TOTAL_votes select 1; _SW_votes = TOTAL_votes select 2; _SE_votes = TOTAL_votes select 3; hint format ["%1\nNW:%2\nNE:%3\nSW:%4\nSE:%5",_countdown,_NW_votes,_NE_votes,_SW_votes,_SE_votes]; //Continue countdown sleep 1; _countdown = _countdown - 1; }; execVM "voteResults.sqf"; voteResults.sqf //Array of max votes in case it's a draw _winners = []; //To keep track of the highest vote value _maxValue = 0; //For naming the winner at the end _winnerName = "Nothing"; //Find the highest number of votes in TOTAL_votes array. { if (TOTAL_votes select _forEachIndex > _maxValue) then { _maxValue = TOTAL_votes select _forEachIndex; } }forEach TOTAL_votes; //Find all options which have the maximum number of votes and add them to _winners array { if (TOTAL_votes select _forEachIndex == _maxValue) then { _winners = _winners + [_forEachIndex]; } }forEach TOTAL_votes; //Count the numebr of winners _numberOfWinners = count _winners; //Select at random one winner from the array of winners _winner = _winners select (floor(random _numberOfWinners)); //Name the winner. if(_winner == 0) then { _winnerName = "NW" }; if(_winner == 1) then { _winnerName = "NE" }; if(_winner == 2) then { _winnerName = "SW" }; if(_winner == 3) then { _winnerName = "SE" }; //Display the winner along with the number of votes it recieved. hint format ["The winner is %1 with %2 votes.",_winnerName,_maxValue]; dialog action: action = "player setVariable [""_voteValue"",[0,1,0,0],true]"; Edited September 9, 2013 by mikemhz Share this post Link to post Share on other sites
Larrow 2804 Posted September 9, 2013 I do actually want to count votes while counting down. A live update for all users on the server so that they can make an informed vote and change it at any time during the countdown.Ok that makes sense.The only problem i see in what you have written above is that this is running on every machine. It would be better if this only ran server side, one machine doing the math and making the final decision. At the moment if you had more than one winner all machines could come up with a different winner due to the random selection from _winners. Share this post Link to post Share on other sites
mikemhz 5 Posted September 13, 2013 Thanks for the heads up. I wrapped everything in my init.sqf with if(isServer) then {}; But this creates problems. E.g. hint, setPos. Is there a way to send generic commands to each player/globally from within a script running only on the server? Share this post Link to post Share on other sites
mantls 2 Posted September 13, 2013 BIS_fnc_MP. just don't use the isPersistent param. Share this post Link to post Share on other sites
Larrow 2804 Posted September 13, 2013 Setpos should not be a problem as it is a global command. Hint via public Variable //init.sqf if (!(isDedicated)) then { //client side PVEH "globalHint" addPublicVariableEventHandler { hint (_this select 1); }; }; //where ever you need to send a hint globalHint = "my message to all"; publicVariable "globalHint"; //Hint the server aswell if it is a hosted server if (!(isNull player)) then { hint globalHint; }; Hint via BIS_fnc_MP //init.sqf if (!(isDedicated)) then { //client side function myTag_fnc_globalHint = { hint _this; }; }; //where ever you need to send a hint //true hints all clients you can change this for side, a player, an array of player etc ["my message to all","myTag_fnc_globalHint",true,false] call BIS_fnc_MP; Share this post Link to post Share on other sites