Jump to content

soldierXXXX

Member
  • Content Count

    73
  • Joined

  • Last visited

  • Medals

Posts posted by soldierXXXX


  1. Hi. You had a invisible character at the end of the script. To check it, you have to use either some editor that supports showing invisible characters or you can paste it here in the code window and the place where such character is located is usually marked with red dot 🔴 . That sometimes happens when you copy paste code from elsewhere.
    So if you want to use the original code, just delete the invisible character at the end. (...call BIS_fnc_holdActionAdd;🔴)

    To make it more useful, I added some stuff to the code. Depends entirely on you if you want to use them or not.
    I further optimized the condition and added lazy evaluation. That means that condition doesn't have to be evaluated further when the condition would return FALSE at some point and thus could not return TRUE at the end. If you wish to know more about lazy evaluation, read Code Optimization page.
    To further solve the problem with recruiting unmanned vehicles I also added the condition that should check if vehicle has some alive friendly units inside.
    Then ,because vehicles are also possible to recruit, I changed activation code, so instead of single unit you will recruit whole group. That's because previous code only recruited the commander of the vehicle and I think that's not intended behaviour. If you want to change that to previous behaviour, because you need only single units to be recruited instead, simply replace what I did.
    Also I changed the activation distance, if the unit is a man then action will be showed at 3 meters from him, if it's a vehicle, then the action will be showed at 7 meters, because vehicles are usually bigger and at 3 meters the action would not be shown. Priority has also been changed, so the action is now visible immediately after you approach the unit.
    When i tested it I also noticed that if you recruit friendly UAV vehicle, you can totally break its behaviour when you order the AI to dismount 😂, so I added another check and forbid recruiting UAVs as well.

    [player, "Recruit Unit",       
        "\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa",       
        "\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa",       
        "side cursorTarget isEqualTo side _this && {cursorTarget distance _this < ([7,3] select (cursorTarget isKindOf 'Man')) && {group cursorTarget isNotEqualTo group _this && {(cursorTarget isKindOf 'Man' OR {({alive _x} count (crew cursorTarget)) > 0}) AND {!unitIsUAV cursorTarget}}}}", "alive cursorTarget",{},{},{       
        params ["_target", "_caller", "_actionId", "_arguments"];       
        units group cursorTarget join _target;       
    },{},[],2,12,false,true] call BIS_fnc_holdActionAdd;

     

    • Thanks 1

  2. Well, deleteVehicle is a global effect effects_global.gif so that means every change that is run with these commands (like setDamage) will be automatically broadcast across all machines, including JIP clients. When client connects to the server, his machine asks the server for all object states, all publicVariabled variables and possibly other stuff and the server sends the latest informations of the object that is known so you can see it properly in the game. So when you connect to the server after the command is run, for you the object will also be deleted.
    I believe to properly target the trigger you should use thisTrigger as this refers to the condition of the trigger.

    deleteVehicle thisTrigger;

    This will be probably the most efficient way to handle that 🙂.

    • Like 1

  3. Hi, yes you're doing it correctly. As trigger placed in the editor is created on each client and then checks condition locally, activation any player will activate the trigger everywhere and the music selected in trigger effects starts playing. RemoteExec is not needed in this case. RemoteExec is used with commands that have local effect effects_local.gif and you know that condition can be activated only on one machine (like for an example, when you tick server only), but you want to run the command everywhere, or on specific machine. For more information about multiplayer scripting check this page: https://community.bistudio.com/wiki/Multiplayer_Scripting 
    Also, welcome on the forum ! 🙂

     

    Worth to mention. Simple trigger like this might trigger again for JIP players, when they join after trigger has been activated, because for them trigger has not been activated yet. Music will then trigger only for them and other JIP players that joined later. If that is an issue then server only trigger and remote executing the music might be a solution. Also can be fixed by adding a variable to the condition, but then the trigger will be checking for nothing (for JIP players). I had to quickly check how the trigger behaves in that situation, so i noticed that behaviour.

    • Like 1

  4. Hi, if i understand correctly, you want to have randomized mission selection that won't repeat when the script is executed again correct ? There is multiple solutions to this. Depends how you wish the script to behave.
    I prepared two scripts.
    The first one will randomize the missions and then proceed them in order they have been randomized.

    //random unique, with fixed order (order is given by randomizing initial array and then the script proceed the array in this order - meaning, you know which mission is selected next)
    private _availableMissions = missionNamespace getVariable ["soldierXXXX_Available_Missions",(["Mission_1","Mission_2","Mission_3","Mission_4","Mission_5","Mission_6"] call BIS_fnc_arrayShuffle)];
    if (_availableMissions isEqualTo []) exitWith {systemChat "No other missions available";};
    private _selectedMission = _availableMissions select 0;
    _availableMissions deleteAt 0;
    missionNamespace setVariable ["soldierXXXX_Available_Missions",_availableMissions];
    systemChat ("Selected mission: " + _selectedMission);
    systemChat ("Path of the selected mission: " + ("missions\" + _selectedMission + ".sqf"));
    systemChat ("Remaining missions: " + str _availableMissions);
    //execVM ("missions\" + _selectedMission + ".sqf");

    The second one will always select random mission no matter what, so you don't know what's next.

    //completely randomized and unique (no one knows what's next)
    private _availableMissions = missionNamespace getVariable ["soldierXXXX_Available_Missions",["Mission_1","Mission_2","Mission_3","Mission_4","Mission_5","Mission_6"]];
    if (_availableMissions isEqualTo []) exitWith {systemChat "No other missions available";}; 
    private _selectedMission = selectRandom _availableMissions; 
    private _index = _availableMissions find _selectedMission; 
    _availableMissions deleteAt _index; 
    missionNamespace setVariable ["soldierXXXX_Available_Missions",_availableMissions]; 
    systemChat ("Selected mission: " + _selectedMission);
    systemChat ("Path of the selected mission: " + ("missions\" + _selectedMission + ".sqf"));
    systemChat ("Remaining missions: " + str _availableMissions);
    //execVM ("missions\" + _selectedMission + ".sqf");

    I hope this will help you 🙂.


  5. Edit:

    Please ignore this comment. I was wrong.Values i was referring to do not have not be hashable.

     

    To me it doesn't seem like a bug, but rather like unsupported type of the value, because value that you give to the key must be hashable to be properly stored. You can find here all the supported types you can use as value with hashmap. Further reading how hashmap works is here. What might be happening is that hashmaps somehow create strong reference on each other and cannot be released from the memory resulting into memory leak, but I'm not a programmer so i don't know for sure, also we don't have direct access to the engine so we cannot check. I might be wrong on that though. Question is what is the use case of having hashmap inside hashmap? Why cannot be either array of hashmaps or hashmap with key and array value? 


  6. Hi, yes it is possible thanks to procedural textures. You can create text and show all possible variables. Here i created simple script to show you how it can be done.
    To test this, open empty mission, place player, few unarmed enemies and a screen which object variable name is TV. Then copy paste this code to debug console and execute. Everytime you kill someone the screen will be updated with the number of kills. I'm sure you'll manage to implement similar code into whatever you're doing. If not, do not hesitate and ask for further assistance 🙂.

    //run this code in debug console-script serves as example how to make variable show as texture
    Kills = 0;//variable that is updated
    
    //function that sets text on the screen as texture
    soldierXXXX_fnc_setKillsOnScreen = {
    scriptName "soldierXXXX_fnc_setKillsOnScreen";
    params [["_screen",objNull,[objNull]]];
    private _text = format ["Total kills:%1 units",Kills];
    private _texture = format ['#(rgb,512,512,3)text(0,0,"Caveat",0.08,"#0000007f","#FF0000",%1)',_text];
    _screen setObjectTexture [0,_texture];
    };
    
    //Eventhandler that will update the screen everytime someone is killed
    addMissionEventHandler ["EntityKilled", { 
     params ["_unit", "_killer", "_instigator", "_useEffects"];
    Kills = Kills + 1;
    [TV] call soldierXXXX_fnc_setKillsOnScreen; 
    }];
    • Thanks 1

  7. Hi, if you want to restore last map position you can do it like this. This code will automatically update map position and when you open the map again, map will be set to latest position. You can of course change the variable names (MapCurrentPos and MapCurrentZoom) to whatever you like. I hope this will help you 🙂.

    addMissionEventHandler ["Map", { 
     params ["_mapIsOpened", "_mapIsForced"];
    if (_mapIsOpened) then {
     private _map = ((uiNamespace getVariable "RscDiary") displayCtrl 51);
    mapAnimAdd [0,missionNamespace getVariable ["MapCurrentZoom",ctrlMapScale _map],missionNamespace getVariable ["MapCurrentPos",_map ctrlMapScreenToWorld [0.5, 0.5]]];
    mapAnimCommit;
    _map ctrlAddEventhandler ["Draw",{
    params ["_map"];
    MapCurrentPos = _map ctrlMapScreenToWorld [0.5, 0.5];
    MapCurrentZoom = ctrlMapScale _map;
    hintSilent format ["%1\nzoom:%2",MapCurrentPos,MapCurrentZoom];
    }];
    };
    }];
    • Like 2

  8. Hi, when you create any air vehicle, the engine thinks the vehicle is on the ground or at least that's how i understand it. You can fix that by changing createVehicle syntax and set it as "FLY" under special argument. Other method would be to use commands (setPos then move or addWaypoint) so the AI realizes it's in the air, but it's not necessary here. setVehicleTIPars is to help target vehicle immediately. I also added setVehicleAmmo to hide rockets that were on the drone, but sadly you can't retexture the rotor blade or hide collision lights, but hey, it's better than nothing 😄.

    this addEventHandler ["Fired",    
    {    
     params ["_unit","_weapon","_muzzle","_mode","_ammo","_magazine","_projectile","_vehicle"];  
     _drone = createVehicle ["O_T_UAV_04_CAS_F", [0,0,1000], [], 0, "FLY"];
    _drone setObjectTextureGlobal [0, ""];
    createVehicleCrew _drone; 
    _drone setVehicleTIPars [1,1,1];
    _drone engineOn TRUE;
    _drone setVehicleAmmo 0;
    _drone attachTo [_projectile,[0,0,0]];
    nul = [_drone, _projectile] spawn {   
    params ["_drone","_projectile"];
    waitUntil {!alive _drone};   
    _bomb = "SatchelCharge_Remote_Ammo_Scripted" createVehicle getPos _projectile;   
    _bomb setDamage 1;  
    deleteVehicle _projectile;    
    deleteVehicle _drone;    
    }; 
    }];
    • Thanks 1

  9. I don't think this is relevant. No Face is cfgIdentity config error with identity that moduleHQ function automatically assigns to logic/unit because in config is face = ""; nothing serious.
    Unable to get word, again it's config error somewhere in RadioProtocolGRE. You can't do anything about it.
    what might be relevant is 

    16:55:13 Error in expression <};
    
    private ["_text"];
    
    {
        _text = _txt param [_forEachIndex,"",["",[]]];
        if (t>
    16:55:13   Error position: <param [_forEachIndex,"",["",[]]];
        if (t>
    16:55:13   Error Type Object, expected Array,String
    16:55:13 File /temp/bin/A3/Functions_F/Tasks/fn_setTask.sqf..., line 210

    that points to wrong syntax used with BIS_fnc_setTask.
    Not sure if you put anything else between removeAction and sideChat. If there is other code between that might fail silently (no error message) it would stop the code and that would be the reason you might not see sideChat appearing. You might try to switch 

    fuelsmuggler sidechat "You're late!";fuelsmuggler removeAction talkactionsmglr;

    and see if the action get's removed. Also you can try to insert debuging hint after each command to see how far the code reaches before it fails. That's the only thing that got on my mind that would cause this behavior 😄 If not then i have to say, i don't know 😄


  10. Hi, i put together a little code that should be able to do it. Tell if you need further assistance 🙂.
     

    /*
    Syntax:
    [
    _pos1, <Array position>
    _pos2, <Array position>
    _precision <number range 0.001 to 0.5>(optional-default 0.05)
    ] call soldierXXXX_fnc_checkWater;
    
    example:
    _cursorPos = screenToWorld [0.5,0.5];
    [position player,_cursorPos] call soldierXXXX_fnc_checkWater;
    */
    
    soldierXXXX_fnc_checkWater = {
    scriptName "soldierXXXX_fnc_checkWater";
    params ["_pos1","_pos2",["_precision",0.05]];
    _isWater = FALSE;
    for "_i" from 0 to 1 step _precision do {
    _curPos = vectorLinearConversion [0, 1, _i, _pos1, _pos2, true];
    if (surfaceIsWater _curPos) exitWith {_isWater = TRUE;};
    };
    _isWater
    };

     

    • Thanks 2

  11. 27 minutes ago, Rok Stuhne said:

    (the error is related to the object the npc is supposed to look at, it's not in this map)

    I overlooked that 😄 Corrected.
    I still can't see what might cause this not to work. I would probably require full code and possibly structure of the mission folder to fully understand, but i don't think anything should be able to do this. The second picture is different problem.


  12. [] spawn {
    if !("ItemRadio" in assignedItems player) then {player linkItem "ItemRadio";};
    fuelsmugglertruck ="O_T_Truck_02_fuel_F" createVehicle position player; 
    sleep 0.1; 
    fuelsmugglertruck setDir 0; 
    fuelsmugglertruck setVehicleLock "LOCKED"; 
    fuelsmugglertruck setFuel 0; 
    fuelsmugglers = creategroup civilian; 
    sleep 0.2;
    fuelsmuggler = fuelsmugglers createUnit ["C_Driver_4_F", position player, [], 0, "NONE"]; 
    fuelsmuggler disableAI "path";
    removeAllWeapons fuelsmuggler; 
    fuelsmuggler forceAddUniform "U_O_T_Officer_F"; 
    fuelsmuggler unassignItem "O_NVGoggles_ghex_F";  
    fuelsmuggler removeItem "O_NVGoggles_ghex_F";   
    fuelsmuggler unassignItem "V_HarnessOGL_ghex_F";  
    fuelsmuggler removeItem "V_HarnessOGL_ghex_F";
    fuelsmuggler addHeadgear "vn_o_helmet_nva_03";
    [fuelsmuggler] call BIS_fnc_moduleHQ;
    talkactionsmglr = fuelsmuggler addAction ["Talk to the smuggler", {fuelsmuggler removeAction talkactionsmglr;fuelsmuggler sidechat "You're late!";}, [], 6, true, true, "", "(fuelsmuggler distance player)<5"];
    };

    Last try. Can you start the game without any mod, open virtual reality map, place any civilian as player and execute this code from debug console to see if it works the way you intended ? Because if not, then i'm pretty sure it's not the code that is causing this.


  13. HQ module can't work with synchronized objects. The code is not adjusted for it. What module does is simply creates the HQ entity on itself. If you want to set unit as HQ entity you need to add line [fuelsmuggler] call BIS_fnc_moduleHQ; to your code. This way there shouldn't be HQ module present in the mission (would be useless). Also you would have to change HQ4 sidechat "You're late!" to fuelsmuggler sidechat "You're late!", but i don't see any benefit of setting unit as HQ entity.


  14. Hi, problem with copying arrays is that by writing _grid1 = _grid; you just referencing to the same array. When engine sees the variable it asks what is that variable ? And searches where it is defined. When engine finds the definition and sees it's another variable, then searches to where that other variable is defined and when he finally reaches the last variable that actually contains some data, he assigns the data to the variable you using. That means it will also refer to it as if you made changes to main array.
    If you want to actually copy the array you should write it as _grid1 = +_grid; This way the engine knows that you want to create copy of the variable that can be changed without changing the other array. You can use isEqualRef to compare if variables are dependent on each other or not. On the page are also examples how the arrays behave.

    • Like 1

  15. 14 hours ago, Harzach said:

    *edit* - Opened not working, for some reason. No time to figure it out, maybe something on my end.

    Just to clarify the difference between BIS_fnc_arsenal_campos_0 and BIS_fnc_arsenal_campos
    BIS_fnc_arsenal_campos_0 
    is initial position variable that is loaded when arsenal is created so if you want to use this, this should be declared before arsenal is opened just as in your solution. If it's not declared before, arsenal will use default camera position. This variable is also set again when you exit the arsenal so next time you open it it's on the same position you left it, but with use of "arsenalClosed" the variable is updated on that position instead. That's why "arsenalOpened" won't work on this one because when Opened is called, camera is already set. Variable runs in missionNamespace.

    BIS_fnc_arsenal_campos on the other hand is variable of latest camera position, with which all positioning scripts inside arsenal function works. When arsenal is opened this variable is set based on BIS_fnc_arsenal_campos_0 position first but then exists on it's own until you exit the arsenal. Variable runs in uiNamespace. "arsenalOpened" will work with this variable correctly, because event is called after all variables are set and scripts used in arsenal function will update it's position based on this variable.

    That's why your solution works with "arsenalClosed" and mine works with "arsenalOpened". 🙂 

    • Like 1
    • Thanks 1

  16. Hi, solution for this problem is update variable of arsenal camera position based on arsenal system.
    here is simple code to manually set the camera on fixed position:

    //easy solution:
    [missionNamespace, "arsenalOpened", {
    params ["_display", "_toggleSpace"];
    uiNamespace setVariable ["BIS_fnc_arsenal_campos",[8,90,((30 max -89) min 89),[0,0,0.85]]];//fixed position
    }] call BIS_fnc_addScriptedEventHandler;

    array is in format [distance of camera, horizontal direction of camera(from -359 to 359),vertical direction of camera (from -89 to 89),target position array (probably modelspace center of object that camera should follow)].

    A bit advanced detection if object is in front of camera (not terrain) and if yes then camera will turn by specified number of degrees on the horizontal axis until camera and target object have clear line between them. Be aware it's just a example code put quickly together and would require tweaking, it's not ideal for all situation so first solution will be probably better.
    I hope it helps 🙂 
     

    Spoiler
    
    soldierXXXX_fnc_Arsenal_SetCamSafePos = {
    scriptName "soldierXXXX_fnc_Arsenal_SetCamSafePos";
    with uinamespace do {
    private _cam = uinamespace getvariable ["BIS_fnc_arsenal_cam", objnull];
    //if (!isNil {uiNamespace getVariable "BIS_fnc_arsenal_campos";}) exitWith {hint "uinamespace"};
    private _type = BIS_fnc_arsenal_type;//uiNamespace getVariable "BIS_fnc_arsenal_type";
    private _camPos = BIS_fnc_arsenal_campos;//uiNamespace getVariable "BIS_fnc_arsenal_campos";
    private _camDefaultPos = [[10,-45,15,[0,0,-1]], [5,0,0,[0,0,0.85]]] select (_type == 0);//arsenal or garage
    _camPos params ["_dis", "_dirH", "_dirV", "_targetPos"];
    //turnCamera by sphere
    private _turnStep = 45;
    private _endTurn = 180;
    private _remainder = _endTurn%_turnStep;
    _endTurn = _endTurn - _remainder;
    for "_i" from 0 to _endTurn step _turnStep do {
    private _dirH = (_dirH + _turnStep)%360;
    private _center = missionnamespace getVariable ["BIS_fnc_arsenal_center", player];
    private _cam = uinamespace getvariable ["BIS_fnc_arsenal_cam", objnull];
    //systemChat str (getPosASLVisual _cam);
    private _viewBlocked = lineIntersects [getPosASLVisual _cam,getPosASLVisual _center,_cam,_center];
    if (!_viewBlocked) exitwith {};
    (uiNamespace getVariable "BIS_fnc_arsenal_campos") set [1,_dirH];
    sleep 0.1;//to see that it actually turns-remove for instant change
    };
    };
    /*
    _debugEH = addMissionEventHandler ["EachFrame",{
        uinamespace getVariable "BIS_fnc_arsenal_campos" params ["_dis", "_dirH", "_dirV", "_targetPos"];
    	private _mousePos = uinamespace getVariable "BIS_fnc_arsenal_mouse";
    	systemChat format ["distance:%1 dirH:%2 dirV:%3 target pos:%4 MousePos:%5",_dis,_dirH,_dirV,_targetPos,_mousePos];
    }];
    */
    waitUntil {isNil {uinamespace getVariable "BIS_fnc_arsenal_display"}};
    //removeMissionEventHandler ["EachFrame",_debugEH];
    };
    
    [missionNamespace, "arsenalOpened", {
    params ["_display", "_toggleSpace"];
    [] spawn soldierXXXX_fnc_Arsenal_SetCamSafePos; // hint message to the player when he opens the Arsenal
    }] call BIS_fnc_addScriptedEventHandler;

     

     

    • Like 1

  17. Code is alright, but may i ask you how exactly you set up HQ entities ? Pictures/Video would be ideal so we can see where might be the problem. if you do it via module, just assign HQ4 variable to module itself and it should work. If you want to have unit as HQ you can put in it's init

    [this] call BIS_fnc_moduleHQ;

    that should also work. Only one unit/module can be set per side. What unit/module is assigned as HQ entity you can check with

    missionnamespace getvariable ["BIS_fnc_moduleHQ_HQs",[objnull,objnull,objnull,objnull]];

    or for specific side only 

    [civilian] call BIS_fnc_moduleHQ;

    Basically when you read through the code you'll see that only one object can be set as HQ entity, that means when you place two HQ entity modules or assign more than 1 unit per side only one will be used as HQ entity.


  18. For question about setting names, yes it's possible. Here is the code i put together. But be aware, naming the group by its type usually is long and in high command you will see only part of it. Also every PC can run Arma in different language so this might lead to people on the server not understanding the groupID name set by the PC that issued the command (these codes are just simple examples how to do it on your PC). This is probably the reason why they are named universally like Alpha, Bravo...
    To set it on every client correctly would require to run part of the script clientside and passing them variables what you spawned so they know what to look for. Also you need to pay attention if the command is global GE or local LE (in this example it should set the name globally). But i'm not really right guy for multiplayer scripting 🙂.

    For Vehicle:

    _vehicle = createVehicle ["B_MBT_01_cannon_F", getMarkerPos "marker_5", [], 0, "NONE"];
    _config = configOf _vehicle;
    _vehicleName = getText (_config >> "displayName");
    _vehicleGroup = createVehicleCrew _vehicle; 
    _originalName = str _vehicleGroup splitString " "; 
    _sufix = _originalName select 2; 
    _newName = _vehicleName + " " + _sufix; 
    _vehicleGroup setGroupIdGlobal [_newName];


    For Group:

    _config = (configfile >> "CfgGroups" >> "West" >> "BLU_F" >> "Infantry" >> "BUS_InfSquad");
    _InfGroup = [getMarkerPos "marker_4", WEST, _config] call BIS_fnc_spawnGroup; 
    _originalName = str _InfGroup splitString " "; 
    _sufix = _originalName select 2; 
    _newName = getText (_config >> "name") + " " + _sufix; 
    _InfGroup setGroupIdGlobal [_newName];


    For the other question. You create units in the editor, set them as playable and ,if i understand correctly, in description.ext declare disabledAI = 1; I guess you can do it also from the 3den multiplayer settings. Biki says you need to have respawn enabled if you want players to be able to JIP. Adding respawn = 3; should be fine. Be aware that this can lead to some problems like for example if you have playable unit synchronized with HC module and player chooses to play other role, errors might appear. If there are other solutions for this problem i'd also like to hear them, because i'm focused on singleplayer missions/scripts and how multiplayer environment works i know only in theory 😅.

    • Like 2
×