Advertisement

Author Topic: add an action to a specific player  (Read 1028 times)

0 Members and 1 Guest are viewing this topic.

Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
add an action to a specific player
« on: 17 Oct 2011, 09:11:20 »
I want to place an object (eg a laptop or satelite phone) somewhere in the map. And if any player go to this object (very close), I want add to him an acion to the action menu.

Since now, I did this, but only in single player and it was easy:
if (player distance obj1 <2) {
player addAction ...
}

But how can I check many players?

I have to run a script on every client and in this script the "player" variable means the player who play on that client?

EDIT: ================== NEW =====================

I added the action to the object in the init script in the section what only run in the server:
Code: [Select]
? !isServer:goto "kliensresz"
satp addAction ["DL enemy plan", "apacs.sqs"]
#kliensresz
...etc

But this action is only available for the host. Other players cannot activate it.
1. How can I add this action to the object for available to the other players too?

This acion is run an "apacs.sqs".
Code: [Select]
satp removeAction 0
ap1 setPos getPos hpad
[copilota] join pilota

? (player==pilota) : goto "pilotaresz"

exit

#pilotaresz

hq sideChat "Hej pilota, rad nagy szukseg lesz. Teleportalunk neked egy Apacsot a bazis kozeleben a magasleshez."

helimarker = createMarker ["Apacs", getPos hpad ]
helimarker setMarkerType "mil_pickup"
~10
hq sideChat "Menj oda es szallj fel, mert BMP-k is tamadni fognak."

There is a pilot (named "pilota") and one of my tester play this role. I thought, if anybody activate the apacs.sqs the script run on every clients until it check the player==pilota and then it only run in the pilota's client. But unfortunately, this script only run on the server, because ap1 was tepleported to hpad, but the pilot didn't see any message and cannot see the new marker on his map.

2. What I did wrong? How can I fix it?
« Last Edit: 18 Oct 2011, 19:23:17 by bardosy »
Fix bayonet!

Offline Loyalguard

  • Former Staff
  • ****
Re: add an action to a specific player
« Reply #1 on: 18 Oct 2011, 22:44:11 »
I would like to begin by saying I do not know sqs well so please excuse any syntax errors.

For part 1,  If you want the action to be available to all players you could add the code to the init line of the object in the editor.  That would be the easiet way in my opinion.  Open the object and insert this in the init field:

Code: [Select]
this addAction ["DL enemy plan", "apacs.sqs"]
If you think the player can see the action from too far away you can limit distance using the condition parameter of addAction.  For Example less than 2 meters:

Code: [Select]
this addAction [["DL enemy plan", "apacs.sqs", ,true , true, " ","(_this distance _target) < 2)"]
For part 2, you would probably need to use public variables and event handlers to ensure the code ran on all machines.  This means we will have to change things.  Here is what to do:

Step 1 - Enter this into the object for the action in the edtior:

Code: [Select]
this addAction ["DL enemy plan", "download.sqs"]
I will get to download.sqs in a minute.  Next, put this code in the init.sqs:

Step 2 - Add a public variable event handler

Code: [Select]
;If not already created initialize a new public variable
? (!isNil "download"): download = false

;Add a public variable event handler for download that will execute apacs on all machines whenever the PV changes
"download" addPublicVariableEventHandler {exec "apacs.sqs"}

Step 3 - Create download.sqs.

Code: [Select]
;make download true and broacast it to all machines
download = true
publicVariable "download"

;Also execute apacs.sqs directly since a PVEH will not fire on the machine where the PV is broadcasted
exec "apacs.sqs"

This is how it works:

1. A public event handler (PVEH) is added to all machines.  It's job is to wait for the public variable (PV) download to be broadcasted.  When it is, it will execute apacs.sqf.

2. The addAction is available on all machines because it is entered in the init line of the object in the editor.  When a user clicks on it, it will execute download.sqs only for the player that activvated because addAction has local effects only.

3. When download.sqs runs it broadcasts download to all machines so that they can in turn execute apacs.sqs EXCEPT on the machine for the player that used the action since a PVEH will not fire for PV it broadcasts itself, so, it executes apacs.sqs directly

I hope this helps.
« Last Edit: 18 Oct 2011, 22:54:07 by Loyalguard »

Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
Re: add an action to a specific player
« Reply #2 on: 19 Oct 2011, 11:12:56 »
Thank you! I'll try it.

But if I understend correctly, the main problem was the apacs.sqs run only on that client, who activate the action?

And if the PVEH will run the script in all clients, the if-statement player==pilota will work, and that section will run only on pilota's client?
Fix bayonet!

Offline Loyalguard

  • Former Staff
  • ****
Re: add an action to a specific player
« Reply #3 on: 19 Oct 2011, 14:25:19 »
You are correct. apacs.sqs was only run on the client since addAction effects are local only.  Since the PVEH is present on all clients when download is broadcasted, it then causes apacs.sqs to run on all machines(the server and clients -- the server is also needed in case the mission is run on an MP host).  As a result this code from apacs.sqs will run on all machines:

Code: [Select]
satp removeAction 0
ap1 setPos getPos hpad
[copilota] join pilota

but the #pilotaresz section will only run on pilota's machine.

Looking at apacs.sqs again, are ap1 and copilota AI or player units?  You may want to put more if-then checks in so that the setPos and join onl run where those units are local to avoid confusion, duplication, or errors.

Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
Re: add an action to a specific player
« Reply #4 on: 19 Oct 2011, 14:45:20 »
ap1 is an empty apache helicopter.
copilota is an AI pilot.

And I thought these units are local in the server (host).

pilota is a playable pilot.
All these stuffs important only if pilota isPlayer. If pilota is not played by human, all these efforts are useless.

(in the mission's first part (30-50mins) there is no heli support, because the enemy is only infantry. But in the second part, there is a counter-attack and if pilota is a player, enemy have BMP support and pilota can support us from the air. The copilota is in the base, in safe to save him in the first part of the mission, but when pilota needs him as a gunner, he join to pilota.)
Don't ask why! :) I just create this mission for my friends and one of them want to be a pilot, but others don't want let him kill all the enemy infantry, because it's not fun to us (infantry). But I said, it's ok, because I can study the multi-scripting. So this is a study-mission. And if I done, I'll rework my campaigns for multiplayer.
« Last Edit: 19 Oct 2011, 14:47:05 by bardosy »
Fix bayonet!

Offline Loyalguard

  • Former Staff
  • ****
Re: add an action to a specific player
« Reply #5 on: 19 Oct 2011, 15:05:59 »
All of that sounds fine.  Yes, ap1 and copilota will be local to the host server, so I recommend using isServer so that...

Code: [Select]
ap1 setPos getPos hpad
[copilota] join pilota

...only runs on the host server just like you limit #pilotaresz only to pilota.  I am not sure of the best way to do that in sqs.

Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
Re: add an action to a specific player
« Reply #6 on: 19 Oct 2011, 16:05:45 »
I got your last sentence. ;) And I compile everything to sqf...
But I cannot test it right now, so I will report the effect later.

I added these lines to init.sqs:
Code: [Select]
? (!isNil "download"): download = false
publicVariable "download"
"download" addPublicVariableEventHandler {dummy = [] execVM "apacs.sqf";}
And I have a question right here. I used more global variables to detect and/or memory some actions. But I never used this ?(!isNil "download"): Is it important in multiplayer scripting. Because if a JIP join and run the init.sqs againg, is it change the value. But I initialize these global variables in a section (in the init.sqs) what runs only in server (and I hope only once).

Then I add this to the object's init field:
Code: [Select]
satp addAction ["DL enemy plan", "download.sqf"];

And create download.sqf
Code: [Select]
download = true;
publicVariable "download";

_dummy = [] execVM "apacs.sqf";

And finally convert sqs to apacs.sqf:
Code: [Select]
satp removeAction 0;

sleep 0.6;

ap1 setPos getPos hpad;

hq sideChat "Koszi fiuk, hogy letoltottetek az ellenseg terveit!";
sleep 5;

[copilota] join pilota;

if (player==pilota) then
{
   hq sideChat "Hej pilota, rad nagy szukseg lesz. Teleportalunk neked egy Apacsot a bazis kozeleben a magasleshez.";

   helimarker = createMarker ["Apacs", getPos hpad ];
   helimarker setMarkerType "mil_pickup";

   sleep 10;
   hq sideChat "Menj oda es szallj fel, mert BMP-k is tamadni fognak.";
};
I'm not sure what you suggested, but I feel wrong the first part of this, because it runs in avery client. So this script will repos the apache heli as many as count of players. (It's not a problem here (who cares how many times teleport the heli in the same place) But I want to understand the mechanism.
Is it better, if I setPos and join only in the server?

Code: [Select]
if (isServer) then
{
  sleep 0.6;

  ap1 setPos getPos hpad;

  hq sideChat "Koszi fiuk, hogy letoltottetek az ellenseg terveit!";
  sleep 5;

  [copilota] join pilota;
};
Oh, but I guess sideChat is always effect only in the client, so I have to remove it from the isServer section, isn't it?

Fix bayonet!

Offline Loyalguard

  • Former Staff
  • ****
Re: add an action to a specific player
« Reply #7 on: 19 Oct 2011, 17:40:00 »
I was not trying to get you to use .sqf! I am sorry if I sounded that way!  I never learned sqs because I only started scripting after ArmA was published.  That being said, IMO sqf is better! ;)

Regarding !isNil, it is good practice to use !isNil with public variables in init scripts because for JIP players, they will receive the last known value broadcasted of the PV BEFORE the init script runs.  So, if you don't make sure it is nil first, you will overwrite it in the init and it may break the mission.  I don't think JIP is relevant to your mission, but as I said, overall it is good practivce. The Notes section of the publicVariable article on the Biki gives a good overall explanation of why to use !isNil with PVs.:

Also, using satp should work but I think it is better practice to use this instead of the name of the object when entering the code in the init of the object itself:

Code: [Select]
this addAction ["DL enemy plan", "download.sqf"];
yes, setPos and join should only be run in the server, so your example using isServer is fine.  However, note that if you put the sleep commands only witing the isServer block, then it is possible that when the clients skip that part because they are not servers, the pilota client may execute the marker/chat code before the copilota joins pilota.

The other part to consider is the player==pilota section.  Do you want all players to the chats or just pilota?  I assume just pilota but I just want to make sure you did not want to show markers only to pilota but let everyone see the chat.

Isn't MP scripting fun? ;)


Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
Re: add an action to a specific player
« Reply #8 on: 20 Oct 2011, 17:33:05 »
No problem with sqf. I know it's better all way as sqs, but I used to use sqs. I try to work in sqf, but when I do tests or I want create things fast, I always use sqs, because it's easier to develop.
I read somewhere, for multi is much safer in sqf, so I convert these scripts.

But! About the test. It was interesting. We tried it and I was the host and my friend is the pilota.
When he activate the action, the system is works fine, except I saw the new marker on the map, but it suppose to be seen only for the pilota.
It's not a big deal, because other things works: copilota joined, ap1 was teleported... etc.

But when I activate the action, the system was failed: pilota didn't get the special messages and didn't get the marker.
Of course, the copliota was joined to him and ap1 was teleported. But it seemd, the apacs.sqf didn't run on his client.

Any advise...?
Fix bayonet!

Offline Loyalguard

  • Former Staff
  • ****
Re: add an action to a specific player
« Reply #9 on: 20 Oct 2011, 19:25:36 »
Hmmm. Let me analyze a bit and get back to you.

Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
Re: add an action to a specific player
« Reply #10 on: 20 Oct 2011, 19:48:57 »
The problem is bigger! :(

We just finished a full test of my mission. The first part went fine, because it was created in the editor and used only a few, simple script.

But when things was changed, the whole mission became a BUG-mare. :(

1. The creted enemy units (created an east group and added enemy soldiers) cannot shoot us. They were east and we were west. My AI mates kill them, but they didn't shoot back.

2. When my friend flight up with the heli and targeting the incoming BM3 and fired a hellfire, something teleport his heli back to the helipad. But he could save the chopper and fly back to shoot again to the BMP3, but when fired, the heli teleport back again.

3. When we cleard the village from the enemy, a script run (this create the incoming enemy groups, who don't shoot, but first) it say us (sideChat) we well done to clear the village, but be carefull for counter-attack. (it worked fine). But when the all enemy unit is created, a new script was started to waitUntil the counter-attack units headcount is under 2 and then we got a goodbye message and mission END. But this script was run in the same time as we clear the village, so I got the well-done and the good-bye messages in paralel. But mission didn't end.

Oh, it was terrible, how chaotic was this last part of the mission. :(
I was very sad and I will rethink this multi-scripting....

Quote
Isn't MP scripting fun?

Well... I have to sleep now and I will tell you tommorrow.

Anyway, I'm really thankful because of your help!!!!!!
Fix bayonet!

Offline Loyalguard

  • Former Staff
  • ****
Re: add an action to a specific player
« Reply #11 on: 21 Oct 2011, 04:52:49 »
Ok, I have re-worked the scripts and tested it as a MP host and as a client on to a MP host and to a dedicated server I have think I have the first part working.  Here are the scripts, not everything has changed but I am re-posting here to make sure they are all together. I have noted changes or problem areas with comments

Code: [Select]
// init.sqf

if (!isNil "download") then {download = false};

// publicVariable "download"; Remove...not necessary....Sometimes you need to broadcast a PV at mission start but not for this mission.

"download" addPublicVariableEventHandler {_dummy = [] execVM "apacs.sqf";};

Code: [Select]
// download.sqf
 
download = true;
publicVariable "download";
 
dummy = [] execVM "apacs.sqf";

Code: [Select]
// apacs.sqf
 
// Run this on the server and clients.
satp removeAction 0;
 
// Run this on the server and clients.
// Do you need this delay?
sleep 0.6;
 
// Run this on the MP host and clients (but not on dedicated servers).
if (player == pilota) then
{
     // Do you have a unit on the map names "hq"? If not no message will be sent
     hq sideChat "Koszi fiuk, hogy letoltottetek az ellenseg terveit!";
};
 
// Run this on the server and clients.
sleep 5;
 
// Only run this on the server.
if (isServer) then
{
    ap1 setPos getPos hpad;
    [copilota] join pilota;
};
 
// Only run this if the player is pilota.
if (player == pilota) then
{
  hq sideChat "Hej pilota, rad nagy szukseg lesz. Teleportalunk neked egy Apacsot a bazis kozeleben a magasleshez.";

  // To make sure only pilota sees the marker you have to use createMarkeLocal otherwise it has global effects.
  helimarker = createMarkerLocal ["Apacs", getPos hpad];
  helimarker setMarkerType "mil_pickup";
 
  sleep 10;
  hq sideChat "Menj oda es szallj fel, mert BMP-k is tamadni fognak.";
};

I have also attached a demo mission.  It is obviously not as complex as yours but it is on Utes and has units and objects with the correct names so that it functions the same.  Check it out and see if it helps.

Regarding your other problems that occurred after your full test, I cannot say why those things happened without seeing the mission or some code.

Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
Re: add an action to a specific player
« Reply #12 on: 21 Oct 2011, 10:10:00 »
Sleep is always a good aviser. :)
Now I see the (multi scripting) future most brighter.

Thanks for helping me!

Quote
// Run this on the MP host and clients (but not on dedicated servers).
if (player == pilota) then
I don't get this part. Why did you add this if-state to the script?
Later, there is a part where I want say something to only the pilot, but this is not that part.
Maybe you want this: (player==player)  ? And why it needed?


Quote
// Do you have a unit on the map names "hq"? If not no message will be sent
Yes, there is a unit in safe distance, named hq and he send the orders in radio (sideChat).

Quote
// publicVariable "download"; Remove...not necessary....Sometimes you need to broadcast a PV at mission start but not for this mission.
Probably it was the bug, when helicopter is always teleported back, when my friend fired a hellfire.
Because in thet last part of the mission, when heli was airborne, many (unknown) players joined to the mission. Probably they run the init again and publicVariable the false value to "download". And I just realise today, PVEH not only triggered if the valiable is TRUE, but always if variable CHANGED.
So, I will remove this publicVariable AND I'll place an if statement in apacs.sqf to check the value of "download" and only run, if it's true.

Quote
Regarding your other problems that occurred after your full test, I cannot say why those things happened without seeing the mission or some code.

Sure, I know this. I will attach it soon. And if this above solve that problem, only remaining bug is the non-hostile enemies.

Fix bayonet!

Offline Loyalguard

  • Former Staff
  • ****
Re: add an action to a specific player
« Reply #13 on: 21 Oct 2011, 13:52:34 »
I thought that maybe you only wanted that message for pilota, but after doing a google translate search maybe you want all players to see it or maybe just the player that activates the action?  if you want all players then just remove the if-then block and have the sideChat in apacs.sqf.  If you only want the player that aactivates it so see it, then remove it from apacs.sqf and put it somewhere in download.sqf.  download.sqf will only run on the machine where the action is activated (which is why we need the PV for the rest of it).

Sorry about the PV bug.  You are exactly right, it will fire every time it changes, so I did exacty what I said I was trying to avoid (overwriting the value on JIP).  This is a little more advanced, but there is away of limiting what happens for a PVEH based on the value.  addPublicVariableEventHandler has two special variables it can pass to the script it exectutes: _this select 0: variable name _this select 1: new variable value.  So, if we did this in init.sqf...

Code: [Select]
"download" addPublicVariableEventHandler {_dummy = [_this select 1] execVM "apacs.sqf";};
...and then this is apacs.sqf...

Code: [Select]
// Determine if true or false
_value = _this select 1;

// If false the exit immediately:
if (!_value) exitWith {};

...the code in apacs.sqf would only run if true.  It is not necessary here, I just wanted you to be aware.

Offline bardosy

  • Honoured Contributor
  • ***
  • campaign designer
    • CartooDiv
Re: add an action to a specific player
« Reply #14 on: 21 Oct 2011, 14:30:40 »
Sorry for the Hungarian lines! I always create missions in English. This was the only time to use Hungarian lines in a mission, because it's only a test with friends, who don't speak English well. (Yeah, I know, I don't speak neighter... But they speak worst, so I did this Hungarian lines.)

How do you test multi scripts? How can you create a server and join to it as a client?

Oh, BTW, I just remember a few error message showed up. when we played, but I comletly forgot. Se when I'm at home, I will check the RPT file too... Maybe I find more details.

And as I noticed, in a mission always have to be a player (his green dot is circled by red and not purple (as the playable)). Is it true? And this character is a special?
I'm not sure, but I guess in the player serection screen (befor start the mission and waiting for the other players) if no one select this special character, the mission cannot start.
Can I create multi mission without a special-player?
Fix bayonet!