Jump to content
Sign in to follow this  
kyfohatl

Helping a noob with DISPLAYEVENTHANDLER scripting...

Recommended Posts

I've been trying to creat a feature for my mission that allows the player to take control of an AI unit simply by clicking on it (the units cannot be named, or changed in the editor [DAC generated], hence why I can't simply set them as playable in the editor).

So what I'm trying to do is to use DisplayEventHandlers to creat this feuture. However, there seems to be no mention of them in any of the four scripting tutorials I'm using, and the wiki seems to be very noob unfriendly. Anyway, I've looked at the wiki, and all I can undrestand is that displayeventhandlers take an "event" (in this case the pressing of a key) and "attach" some sort of a function or script to it (in this case, I'de be using onMouseButtonClick). Exactly how they do this is too difficult for me to uderstand from the wiki examples. Could anyone help me better understand them?

So here's the example given in the wiki:

(findDisplay 46) displayAddEventHandler ["keyDown", "_this call functionName_keyDown"];

functionName_keyDown =

{

private["_handled", "_ctrl", "_dikCode", "_shift", "_ctrlKey", "_alt"];

_ctrl = _this select 0;

_dikCode = _this select 1;

_shift = _this select 2;

_ctrlKey = _this select 3;

_alt = _this select 4;

_handled = false;

if (!_shift && !_ctrlKey && !_alt) then

{

if (_dikCode in (actionKeys "NetworkStats")) then

{

nul = [] execVM "path\script.sqf";

_handled = true;

};

};

_handled;

};

I can see that local variables such as "_Ctrl" or "_shift" refer to the buttons, but I have no idea what the line

(findDisplay 46) displayAddEventHandler ["keyDown", "_this call functionName_keyDown"];

does.

Also, how do I refere to the position on the map where I clicked with my mouse (is it possibly "_pos"?)?

And finally, here is what I'm intending to do:

OnMouseButtonClick -----> triggers the script: selectPlayer (nearestObject [_pos, "CAManBase"]) (so the player takes control of the unit he clicked on, on the map).

By the way, I have tried (thanks to alot of help from Kyliana and UNN):

onMapSingleClick "selectPlayer (nearestObject [_pos, "CAManBase"])"

Though "onMapSingleClick" works fine for a small test mission I tried on Utes, it for some reason doesn't work on my actual missions (with more units, in Chernarus), which is why I'm trying to use event handlers (onMapSingleClick sometimes works and sometimes doesn't, and it seems to be completely random, it lets me play as some units and not as others).

Thanks for the help. Sorry, I know I ask too many questions. I guess it comes from having not having any previous programming experience.

Share this post


Link to post
Share on other sites
but I have no idea what the line

(findDisplay 46) displayAddEventHandler ["keyDown", "_this call functionName_keyDown"];

does.

findDisplay 46 refers to what display the displayAddEventHandler is interacting with. If display 46 was not active, nothing would happen. Can refer to main 3D screen, map, other vanilla displays (I don't remember the codes) or some custom display.

displayAddEventHandler is the command, doh :p

"keyDown" is the hook, what is it that you want to trigger the script, like keyDown, mouseOver, or whatever. When that event happens, the following call is performed. Check here for a complete list. The UAV system is one example where keys are trapped.

call functionName_keyDown is of course the function you have in your snippet, which in turns execVMs "path\script.sqf" which is where your own code goes - either in own file or just paste it within the then statement.

Consider onMapSingleClick a prebuilt displayEventHandler, where you don't have to mess with anything except obtaining the position and executing your code. But the "'s looks a bit wrong, shouldn't it be:

"the whole thing having ""strings"" encapsulated in apostrophes" ? Single " is read as code, while double "" is read as strings.

Share this post


Link to post
Share on other sites
But the "'s looks a bit wrong, shouldn't it be:

"the whole thing having ""strings"" encapsulated in apostrophes" ? Single " is read as code, while double "" is read as strings.

I think t looks a bit strange too... I got it from UNN's post since I don't trust my scripting skills enough (he wrote it for me). As you know, I've asked a question about the proper use of brackets; well, this is exactly why I asked it. Anyway, according to guidelines I got from skilled scripters like yourself:

we have: onMapSingleClick {CODE ---> then command ----> then array ---> then Classname}

So shouldn't it be: onMapSingleClick {selectPlayer (nearestObject [_pos, 'CAManBase'?

Anyway, so would this work?

(findDisplay <code for map>) displayAddEventHandler ["onMouseButtonClick", "_this call Function_MapClick"]

Function_MapClick:

private [_click, _returnvalue];

_click = _this select 0;

_returnvalue = false;

if (_click) then {

execVM "MyProcedure.sqf";

_returnvalue = true;

};

_returnvalue

MyProcedure.sqf:

selectPlayer (nearestObject (_pos, 'CAManBase'))

Theres a few things I don't understand:

1. Why am I returning a value in the Function_MapClick? I did it because the wiki did, but I don't really know why its necessary.

2. Where do I find the codes for the displays? (I of course need a code for the world map, but I couldn't find a list of display codes in the wiki)

3. How do I refer to the position I clicked on the map? At the moment I'm using "_pos", but I'm not sure if it will work.

4. Where do I put the line: (findDisplay <code for map>) displayAddEventHandler ["onMouseButtonClick", "_this call Function_MapClick"]

Do I put it in init.sqs, or some script, or a trigger???

Anyway, thanks for your response :).

Edited by kyfohatl

Share this post


Link to post
Share on other sites
I think t looks a bit strange too... I got it from UNN's post since I don't trust my scripting skills enough (he wrote it for me).

No, I wrote this:

onMapSingleClick "selectPlayer (nearestObject [_pos,'soldierWB'])"

Which is not the same. Note the use of single and double quotes.

Share this post


Link to post
Share on other sites

Which is not the same. Note the use of single and double quotes.

The expression doesn't need to be a string. All onBla commands work fine with normal code too.

onMapSingleClick {selectPlayer (nearestObject [_pos,"soldierWB"])};

Xeno

Share this post


Link to post
Share on other sites
The expression doesn't need to be a string.

Who said it did?

Share this post


Link to post
Share on other sites

The reason it won't work is because of a little quirk with what _pos is actually getting, which is not very obvious. Frankly I thought that was fixed by now, but. I think Xeno will remember how artillery position distances was messed up because of this :)

This will not work: onMapSingleClick {selectPlayer nearestObject [_pos, 'CAManBase']}

But this will: onMapSingleClick {selectPlayer nearestObject [[_pos select 0, _pos select 1, 0], 'CAManBase']}

Now, the first one may work on certain islands (Utes?) and not others (Takistan?) because the _pos that is actually obtained has an elevation of absolute zero. When you replace it, it becomes zero meters AGL. Pretty weird stuff actually.

You can verify this by:

onMapSingleClick {hint format ["Dist: %1", player distance _pos]}

or

onMapSingleClick {hint format ["Pos: %1", _pos]}

and just try to click on yourself. On the main airport in Takistan, I get 297m distance (or -297m altitude) which doesn't make sense. Reason; I'm at elevation 2297, and island has elevation offset 2000, which gives 297.

And since nearestObject only searches within a 50m (3D) radius, it won't find the man you clicked on/near.

Edit: I guess on the positive side of things, having _pos work this way allows you to get altitude by the click rather than dealing with a 2D position where you have to place a dummy object to get the altitude. So it complicates things a little for us (more typing), but it allows greater flexibility in its use.

Edited by CarlGustaffa

Share this post


Link to post
Share on other sites

@UNN: oops... FPDR. I even failed at copying your post. Sorry UNN, didn't mean to ruin your good scripting reputation :o.

@CarlGustaffa: You are absolutely right. Your script works perfect. And yes, the previous script worked on Utes, whilst not working on Chernarus. So what your saying, is that _pos gives you three dimenstion [X,Y,Z], and the "Z" component messes it up (because of varying hights). So you use "_pos select 0 and _pos select 1" to get around it?

Thanks for your help man :).

Oh, and will the event handler script of written in post #3 work? (its probably very VERY wrong :o)

Share this post


Link to post
Share on other sites

Yes, but in array form:

[_pos select 0, _pos select 1, 0]

since _pos is already in array form just containing a weird z coordinate.

Didn't check your EventHandler, as it's not needed. You should go with the

bMyBooleanThatConfirmsJobDone = false;

onMapSingleClick { ...code... ; bMyBooleanThatConfirmsJobDone = true} instead, which is the same but in much more simplified form to use.

Remember to:

waitUntil {!visibleMap || !alive player || bMyBooleanThatConfirmsJobDone};

onMapSingleClick {}; //Stops the previous handling (clicking again won't select yet another player).

Share this post


Link to post
Share on other sites
Sorry UNN, didn't mean to ruin your good scripting reputation

Well I can't imagine there are many people, old or new, who like being misquoted :)

BTW If you can see the map icons of the units you want to control, then this is quite a neat method:

init.sqf for example:

waitUntil {!(isNull (findDisplay 12))};
_index=(findDisplay 12) displayAddEventHandler ["MouseButtonDown","if !(isNull cursorTarget) then {selectPlayer cursorTarget ; openMap false}"]

Now you don't have to worry about other peoples addons with displayAddEventHandler . If you want to turn the feature off, either remove the event handler or add some additional logic to its code.

If you don't get to see the icons, then use:

waitUntil {!(isNull (findDisplay 12))};
_index=(findDisplay 12) displayAddEventHandler ["MouseButtonDown","_unit=nearestObject [((_this select 0) displayCtrl 51) posScreenToWorld [_this select 2,_this select 3],'CAManBase'] ; if !(isNull _unit) then {selectPlayer _unit ; openMap false}"]

posScreenToWorld always returns a z value of 0.

Forgot to ask, this is for a single player isn't it? Other wise select player won't work on remote units in an MP session. At least that was the case with Arma1, as always in most cases, there are work arounds.

Edited by UNN

Share this post


Link to post
Share on other sites

@UNN: Excellent. Thanks UNN. I was actually using a gamelogic with the init line of DAC_Marker = 3 (which of course uses DAC markers to show units on the player map). But that required me create a new logic every time the player died, and then delete it as soon as the player came back to life (since I didn't know how to change the gamelogic's options ingame). But this method is much neater.

this is for a single player isn't it?

Yeah, its singleplayer.

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  

×