lozz08 10 Posted February 22, 2011 Hello all, I've just finished my Volition: Undead mission but I am having real difficulty converting it to multiplayer. The primary reason is that lots of things are happening on the server. For instance, the zombies have a random chance to say something every x seconds. The server is running this looping script. How can I broadcast the command to have the zombie say a certain sound, to all clients? Keep in mind that this zombie only has a local name to the script, _zom, and I read you can't pass local objects with publicvariable. I have the same problem with all the animations using switchmove, all the particle effects, all the sounds. Share this post Link to post Share on other sites
demonized 20 Posted February 22, 2011 locality is your problem, i must admit i dont have a full grasp on it, but you basically want to play the move,sound,particle on each client. using if (isServer) then {script here is only done on server}; script here is done on server plus all clients. I advice you to have all sounds, particles, animations in a script without using if (isServer) then { simply have script //script here no isserver playmove "" say. start the script from the main script, fex animation you want played. [_zombie, _animation] execVM "localscript.sqf"; Now you pass local variables to wherever you want, no limits. Someone else have more info for you, i bet. In earlier days i worked around the locality with script created triggers wich activated the animation for the unit, wich makes sure all is displayed correctly on all clients, this was with animations. I made trigger very small, positioned on unit in question, 0.1 radius big, then anyone present, {_x playmove ""} foreach thisList. Wich played the move for that unit only. Share this post Link to post Share on other sites
lozz08 10 Posted February 22, 2011 nice idea with the trigger. But creating all those triggers scares me... Seeing as there will be a lot of this broadcasting going on in the mission... Check out this script: if (not isserver) exitwith {}; _zom = _this; _hunted = blah; _zom allowFleeing 0; _zom setbehaviour "aware"; _zom setspeedmode "full"; _zom setunitpos "UP"; _zom disableAI "AUTOTARGET"; _zom setSkill 0; removeAllItems _Zom; removeAllWeapons _Zom; _zom setmimic "Agresive"; _Zom setVariable ["BIS_noCoreConversations",TRUE]; _zom enableai "move"; _zom enableai "anim"; _number = 200; while {alive _zom} do { if (_zom distance _hunted < 2.7) then { _script = [_zom, _hunted] call anm; }; _random = round (random _number); if (_random == 1) then { _sound = zombiemsoundarray select (round (random 21)); _zom say _sound; }; _list = nearestObjects [_zom, ["soldiereb"], 800]; _hunted = _list select 0; _zom domove getposatl _hunted; sleep 0.3; }; It's a simple zombie movement script, and if the zom is within a certain radius of the hunted person, the script to attack executes. the anm function is defined elsewhere. What I'd really like to do is have the server broadcast that _zom say _sound command to all clients so that that sound is played for everyone. Share this post Link to post Share on other sites
shay_gman 272 Posted February 22, 2011 Well actually the easiest way to do it is use CBA functions such as CBA_fnc_addEventHandler, which you can use easy to broadcast commands across MP. You can find more data in the wiki inside CBA folder. Contact me if you need help. If you choose not to use CBA then use addPublicVariableEventHandler. Now you should make a variable like it in the init file and put this line. zombieMoveCount = 0; "zombieMoveCount" addPublicVariableEventHandler {private ["_ok"]; _ok= [zombie, hunted] call anm}; Now in you code you should change it to: zombie = _zom; hunted = _hunted; zombieMoveCount = zombieMoveCount +1; //so the eventhandler will fire publicVariable "zombie"; publicVariable "hunted"; publicVariable "zombieMoveCount"; Now all have the same value for zombie and hunted and the change in zombieMoveCount will fire the event on all clients. Or you can use CBA :bounce3: Share this post Link to post Share on other sites
demonized 20 Posted February 22, 2011 replace the line: _zom say _sound; with: [_zom, _sound] spawn { // this will create new script wich will run as any other script and it will not pause anything in the main script. if (isServer) exitwith {}; // it will not run on server, only clients (players) _zom = _this select 0; _sound = _this select 1; _zom say _sound; }; Also it well adviced to read up on what shay_gman mentioned as it have multiple powerful uses for scripting. Share this post Link to post Share on other sites
neokika 62 Posted February 22, 2011 Hi, Place the Functions module on the editor: If (!isServer) exitWith {}; waituntil { !isNil "BIS_fnc_init" }; _sound = zombiemsoundarray select (round (random 21)); [nil, _zom, rSAY, _sound] call RE; More info here. _neo_ Share this post Link to post Share on other sites
lozz08 10 Posted February 22, 2011 (edited) That is precisely what I was looking for neokitta. So if I want to broadcast any of the commands in that long list I just put r in front of it capitalised? excellent. Will putting any other letters in front do any other cool things? edit now, I do have another mp problem that I should't open a new thread for. It has to do with the scoring system. When a zom spawns, it has this done to it: _zom addeventhandler ["hit", {nul = _this spawn hit;}]; _zom addmpeventhandler ["mpkilled", {nul = _this spawn killed;}]; hit.sqf: if (isserver) then { _zom = _this select 0; _hitter = _this select 1; _score = _hitter getvariable "score"; _hitter setvariable ["score", _score + 10]; _totalscore = _hitter getvariable "totalscore"; _hitter setvariable ["totalscore", _totalscore + 10]; _zom setvariable ["lasthit", _hitter]; _sound = zombiehitarray select (round(random 2)); _random = round (random 9); _zom say _sound; }; killed.sqf: if (isserver) then { sleep 0.5; _zom = _this select 0; _hitter = _zom getvariable "lasthit"; sleep 0.1; _score = _hitter getvariable "score"; _hitter setvariable ["score", _score + 100]; _totalkills = _hitter getvariable "totalkills"; _hitter setvariable ["totalkills", _totalkills + 1]; _totalscore = _hitter getvariable "totalscore"; _hitter setvariable ["totalscore", _totalscore + 100]; _sound = zombiekilledarray select (round(random 5)); "logic" createunit [getpos _zom, "source=this"]; source say _sound; sleep 2; deletevehicle source; }; The reason I am adding the score for a kill in such a wierd way is because it wasn't giving score reliably before. Anyway, clients can't get any score. Only a host-player can. is setvariable local or something? The variables for the player have been defined on mission init, so that's not the problem. editedit: neokita, the code you posted works very well, however, I am unsure why. [nil_or_caller, nil_or_target_object,"loc", script_to_execute, par0, par1...] call RE; [nil, _zom, rSAY, _sound] call RE; why isn't _zom par0, and _sound par1? when I used rFADEMUSIC, this worked: [nil, nil, rFADEMUSIC, 2, 1] call RE; this caused 2 fademusic 1 to be executed on all clients. I don't get why _zom is being put in target_object and not a param. Edited February 22, 2011 by lozz08 Share this post Link to post Share on other sites
neokika 62 Posted February 22, 2011 (edited) Hey, Well, all you give is an array with parameters and call RE function. FadeMusic command does not need an Object, although, Say does. You will actually need to go inside the MP framework scripts and see for yourself what you can count with and what order the parameters need to be put in. Modules.pbo/MP/DATA/scriptCommands.sqf Also, setVariable can have local or global effect: _unit setVariable ["TAG_points", 5, true]; //Global Effect _unit setVariable ["TAG_points", 5]; //Local Effect _neo_ Edited February 22, 2011 by neokika Share this post Link to post Share on other sites