Jump to content
Sign in to follow this  
Tankbuster

triggers calling scripts and multiplayer and locality

Recommended Posts

I thought I understood triggers in multiplayer and how they call scripts. But I was wrong. I'm going to set out my new understanding and ask you gents to comment.

I've looking into the difference between faction and side and in the course of this, had a trigger that ran a script that simply reported the faction and side.

So the trigger has this in it's On Act

_handle = player execVM ""sidecheck.sqf"";

Fairly simple, it passes the player to the script as a parameter. and the script

//sidecheck.sqf

_vehicle = vehicle _this;

player sideChat format["Faction=%1", faction _vehicle];
player sideChat format["Side=%1", side _vehicle];

Now what happens is that a opfor player takes a cobra into the trigger and that opfor player sees sidechat "faction = RU side = East". This is what I expected, but the other player, who is blufor sees faction "usmc and side = west".

So the script is running on the blufor player's machine even though he didn't fire the trigger. Initially, this confused me, but I do sort of understand what's happening - the script runs on all clients with potentially odd results for the player who didnt fire the trigger.

So perhaps the script should start with a clause that makes it exit if the location of the player isn't near the trigger, so that bystanders wouldn't see anything.

Or am I missing something elementary?

Share this post


Link to post
Share on other sites

Dunno if it works but try with...

this and player in thisList

...in condition field.

Share this post


Link to post
Share on other sites

Ah... the condition field! Cunning. :)

Share this post


Link to post
Share on other sites

player is always local, the unit it points to just changes.

Using player in multiplayer triggers is just asking for trouble anyway.

Share this post


Link to post
Share on other sites

Basically what happens is when the trigger's condition is true on anyone's machine then the onAct will run. If the trigger is activated when opfor go in then when an opfor goes in it'll activate on all machines (except maybe on machines that are lagging/desyncing, so if it's important you should have it only run on the server and then publicVariable the result).

Either create the trigger only on the machines that need to run the script, or add a relevant condition to either the trigger's condition or to the script.

Share this post


Link to post
Share on other sites
Either create the trigger only on the machines that need to run the script, or add a relevant condition to either the trigger's condition or to the script.

OK, gonna give me any clues? :)

Share this post


Link to post
Share on other sites

Well, I can't tell you exactly what you need to do because I don't know what you are trying to do, so I was trying to explain to you how things work... Basically the condition in the trigger is checked individually on every computer and on every computer where the condition becomes true the onAct field will execute. So you could possibly have the onAct field execute only on my computer, only on yours or on everyone's, depending who has the trigger's condition as true. Simple conditions (such as "opfor present") will usually become true at about the same time on all machines (putting lag/desync aside).

Share this post


Link to post
Share on other sites

It seems to me I need the trigger to only get activated on the player who is within the trigger. It's the fact that this doesn't happen that made me write this thread in the first place.

Share this post


Link to post
Share on other sites

The problem with your trigger/script combination, they do not rely on each other. So the trigger gets launched (on all clients to make sure all will get same results at first) and launches the script. And there you lose connection between the unit which activated the trigger and the script. Instead of passing the relevant unit to the script, you pass the variable "player" to it.

This variable always holds the local player on each client. So on my PC it would be "Myke" and on yours it would be "Tankbuster".

From this point of view, your trigger/script combination does exactly what you told it to do: whenever trigger gets activated, output players side and faction.

As a simple method, try this:

_handle = (thislist select 0) execVM ""sidecheck.sqf"";

This way, the script gets the relevant unit instead of the player and can show your desired output.

Share this post


Link to post
Share on other sites

OK, so a small light bulb just clicked on, Myke. :)

So this is a drawback inherent when you use triggers to exec a script.

thislist contains a list of the people that fired the trigger and only the first one (select 0) will execute the script. Am I understanding that right?

Share this post


Link to post
Share on other sites
thislist contains a list of the people that fired the trigger and only the first one (select 0) will execute the script. Am I understanding that right?

Half correct. ;)

thislist (only valid when used in a trigger itself) indeed contains a list with units actually inside the trigger area, sorted by triggers statement. So a WEST/PRESENT triggers thislist will not return EAST units within the trigger area.

Not correct is that only the first one will execute the script, it just passes the first unit from thislist as variable to the script. Usually this is equal with the unit which activated the trigger.

Be aware that on a repeated trigger (WEST/PRESENT/REPEATEDLY) all WEST units have to leave the trigger area before the trigger can fire again. You may imagine a dark room where the first person goin in turns on the light and the last person leaving the room turns the light off.

So as long there is at least one WEST unit inside a WEST triggered area, any new unit entering the trigger area will not activate the trigger again.

:EDITH:

As a sidenote: although the trigger does not reactivate as long respective units are within the trigger area, the list of the trigger is updated in realtime. So at any time you may get the list of a trigger, representing the actual content of who is within the trigger area.

Edited by [FRL]Myke

Share this post


Link to post
Share on other sites

Myke, you're being so helpful, I really do appreciate you spending time on this and me.

Let me see if I'm understanding this properly.

I get that thislist contains objects that are within the trigger area AND meet it's statement. How does it pass this to the script? Is it passed as _this or as _thislist?

What I'm actually trying to do here is only allow a couple of specific units (discerned by userID) to fire a script and this is taking me some of the way to achieving this. I can extract the userid of the object passed to the script and end the script if the userid isn't on my list of specific units.

Also, I didn't realise that repeatedly worked in that way, ie. I thought a repeatedly trigger fired over and over again WHILE the unit was inside the area, so I'm grateful for that info as I need to have a repeatedly trigger for something else.

Once again, many thanks. I hope that others can gain as much insight from this thread as I have.

Share this post


Link to post
Share on other sites

thislist is an array holding the info. So let's say in the on activation line you have this:

nul = thislist execVM "myScript.sqf"

and in myScript.sqf you have this here:

_myArray = _this;

then _myArray will contain all units within trigger area, presorted by the triggers statements.

However, from what i understand what you try to do i guess a looped script would fit better. If you can describe detailed what exactly you want the trigger to behave like and for which units (single units, grouped units or whatever), if it should be repeateing for each unit or every unit fires the trigger only once...you see, just as detailed as ever possible...i might be able to bring up a solution for your problem.

Meanwhile you may try this:

Place a player unit

place a trigger (settings as you like)

Group player unit (although it works for every unit and/or vehicle) with the trigger

Re-open trigger dialogue and see that you have now different statements to choose than before.

These are:

Vehicle: useful when a specific vehicle has to be within the trigger area, regardless who is in.

Whole group: all group members have to be within trigger area to activate it.

Leader of the group: only the group leader has to be within the trigger area.

Any group member: at least one member of the group has to be within trigger area.

Please note that it might be named slightly different since i have the german ArmA 2 version but you should get the idea.

Maybe this already solves your problem.

Share this post


Link to post
Share on other sites
thislist is an array holding the info. So let's say in the on activation line you have this:

nul = thislist execVM "myScript.sqf"

and in myScript.sqf you have this here:

_myArray = _this;

then _myArray will contain all units within trigger area, presorted by the triggers statements.

However, from what i understand what you try to do i guess a looped script would fit better. If you can describe detailed what exactly you want the trigger to behave like and for which units (single units, grouped units or whatever), if it should be repeateing for each unit or every unit fires the trigger only once...you see, just as detailed as ever possible...i might be able to bring up a solution for your problem.

OK I understand how what the array does and how we get data to the script.

Detailed description, Here goes then. :)

In Domination, some of the side missions don't always end gracefully, for example, the dude you are supposed to arrest wanders off and can't be found. If players can't find him, the side mission won't complete and so no more side missions are created. That's a third of the game functionality gone.

So we edited all of the side missions, not to alter how they fail to complete or fix the logic, but so that we admins can *manually* end them by script. So at the moment, there's a hidden trigger in a building that only game admin knows about. He goes there and walks onto a trigger, that trigger runs a script that gets the players ID, sees if he's an admin and then sets the conditions on the server for side mission failure. In my example above, the dude gets shot instead of arrested. Mission failure means the next side mission can spawn and the game can continue.

But, as we know, when a player goes to this hidden trigger, it gets fired on every machine and thus the script runs on every machine. So provided an admin is playing, the script finds an admin and ends the side mission.

At the moment, we do a check where when the trigger fires, it runs the script and first thing the script does is find player nearest the trigger. If that is NOT an admin (checked by a list of known userids) then the scripts exits right at the start. This means that while any player can fire the trigger and all players run the script, the script only runs to completion on the admin machine, set side mission failure conditions.

Now, this works and I'm not disrespecting my coding chap who wrote it, but I think there must be a more elegant way of doing this?

I think it would be best not to give admins a permanent addaction as they will be playing and I'd hate for them to in the heat of battle mis select and accidently kill a sidemission when all the intended to do was get in to a chopper. :) So I think the trigger tucked away somewhere is a good way of doing this, but want to improve the way we check so we only allow admins to do it.

Share this post


Link to post
Share on other sites

You could just place an if (isServer) then {.....} in the trigger's onAct field so that it only runs on the server...

Alternatively, you can create a radio trigger separately on every admin's machine, and since the trigger created with createTrigger is local only, activating it will only execute the script on the machine of whoever used the trigger. Since the trigger is only created for admins, only admins can activate it.

Share this post


Link to post
Share on other sites

Ahhhh. I like it. :) I'm washing that through my grey matter while I assimilate what you're suggesting. :D

Share this post


Link to post
Share on other sites

Guys, just wanted to say thanks for all your help. While we don't have it working yet, we know how we are going to make it work and you chaps helped us get that understanding. Thank you very much.

Share this post


Link to post
Share on other sites

Quick follow up question guys, if you don't mind.

Can you confirm that _thislist doesn't work for radio triggers? I'm getting null.

Share this post


Link to post
Share on other sites

_thisList will give you a null as far as I know, try removing the '_' because I am sure that thisList does work as I have used many times before.

Example condition:

this && (player in thisList)

so in your case you could try something like:

this && ((adminSlot1 in thisList) OR (adminSlot2 in thisList))

Edited by Andy455

Share this post


Link to post
Share on other sites

Radio triggers have no side or area, thus thislist will be empty.

Andy, you don't need to add "this &&" to conditions with thislist, because this/trigger settings are already included in thislist. So, just use the actual condition.

Share this post


Link to post
Share on other sites

the underscore might have been a typo on my part as I typed that post at work, away from my ArmA2 machine.

Do we know for sure thislist works with radio triggers?

Share this post


Link to post
Share on other sites
thus thislist will be empty.

What part of that was unclear? Radio trigger's thislist will be an empty array.

If you want to pass a list of unit in a trigger area, make it west/present or something and name the trigger. Then you can access that list with "list theTriggername".

However, checking the previous page, area trigger for admins seems a bit silly approach. Why not create a trigger (action none) that fixes the mission and then just check if a player is an admin and then enable that trigger for him/her/them with setTriggerActivation?

Share this post


Link to post
Share on other sites

I'm not sure if my code really has the underscore or not. As I said, I wasn't at my ArmA2 machine when I wrote the post. I asked if _thislist would work for a radio trigger, but it's possible I should have said thislist. No underscore. I don't actually remember what I typed in the code.

Share this post


Link to post
Share on other sites

Underscore means it would be a local variable, which are not allowed in global space (triggers etc editor stuff). So, neither _thislist nor thislist will work directly in a radio trigger.

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
Sign in to follow this  

×