Jump to content

igneous01

Member
  • Content Count

    924
  • Joined

  • Last visited

  • Medals

Posts posted by igneous01


  1. I'm trying to revive a script that someone wrote in the mod section to allow the AI gunner in a helicopter to follow where the pilot player is looking.

     

    It used to work by creating a laser target, setting the gunner to target it via commandTarget, and then update the laser target position every few ms based on where the player is looking.

     

    The problem I've run into now is that when the player is in the driver/pilot seat of the helicopter, the gunner wont target anything.

     

    If the player leaves the helicopter, the gunner will target the laser. When the player jumps back in, he stops targeting.

     

    I've tried various things:

     

    - making gunner group leader

    - making gunner join another group

    - making the gunner captive

    - disableAI "ALL" on gunner

    - doWatch

    - doTarget

    - commandWatch

     

    Nothing works - I don't know if this is a bug with vehicles, but I cant get the gunner to target anything when I am inside the vehicle. 

     

    Has anyone had any luck with getting this to work?

    • Like 1

  2. Both of these methods do not work anymore. The first one doesn't do anything, and the second one causes the engine to shut off and crash into the ground.

     

    I tweaked this to make another version that does work (I can control the turret) but it's not possible to change weapons while controlling the turret (and it seems random what weapon is selected) - so it seems like there's no reliable way of getting this to work today at all.

     

    CH_fnc_controlGun = {
    	_heli = vehicle player;
    	_gunner = gunner _heli;
    
    	player remoteControl _gunner; 
    	_heli switchCamera "GUNNER";
    
    	waitUntil {cameraView != "GUNNER"};
    
    	objNull remoteControl _gunner;
    };

     


  3. It's been a while since I last played Arma - before the Helicopters DLC at least. It's great to see the improvements made in the flight model with things like VRS and Overspeeding the rotors.

     

    But one thing I am dumbfounded by is the lack of being able to manually guide a Scalpel ATGM on a target. I understand that it requires another weapon lasing (or IR lock) but it's really unfortunate the gunner can't manually guide the missile.

     

    It would be nice to be able to do popup attacks on AA targets at a distance where you still have enough time to maneuver back into cover, but without a way to manually guide it in that makes all modern helicopter tactics unusable.

     

    Now I know most people will say that AA will always have the advantage in range, but that doesn't mean it's impossible to kill an AA unit.

     

    For example, in DCS Black Shark, the SA-8 OSA has an effective range of 10km, with the Ka-50 effective range for the Vikhr ATGM at about 7.2 - 7.5 km - even though the SA-8 has nearly 3km more range than the Ka-50, with proper positioning the Ka-50 can popup behind a mountain, fire off a missile, and destroy the SA-8 at about the same time the SA-8 has fired it's missile (now because the SA-8 is destroyed the missile goes ballistic because the radar is no longer actively tracking, but that's another story). All AAA weapons like the Shilka are outranged by the KA-50 because it's maximum AAA range is 4km.

     

    So it's not unrealistic for an attack helicopter to face against AAA or light Radar SAM platform. Obviously heavy duty SAMs like the BUK and S-300 will always win against an Attack Helo, but for lighter SAM threats (such as what's portrayed in Arma) can totally be handled by an attack pilot with enough skill.

     

    This is a bit off topic - but the possibility of adding in HARM (Homing Anti-Radiation Missiles) missiles would be great - some models of attack helicopters have been known to carry light to medium range HARMs in a SEAD role.


  4. If you want to change the position where the text is rendered, you need to use the 'style' property:
     

    // basic styles, generated through gui editor
    
    #define ST_POS            0x0F
    #define ST_HPOS           0x03
    #define ST_VPOS           0x0C
    #define ST_LEFT           0x00 // Left aligned text
    #define ST_RIGHT          0x01 // Right aligned text
    #define ST_CENTER         0x02 // Center aligned text
    #define ST_DOWN           0x04
    #define ST_UP             0x08
    #define ST_VCENTER        0x0C
    
    #define ST_TYPE           0xF0
    #define ST_SINGLE         0x00 // Single line textbox
    #define ST_MULTI          0x10 // Multi-line textbox (text will wrap, and newline character can be used). There is no scrollbar, but mouse wheel/arrows can scroll it. Control will be outlined with a line (color = text color).
    #define ST_TITLE_BAR      0x20 // Light gray background with 3D border
    #define ST_PICTURE        0x30 // 'Text' property is interpreted as an image path.
    
    class myText
    {
    	style = ST_LEFT + ST_MULTI;	// Text overflow will go to a new line
    };
    
    class myCenterAlignedText
    {
    	style = ST_CENTER + ST_MULTI;
    };
    
    class myCenterBottomText
    {
    	style = ST_DOWN + ST_MULTI;
    };
    
    class myCenterTopText
    {
    	style = ST_UP + ST_MULTI;
    };

    The above code only shows the property you need to change - you still need to have the other properties set up in your text class for it to render properly.

     

    If you want to be able to format individual lines inside of a single text field, then you need to use a structured text class, not a text class:

    class ignStructuredText : ignBase
    {
    	type = CT_STRUCTURED_TEXT;
    	style = ST_UP + ST_MULTI;		
    	size = 1;						
    };

     

    afterwards in the .sqf for your dialog, you can format the text as html and use parseText:

    https://community.bistudio.com/wiki/parseText

     

    ^ this link above explains how you can change color, font size, etc using structured text.


  5. On 3/7/2017 at 7:07 AM, fn_Quiksilver said:

     

    bohemia encrypts their stuff, and awarded big money $50k to winners of MANW contest who heavily obfuscated and encrypted their stuff

     

    also there is no such thing as 'the arma community'. there is no community spirit between average Arma 3 Life player and most milsim unit members, for instance. there are half a dozen definable 'arma communities', and unfortunately some of them in recent years have turned to theft. i dont see problem with modder doing what he can to resist theft.

    One of the winners of MANW took my mission, all the scripts inside it, then simply replaced the helicopters with UN helicopters, and presto. 


  6. As Serena mentioned, those commands will help control individual targets.

     

    As for calculating accuracy, if the targets your using have selection support in the hitpart event, you can easily determine if the shot was accurate. Otherwise do what bis did in the COF - create gamelogics and attach them to the target spots, then on hitpart you can compare the hit position distance to the game logic.


  7. I'm a bit confused about the benefits of using missionConfigFile. On the one hand it is a nice place to define constants and paths to resources, but on the other config lookups are relatively slow compared to a global variable already in memory.

     

    If I have a bunch of constants that are being referenced (say on fired handler/hit handler/onEachFrame) does it make sense to even use missionConfig for this purpose?


  8. 11 hours ago, serena said:

    To get all mission targets:

    
    AllMissionObjects "TargetBase"

    Careful with this if you are using any railings for moving targets - they are also part of the "TargetBase" family.

    Interestingly enough, the swivel targets do not use "TargetBase" as a parent, so you need to get those through one of the parents.


  9. Do you have any mods installed that may be interfering?

    Do you have any other scripts running (like maybe an incognito/stealth script) that may be interfering with side alliances?

    It sounds like a 'fired' handler is changing the friendliness of resistance and altering the behavior you see in your script.

    Have you tried running just this code in an isolated test case?

     

    Another thing comes to mind - are the ai fleeing / surrendering?

     

    I believe that when ai are captive they change sides. It would be a good idea to check if the ai is not your captive / is fleeing / is surrendered


  10. 3 minutes ago, killzone_kid said:

     

     

    This is not what I posted.

    1. you cannot execVM if you need to return true

    2. you cannot have ;true in macro

    3. missing }

    So once again, you haven't tried the solution I posted, have you? 

     

    What you posted does not apply to my problem.

     

    Ok seriously, whats with the toxicity here? I remember this community was A LOT more well behaved than it is now. I was not expecting to be insulted and treated as incompetent when asking some questions (and the fact that you tried to insult me as being wrong about the single quotes is ridiculous - have you even tested this yourself?

     

    Yes, I did try your original code, it worked, but it wasn't the problem or the use case I was describing. Don't be a hypocrite about not trying your code when you havn't even bothered testing what I deem as a bug in the parser.

    I think it's best we leave this thread here. There is nothing more to be said besides insults at this point. I'll say thanks for the brainstorming as it gave me an idea for working around this, but I am absolutely disgusted with your behavior.


  11. 2 minutes ago, killzone_kid said:


    Hate to state the obvious, but you can return true in your script

    The script doesn't return true, it's meant to call handlers registered to my events. Although I suppose the workaround is to pass it as an argument to the function and return true if something is passed in. I think I'll just do that instead - thanks for the idea.

     

    6 minutes ago, killzone_kid said:


    This works. You haven't tried it, have you?

    Yes I did - same problem:

    #define MYMACRO(SCRIPT) \
     onCanDestroy = ['IGN_Event_onCanDestroy', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM SCRIPT; true
    
    
    // Base control class
    class ignBase
    {
    	access = 0;
    	idc = -1;
    
    	x = 0.5;
    	y = 0.5;
    	w = 0.2;
    	h = 0.2;
    
    	moving = IGN_DLG_Template_ControlMoving;	
    
    	font = IGN_DLG_Template_Font;
    	sizeEx = IGN_DLG_Template_FontSize;
    
    	colorText[] = IGN_DLG_Template_ColorText;
    	colorBackground[] = IGN_DLG_Template_ColorBackground;
    
    	text = "";
    	shadow = IGN_DLG_Template_Shadow;
    
    	size = 1;
    
    	// based on defaults provided in rscText
    	tooltipColorText[] = IGN_DLG_Template_ToolTipColorText;
    	tooltipColorBox[] = IGN_DLG_Template_ToolTipColorBox;
    	tooltipColorShade[] = IGN_DLG_Template_ToolTipColorShade;
    
    	// Events - all controls implement these two events
    	MYMACRO("scripted\IGN_DLG\internal\IGN_DLG_raiseEvent.sqf"); // true is a new definition, not treated as part of same code.

     

     


  12. 33 minutes ago, killzone_kid said:

    Anyway. The following works.... just to prove my point above:
     

    
    #define MYMACRO(SCRIPT) onCanDestroy = [] call compile preprocessFileLineNumbers SCRIPT
    class myControl
    {
    	MYMACRO("pathtosomescript");
    };

    Also, this is not useful as each control event passes in different sets of parameters - so I would have to define a macro for each event (which defeats the purpose)

    Correction - this wont work either because onCanDestroy needs the code passed in as a string. The moment you use double quotes to surround MYMACRO, the SCRIPT parameter will not be replaced with a path.

     

    33 minutes ago, killzone_kid said:


    For example, I have this right now:
     

    
    #include "BIS_Defaults.hpp"
    #include "Font_Definitions.hpp"
    #include "Color_Definitions.hpp"
    #include "Template_Default_Definitions.hpp"
    
    // ************* MACROS ************************************************************************
    
    // Directory macro
    #define IGN_DLG_DIR scripted\IGN_DLG\internal\IGN_DLG_raiseEvent.sqf
    
    #define ctrlOnCanDestroy \
    	onCanDestroy = "['IGN_Event_onCanDestroy', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM 'scripted\IGN_DLG\internal\IGN_DLG_raiseEvent.sqf'; true;"
    
    #define displayOnLoad \
    	onLoad = "['IGN_Event_onLoadDisplay', _this, ctrlIDD (_this select 0)] execVM 'scripted\IGN_DLG\internal\IGN_DLG_raiseEventDisplay.sqf'; true;"
    
    #define displayOnUnload \
    	onUnload = "['IGN_Event_onUnloadDisplay', _this, ctrlIDD (_this select 0)] execVM 'scripted\IGN_DLG\internal\IGN_DLG_raiseEventDisplay.sqf'; true;"
    
    // CONTROL EVENTS
    
    #define ctrlOnButtonClick \
    	onButtonClick = '[''IGN_Event_onButtonClick'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnButtonDown \
    	onButtonDown = '[''IGN_Event_onButtonDown'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnButtonUp \
    	onButtonUp = '[''IGN_Event_onButtonUp'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseEnter \
    	onMouseEnter = '[''IGN_Event_onMouseEnter'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseExit \
    	onMouseExit = '[''IGN_Event_onMouseExit'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnSetFocus \
    	onSetFocus = '[''IGN_Event_onSetFocus'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnKillFocus \
    	onKillFocus = '[''IGN_Event_onKillFocus'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnTimer \
    	onTimer = '[''IGN_Event_onTimer'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnLBDrop \
    	onLBDrop = '[''IGN_Event_onLBDrop'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnKeyDown \
    	onKeyDown = '[''IGN_Event_onKeyDown'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3, _this select 4]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnKeyUp \
    	onKeyUp = '[''IGN_Event_onKeyUp'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3, _this select 4]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnChar \
    	onChar = '[''IGN_Event_onChar'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseButtonDown \
    	onMouseButtonDown = '[''IGN_Event_onMouseButtonDown'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3, _this select 4, _this select 5, _this select 6]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseButtonUp \
    	onMouseButtonUp = '[''IGN_Event_onMouseButtonUp'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3, _this select 4, _this select 5, _this select 6]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseButtonClick \
    	onMouseButtonClick = '[''IGN_Event_onMouseButtonClick'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3, _this select 4, _this select 5, _this select 6]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseButtonDblClick \
    	onMouseButtonDblClick = '[''IGN_Event_onMouseButtonDblClick'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3, _this select 4, _this select 5, _this select 6]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseMoving \
    	onMouseMoving = '[''IGN_Event_onMouseMoving'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseHolding \
    	onMouseHolding = '[''IGN_Event_onMouseHolding'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2, _this select 3]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnMouseZChanged \
    	onMouseZChanged = '[''IGN_Event_onMouseZChanged'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnDestroy \
    	onDestroy = '[''IGN_Event_onDestroy'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnIMEChar \
    	onIMEChar = '[''IGN_Event_onIMEChar'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnIMEComposition \
    	onIMEComposition = '[''IGN_Event_onIMEComposition'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnJoystickButton \
    	onJoystickButton = '[''IGN_Event_onJoystickButton'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnLBSelChanged \
    	onLBSelChanged = '[''IGN_Event_onLBSelChanged'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnLBListSelChanged \
    	onLBListSelChanged = '[''IGN_Event_onLBListSelChanged'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnLBDblClick \
    	onLBDblClick = '[''IGN_Event_onLBDblClick'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnLBDrag \
    	onLBDrag = '[''IGN_Event_onLBDrag'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnLBDragging \
    	onLBDragging = '[''IGN_Event_onLBDragging'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnCheckBoxesSelChanged \
    	onCheckBoxesSelChanged = '[''IGN_Event_onCheckBoxesSelChanged'', [ctrlParent (_this select 0), _this select 0, _this select 1, _this select 2]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnSliderPosChanged \
    	onSliderPosChanged = '[''IGN_Event_onSliderPosChanged'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR'''
    
    #define ctrlOnVideoStopped \
    	onVideoStopped = '[''IGN_Event_onVideoStopped'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''
    
    // ********************** MACROS END ***************************************************************
    
    // Base control class
    class ignBase
    {
    	access = 0;
    	idc = -1;
    
    	x = 0.5;
    	y = 0.5;
    	w = 0.2;
    	h = 0.2;
    
    	moving = IGN_DLG_Template_ControlMoving;	
    
    	font = IGN_DLG_Template_Font;
    	sizeEx = IGN_DLG_Template_FontSize;
    
    	colorText[] = IGN_DLG_Template_ColorText;
    	colorBackground[] = IGN_DLG_Template_ColorBackground;
    
    	text = "";
    	shadow = IGN_DLG_Template_Shadow;
    
    	size = 1;
    
    	// based on defaults provided in rscText
    	tooltipColorText[] = IGN_DLG_Template_ToolTipColorText;
    	tooltipColorBox[] = IGN_DLG_Template_ToolTipColorBox;
    	tooltipColorShade[] = IGN_DLG_Template_ToolTipColorShade;
    
    	// Events - all controls implement these events
    
    	ctrlOnCanDestroy;
    	ctrlOnDestroy;
    	ctrlOnMouseEnter;
    	ctrlOnMouseExit;
    	ctrlOnTimer;
    	ctrlOnKeyDown;
    	ctrlOnKeyUp;
    	ctrlOnMouseButtonDown;
    	ctrlOnMouseButtonUp;
    	ctrlOnMouseButtonDblClick;
    	ctrlOnMouseMoving;
    	ctrlOnMouseHolding;
    	ctrlOnMouseZChanged;
    
    };

     

     


  13. 24 minutes ago, killzone_kid said:


    Yeah! It is very easy and comfortable to blame BIS for everything. Use command with wrong type, the command must be broken! Fail to define a variable, WTF BIS!!11!! Not understanding how pre-processor works, BIS FIX THIS!!!!!!!!!!

     

    I made a typo with my example above try this in description.ext and you'll see what I mean:

     

    class myControl
    {
    	onCanDestroy = '[] execVM ''Somescript.sqf''; true;';
    };
    
    // or
    
    class myControl
    {
    	onCanDestroy = '[] execVM "Somescript.sqf"; true;';
    };

    This will not properly compile, it will think that true is a new property you are defining for the control.

     

    This is what you'll see when you do this:

    http://steamcommunity.com/sharedfiles/filedetails/?id=867939804

     

    Quote

     

    You made 2 errors minimum:
     


    You cannot call the string path of a script
     

    That was a typo - I'll correct it in my comment (should be execVM)

    Quote


    It has to finish with  ;

    Anyway. The following works.... just to prove my point above:
     

    
    #define MYMACRO(SCRIPT) onCanDestroy = [] call compile preprocessFileLineNumbers SCRIPT
    class myControl
    {
    	MYMACRO("pathtosomescript");
    };

     

     

    I can get that working using the following as well:

    #define IGN_DLG_DIR scripted\IGN_DLG\internal\IGN_DLG_raiseEvent.sqf
    
    #define ctrlOnButtonClick \
    	onButtonClick = '[''IGN_Event_onButtonClick'', [ctrlParent (_this select 0), _this select 0]] execVM ''IGN_DLG_DIR'''

     

    The problem is when I need to add additional statements using ';' (such as returning true onCanDestroy)

    I had this, and it was not working:

    #define IGN_DLG_DIR scripted\IGN_DLG\internal\IGN_DLG_raiseEvent.sqf
    
    #define ctrlOnCanDestroy \
    	onCanDestroy = '[''IGN_Event_onCanDestroy'', [ctrlParent (_this select 0), _this select 0, _this select 1]] execVM ''IGN_DLG_DIR''; true;'
    
    class ignBase
    {
    	access = 0;
    	idc = -1;
    
    	x = 0.5;
    	y = 0.5;
    	w = 0.2;
    	h = 0.2;
    
    	moving = IGN_DLG_Template_ControlMoving;	
    
    	font = IGN_DLG_Template_Font;
    	sizeEx = IGN_DLG_Template_FontSize;
    
    	colorText[] = IGN_DLG_Template_ColorText;
    	colorBackground[] = IGN_DLG_Template_ColorBackground;
    
    	text = "";
    	shadow = IGN_DLG_Template_Shadow;
    
    	size = 1;
    
    	// based on defaults provided in rscText
    	tooltipColorText[] = IGN_DLG_Template_ToolTipColorText;
    	tooltipColorBox[] = IGN_DLG_Template_ToolTipColorBox;
    	tooltipColorShade[] = IGN_DLG_Template_ToolTipColorShade;
    
    	// Events - all controls implement these events
    
    	ctrlOnCanDestroy;	// error here - ignBase.True missing definition
    };
    

     


  14. That doesn't work, as the macro doesn't get processed inside double quotes.

     

    However it appears that the BI Sim wiki is more explanatory about macros:

     

    https://resources.bisimulations.com/wiki/PreProcessor_Commands#Defines_in_strings

     

    You can expand a macro if it's inside single quotes like so:

    #define MY_NUM 2
    player sidechat 'The number is MY_NUM'; // shows "The number is 2"
    // with double quotes the define will be output verbatim:
    player sidechat "The number is MY_NUM"; // shows "The number is MY_NUM"

     

    This works in Arma 3 as well, however there appears to be a bug with the description.ext parsing if you use single quotes:

    onCanDestroy = '[] execVM MYMACRO; true;';	// MYMACRO expands, but description.ext parser thinks that ';' ends the line, and later complains that myControl.true - encountered ';' expected '='

    This doesn't happen with double quotes, but with single quotes the parser interprets this:

    #define MYMACRO "somepath\somescript.sqf"
    onCanDestroy = '[] execVM MYMACRO; true;'
    
    Parser defines as:
    
    class myControl
    {
    	onCanDestroy = '[] execVM "mypath\somescript.sqf";
    	true;
    	';
    };

    So unless BIS fixes this for description.ext, looks like what I want to do is not possible.


  15. I have a build script where I'm trying to generate some UI classes and attaching some handlers to them using macros.

     

    
    #include "BIS_Defaults.hpp"
    #include "Font_Definitions.hpp"
    #include "Color_Definitions.hpp"
    #include "Template_Default_Definitions.hpp"
    
    // ************* MACROS ************************************************************************
    
    // Directory macro
    //#define IGN_DLG_DIR 'scripted\\IGN_DLG\\IGN_DLG_raiseEvent.sqf'
    //scripted\IGN_DLG\IGN_DLG_raiseEvent.sqf
    
    // CONTROL EVENTS
    
    #define ctrlOnButtonClick \
    	onButtonClick = "['IGN_Event_onButtonClick', [ctrlParent (_this select 0), _this select 0]] execVM 'scripted\IGN_DLG\IGN_DLG_raiseEvent.sqf'"
    
    #define ctrlOnButtonDown \
    	onButtonDown = "['IGN_Event_onButtonDown', [ctrlParent (_this select 0), _this select 0]] execVM 'scripted\IGN_DLG\IGN_DLG_raiseEvent.sqf'"

    Everything works as long as my script folder is inside a 'scripted' folder, but if I want to add flexibility of relocating my scripts to a different path, this breaks.

     

    I want to be able to define the parent path like so:

     

    #define LIB_PATH = "AnotherFolder\IGN_DLG"
    

    Then on the #define ctrlOnButtonClick replace only a part of the definition with part of the LIB_PATH macro like so:

    #define ctrlOnButtonClick \
    	onButtonClick = "['IGN_Event_onButtonClick', [ctrlParent (_this select 0), _this select 0]] execVM 'LIB_PATH\IGN_DLG_raiseEvent.sqf'"

    But this doesn't work. I've read you can combine macros together like so:

    ##LIB_PATH##\IGN_fnc_raiseEvent.sqf

    but I also have problems getting this to work (I'm assuming if you #define "MyPath\IGN_DLG" it also inserts the quotes, which screws up the original string.

    Anyone know a way around this?


  16. I have some functions that are used to generate / obtain a subset from a collection, with a predicate as an argument (a form of Inversion of Control), but the problem is that the call generates a lot of overhead.

    fnc_generate = {
    	params["_size", "_initV", "_pred"];
    	private _array = [];
    	private _it = _initV;
    	for [{_i = 0}, {_i < _size}, {_i = _i + 1}] do
        {
            _array pushback (call _pred);                        
        };   
        _array;
    };
    fnc_subset = 
    {
    	params["_array", "_pred"];
    	private _collection = [];
    	{
    		if (_x call _pred) then { _collection pushback _x; };
    	} foreach _array;
    	_collection;
    };


    I'm comparing doing the following:

    // Manual way
    BIGARRAY = [];
    for [{_i=0}, {_i < 10000}, {_i = _i + 1}] do
    {
          BIGARRAY pushback _i;
    };
    // 45 ms avg
                              
    BIGARRAY = [];
    BIGARRAY = [10000, 0, {_it = _it + 1; _it;}] call fnc_generate;
    // 68 ms avg
                              
                              
    // manual way
    SUBSET = [];
    {
    	if (_x > 10) then { SUBSET pushback _x; };
    } forEach BIGARRAY;
    
    // 47 ms avg
    
    SUBSET = [];
    SUBSET = [BIGARRAY, {_this > 10;}] call fnc_subset;
    
    // 69 ms avg

     

    Adding call makes the code ~28% slower, and this starts to get noticeable if you are doing things like this often/with larger sets of data.

    Is there a way to inline the predicate so that it just replaces (call _pred) with the predicate code the user passed in?

    Macros have a way of doing this sort of replace, but the problem is you cant use preprocess commands on a function, only on a filepath.


  17. The last argument of PlayerConnected is owner ID, which is the same value returned from clientOwner. Depending on what scripts you have being execVM in that loop, may not work like that. You would need to remoteExec the script on that players machine using the owner ID that PlayerConnected returned.

     

    The other problem is that loop you have above doesn't handle the JIP queue. It's better to use remoteExec in this case and specify which commands should be added to JIP queue and which ones should not.

    • Like 1

  18. nearestObjects doesn't support waypoints and it wont return them. If you need to get a list of all waypoints on the map then you need to use:

     

    private _waypointPositions = [];
    {
    	private _group = _x;
    	{
    		private _wp = _x;	// this is not the same _x as above, we are in a different forEach scope
    		_waypointPositions pushback (waypointPosition _wp);
    	} forEach (waypoints _group);	// _x is current group
    } forEach AllGroups;

     


  19. Looking at the ContainerOpened event on the wiki, the arguments you pass in don't have to be local, but the effect of the add handler call is local to the machine. So as you have it setup now it should work, but I think this note gives a clue:

     

    Quote

    Triggers when cargo container is accessed by player. This event handler is similar to "InventoryOpened" EH, but needs to be assigned to the container rather than the player and cannot be overridden. Note: will trigger only for the unit opening container..

     

    Maybe try adding the handler on all machines? The description seems a bit contradictory (what does it mean override? You should be able to add multiple handlers to this event).

     

    Do you see it logging the message at least when you run it currently?

     

    • Like 1

  20. How is the supply crate being created? With CreateVehicle or CreateVehicleLocal? Is there only 1 supply crate that all clients see, or does each client have their own version of the supply crate?

     

    The addHandler call should be run on the machine that 'owns' the crate. That means if the server created the crate, this could should only run on the server.

     

    What does CTISHR_fnc_ctiLog do? Is it just logging using diag_log? if there's other stuff happening here you need to check the locality of it.


  21. AI Groups don't normally communicate in default Arma. You either script it or use guarded/sentry waypoints.

     

    Ie. to have a set of groups act as reinforcements, you would setup some groups to have a 'guard' waypoint. Then have another group/groups have a 'sentry' waypoint. What happens is when the sentry detects enemy units, they will request reinforcements from the 'guard' pool to assist. I believe it calls all the guard groups to assist, but if there are multiple locations where sentries are requesting assistance then the reinforcements will split off to defend each (don't quote me on this, it was how it worked in Arma 2).

     

    The other option is to script it - you would need a loop running for the duration of the mission where, each time a group detects a unit, they broadcast that information to all other groups in the network. Unfortunately there is no 'detected' event, so you would need to compare each result using knowsAbout.

     

    {
    	private _unit = _x;
    	{
    		private _entity = _x;
    		if (_unit knowsAbout _entity > 0.1) then
    		{
    			{_x reveal [_entity, (_unit knowsAbout _entity)} forEach allEnemyGroups;
    		};
    	} forEach _unit nearTargets 500;
    } forEach allGroupLeaderUnits;
    
    This is a crude example and somewhat expensive to run, so you would need to tweak how often to sleep, or run a spawn on each group leader.

     


  22. If you need to get the clientID when doing a remoteExecute on the server, the best method is to pass it in as a parameter like so to remoteExec, just before the code is executed on the server:
     

    [clientOwner, {_clientID = _this; ...}] remoteExec ["bis_fnc_call", 2];

    This example is one way, there are other ways of calling remoteExec that don't rely on bis_fnc_call. You would only use bis_fnc_call on anonymous functions/code that is not defined globally for example. This is how I implemented global events and remote handlers.

    If you have multiple admin scripts that you need access to, you could do something like this with IGN_EH: IGN_EH

    if (isDedicated) then
    { 
    	// create an AdminCallRequested event, with parameters ["fncName", clientID, params]
    	SERVER_EVT_AdminCallRequested = [["", 0, [] ], "SERVER_EVT_AdminCallRequested", true] call IGN_fnc_createEvent;
    
    	AdminCallRequestedHandler = ["SERVER_EVT_AdminCallRequested",
    	{
    		params["_fnc", "_clientID", "_params"];
    		// use your method for validating the client has permissions to run
    		// if _fnc is a valid function on server
    
    		call compile format ["_adminFnc = %1", _fnc];	// this will strip the quotes off _fnc, so that "MyFunction" becomes MyFunction 
    		_data = _params call _adminFnc;
    
    		// get some data and return it to remote caller
    		_data remoteExec ["hint", _clientID];
    	}] call IGN_fnc_addEventHandler;
    };
    
    // somewhere locally on a machine...
    ["AdminGetSectors", clientOwner, [someArgs, 0, ...] ] call IGN_fnc_raiseEvent;
    

    This will create a global event that the server owns, with a server side handler. When a client raises the event, the server handler takes the clientID passed in and can do some validation to ensure the proper client has access. It's a somewhat contrived example, as it's not completely secure, since all clients are aware of the event and can register their own handlers or raise it. But this should hopefully give you some ideas for getting what you want done.

    • Like 1
×