Jump to content


  • Content Count

  • Joined

  • Last visited

  • Medals

Everything posted by jwllorens

  1. I might be able to help. I am new to ArmA scripting but I have a functional cerebrum and I am working on an ArmA project of my own. If you could explain some aspect of your question, I think we could both benefit. What does "BIS_fnc_moduleSimulationManager" do and more importantly, what are you "expecting" it to do? Also, is this intended for multiplayer? It seems like you want to disable simulation on some distant units or objects, but enable simulation on them if the player is in a mortar or if any projectiles fired by a mortar vehicle occupied by the player still exist. This would make sense if your mission has a lot of units and you are trying to limit overhead by only simulating the ones within a certain range of the player. However, since artillery has an enormous range, exceptions would need to be made for this. In multiplayer, however, I see nothing wrong with leaving simulation disabled on distant units unless another player is near the units that are being targeted by the artillery, though this could be circumvented as well if needed.
  2. jwllorens

    detect allowDamage state

    Interesting. So allowDamage does create a variable (or alter a pre-existing one) in the object namespace of the object it was called on?
  3. jwllorens

    detect allowDamage state

    Try adapting grumpyOldMan's code. Note that this code will have some pretty decent overhead if you loop it, so you may want to call it only on suspicious players. You could even implement a voting system whereby the script runs and checks allowDamage = false on a player that has been "voted" as a suspected cheater by someone else. GrumpyOldMan's script basically does the following. For each player, it does this: Creates a bomb in the sky at map position 0,0, hides the bomb, moves it to eye level of the player unit, and then detonates it, and then checks to see if the unit is alive. If not, the player is a cheater. Yes, this works, but it is obviously a joke solution because all players will explode regardless of whether they are cheating or not, and only the cheaters will survive. However, this may provide some insight into how to detect the state of allowDamage, since hit event handlers do not fire. You could apply a similar concept by 1: Obtaining the player's current damage state. https://community.bistudio.com/wiki/getAllHitPointsDamage 2: Then, determine if the player is about to die (or not, but risk killing them with the script if they are already hurt. If they are close to death and will die from the test and this condition alone prevents the test from being run, then cheaters can circumvent it by setting their damage state to almost dead and THEN using allowDamage = false;. To prevent this, perhaps tally the votes to check if the player is a cheater and if they are numerous, override this check. The idea is that if you run this test on a player that is close to death, they could be innocent and you could kill them and annoy the player which is always bad. By requiring more than 1 vote to run the test ONLY IF the player is damaged enough to die from the test, that means multiple people agree that they are likely to be cheating, in which case, the risk of the player being innocent will be lowered while the consequences of them being innocent and running the cheater allowDamage test, killing them, remains the same. Striking a balance here will be hard. Perhaps the test can be run with only one vote if the player would not die to the test, but require 2 or more votes if the player would.) https://community.bistudio.com/wiki/damage 3: Spawning a 9mm bullet. https://community.bistudio.com/wiki/createVehicle 4: Move the bullet BEHIND the player's chest. May be complicated and involve a great deal of testing. You will have to use some hardcoded and tested values along with some 3D geometry skills to place the bullet behind the back of the player regardless of the player's stace. https://community.bistudio.com/wiki/setPosASL https://community.bistudio.com/wiki/eyePos https://community.bistudio.com/wiki/stance https://community.bistudio.com/wiki/Math_Commands 5: Give the bullet a velocity in the direction of the player's chest. https://community.bistudio.com/wiki/setVelocity https://community.bistudio.com/wiki/BIS_fnc_dirTo https://community.bistudio.com/wiki/vectorMultiply 6: Checking the player's damage state again and comparing it to the original. https://community.bistudio.com/wiki/damage 7: Restore the player's health if they were damaged or flag them as a cheater if they were not. Careful to restore the exact damage state to each hit part. https://community.bistudio.com/wiki/setHitPointDamage
  4. When creating triggers through createTrigger command, there is a parameter to create the trigger locally or globally. I have a few questions about this. 1: Is a "globally" created trigger using createTrigger simply broadcast over the network so that all machines create a trigger with the same parameters? 2: Is a global trigger is therefore several different triggers that are each created with the same starting parameters but otherwise "local" to their own machine and not synced? 3: If I run a script on one machine setting the statements or other aspects of this trigger, including the position of the trigger, will these updates to the trigger be broadcast to other machines and update the instances of that trigger on their machine? 4: Can a local trigger still tell if non-local units are inside of it? 5: Will the code in the condition, activation, and deactivation fields of a global trigger be executed on every machine if the trigger is activated only on one machine? (assuming the activation condition was somehow different for that one machine due to a local global variable or something). 6: What is the point of a global trigger? If the statements are only run locally, why not save every machine the hassle of checking the condition every 0.5sec and just define the trigger locally on the server. Then, in the statements, just use remoteExec to execute a predefined function on all machines if needed.
  5. jwllorens

    Variables and IF statements

    As previous posters have said, be careful about the following: "=" is an assignment operator. It does not compare anything, it assigns data to a variable. "==" compares two variables to see if they are equal. You would use "==" in something like an "if" statement or some other conditional statement, wheras "=" is pretty much only used to assign data to a variable. Unlike some other languages, in ArmA you need to put "_variable = _variable + 1;" if you want to increment a variable. "_variable + 1;" returns the value of _variable + 1, but if you do not assign it to anything with the "=" operator then that bit of code ("_variable + 1;") essentially does nothing besides calculate the value and then discard it,
  6. Alright I polished it up a bit and fixed some bugs. I tested it in several vehicles. It works AMAZINGLY WELL in gunships. Instead of guessing where the rounds will fall (especially if you have an AI pilot that likes to fly low and fast over the targets) you simply aim where you want them to hit. This script will simply subtract out the velocity of the vehicle from the initial velocity of each projectile, meaning it travels with a muzzle velocity as if the vehicle was stationary when it was fired. The bullets still travel completely normal, and it looks perfectly believable. The only difference is that the bullets land wherever the crosshair was pointed when it was fired. Is it realistic? No, because in real life bullets inherit the velocity of the firing platform. But it still looks very believable and achieves the same effect as an imaginary advanced ballistic computer using an accelerometer to adjust the crosshairs on the fly. I just started this scripting stuff not too long ago so I had to try my hand at making this function a simple toggle on/off. I think I did alright with the use of setVariable to store the index of the event handler. You can call the function from different scripts on the same object and it will always keep track of whether it has already been enabled or not and be able to disable it even if it was enabled earlier somewhere else. I do have a question about event handlers and object locality. Will this event handler fire on all computers? My understanding is that in multiplayer, bullets and shells are not updated across the network, instead they are just "duplicated" by creating a different bullet on every PC and giving them the same starting position and velocity. As such, I want to make sure the event handler in this script is firing on all PCs so that the gunner isn't getting direct hits while the target is getting killed by shells that he is seeing land miles away.
  7. https://community.bistudio.com/wiki/getUnitLoadout https://community.bistudio.com/wiki/setUnitLoadout Don't worry, I made a complicated script to get and set unit loadouts before I realized those two commands existed too. Use those commands. They do everything you want, including adding half empty magazines and stuff with the right bullet count. So these two commands are perfect for something like a revive script where the unit is actually completely killed and not put into an incapacitated state. If you are trying to load a hardcoded inventory to put on an AI, then these commands may not be the best idea. The array format they use isn't final, so a hardcoding an array of items and calling setUnitLoadout on it might not work in the future if BIS changes the way the commands work. If you want to look at how I did the script version before realizing we had those commands, take a look at this: comment "------------------------------------------------------------------------------------------------------------- Function to spawn an infantry unit. Can spawn WEST or EAST unit. Uses loadout templates to equip the soldier with a custom loadout. Also sets the AI skills for the unit. Arguments: group, class, position, kitUpgrade, skillUpgrade group = group to add the unit to. class = string name for class loadout definition file. position = position array to spawn the unit at. kitUpgrade = array defining whether to upgrade weapons and night vision. [bool, bool] skillUpgrade = a number to increase all base skills by Return: unit unit = the unit that was created. ---------------------------------------------------------------------------------------------------------------------"; params [ ["_grp", grpNull, [grpNull], 1], ["_cls", "EMPTY", [""], 1], ["_pos", [0,0,0], [[]], 3], ["_kitUp", [false,false], [[]], 2], ["_sklUp", 0, [0], 1] ]; comment "------------------------------------------------------------------------------------------------------------- Retrieve an array defined in AILoadouts\SoldierClassName.sqf. This array contains the base soldier classname, an array of custom equipment, and an array of individual skills. ---------------------------------------------------------------------------------------------------------------------"; _info = [(side _grp),(_kitUp select 0),(_kitUp select 1)] call (compile loadFile (format ["AILoadouts\%1.sqf", (toLower _cls)])); _ldt = _info select 1; comment "------------------------------------------------------------------------------------------------------------- Create the unit, turn off damage. Sleep ensures that remainder of script runs after default engine randomization has completed to prevent conflicts or overriding intended behavior (mostly ensures that headgear is spawned properly). ---------------------------------------------------------------------------------------------------------------------"; _unit = _grp createUnit [(_info select 0),_pos, [], 0, "CAN_COLLIDE"]; _unit setVariable ["BIS_enableRandomization", false]; sleep 0.05; comment "------------------------------------------------------------------------------------------------------------- Remove all default equipment and items from the unit. ---------------------------------------------------------------------------------------------------------------------"; removeAllWeapons _unit; removeAllItems _unit; removeAllAssignedItems _unit; removeUniform _unit; removeVest _unit; removeBackpack _unit; removeHeadgear _unit; removeGoggles _unit; comment "------------------------------------------------------------------------------------------------------------- Add equipment and items from _classInfo. ---------------------------------------------------------------------------------------------------------------------"; if ((_ldt select 0)!= "EMPTY") then {_unit addHeadgear (_ldt select 0);}; if ((_ldt select 1)!= "EMPTY") then {_unit addGoggles (_ldt select 1);}; if ((_ldt select 2)!= "EMPTY") then {_unit forceAddUniform (_ldt select 2);}; {for "_i" from 1 to (_x select 1) do { if ((_x select 0)!= "EMPTY") then { _unit addItemToUniform (_x select 0);}; }; true } count (_ldt select 3); if ((_ldt select 4)!= "EMPTY") then {_unit addVest (_ldt select 4);}; {for "_i" from 1 to (_x select 1) do { if ((_x select 0)!= "EMPTY") then { _unit addItemToVest (_x select 0);}; }; true } count (_ldt select 5); if ((_ldt select 6)!= "EMPTY") then {_unit addBackpack (_ldt select 6);}; {for "_i" from 1 to (_x select 1) do { if ((_x select 0)!= "EMPTY") then { _unit addItemToBackpack (_x select 0);}; }; true } count (_ldt select 7); {if (_x != "EMPTY") then { _unit addWeapon _x;}; true } count ([_ldt select 8] + (_ldt select 10)); {if (_x != "EMPTY") then { _unit addPrimaryWeaponItem _x;}; true } count (_ldt select 9); {if (_x != "EMPTY") then { _unit linkItem _x;}; true } count (_ldt select 11); comment "------------------------------------------------------------------------------------------------------------- Set individual skills of unit. Skills are retrieved from _info, then incremented by _sklUp. ---------------------------------------------------------------------------------------------------------------------"; {_unit setSkill [_x, (((_info select 2) select _forEachIndex) +_sklUp)];} forEach ["aimingAccuracy", "aimingShake", "aimingSpeed", "commanding", "courage", "reloadSpeed", "spotDistance", "spotTime"]; comment "------------------------------------------------------------------------------------------------------------- Add a killed event handler to unit for cleanup, turn damage back on now that setup is complete, and return the unit object from the function. ---------------------------------------------------------------------------------------------------------------------"; _unit addEventHandler ["killed", {_this spawn JFNC_Cleanup;}]; _unit allowDamage true; _unit Then I have a folder called AILoadouts, and inside I have some sqf files named "rifleman.sqf" "grenadier.sqf" ect. params [["_side", west, [west], 1], ["_wUp", false, [true], 1], ["_nv", false, [true], 1]]; _info = switch (_side) do { case (west): { _baseSoldier = "B_T_Soldier_F"; _helmet = selectRandom ["H_HelmetB_light"]; _facewear = selectRandom ["EMPTY","G_Lowprofile","G_Aviator","G_Sport_Blackred"]; _uniform = selectRandom ["U_B_T_Soldier_F"]; _uniformItems = ([[["EMPTY",0]],[["EMPTY",0]]] select _wUp) + [["FirstAidKit", 1], ["16Rnd_9x21_Mag",3]]; _vest = selectRandom ["V_PlateCarrier1_rgr"]; _vestItems = ([[["30Rnd_556x45_Stanag_red",8]],[["30Rnd_65x39_caseless_mag",8]]] select _wUp) + [["HandGrenade", 2], ["SmokeShell", 2]]; _backpack = selectRandom ["EMPTY"]; _backpackItems = ([[["EMPTY",0]],[["EMPTY",0]]] select _wUp) + [["EMPTY",0]]; _rifle = ["arifle_SPAR_01_khk_F","arifle_MX_khk_F"] select _wUp; _attachments = ([["acc_flashlight"],["acc_pointer_IR"]] select _nv) + ["optic_ERCO_khk_F"]; _secondaryWeapons = ["hgun_P07_khk_F"]; _gear = [["ItemMap", "ItemCompass", "ItemWatch", "ItemRadio"], ["ItemMap", "ItemCompass", "ItemWatch", "ItemRadio", "NVGoggles_INDEP"]] select _nv; [_baseSoldier,[_helmet, _facewear, _uniform, _uniformItems, _vest, _vestItems, _backpack, _backpackItems, _rifle, _attachments, _secondaryWeapons, _gear]]; }; case (east): { _baseSoldier = "O_T_Soldier_F"; _helmet = selectRandom ["H_HelmetSpecO_ghex_F"]; _facewear = selectRandom ["G_Balaclava_oli"]; _uniform = selectRandom ["U_O_T_Soldier_F"]; _uniformItems = ([[["EMPTY",0]],[["EMPTY",0]]] select _wUp) + [["FirstAidKit", 1], ["16Rnd_9x21_Mag",3]]; _vest = selectRandom ["V_HarnessO_ghex_F"]; _vestItems = ([[["30Rnd_580x42_Mag_F",8]],[["30Rnd_65x39_caseless_green",8]]] select _wUp) + [["HandGrenade", 2], ["SmokeShell", 2]]; _backpack = selectRandom ["EMPTY"]; _backpackItems = ([[["EMPTY",0]],[["EMPTY",0]]] select _wUp) + [["EMPTY",0]]; _rifle = ["arifle_CTAR_blk_F","arifle_Katiba_F"] select _wUp; _attachments = ([["acc_flashlight"],["acc_pointer_IR"]] select _nv) + ["optic_Arco_blk_F"]; _secondaryWeapons = ["hgun_Rook40_F"]; _gear = [["ItemMap", "ItemCompass", "ItemWatch", "ItemRadio"], ["ItemMap", "ItemCompass", "ItemWatch", "ItemRadio", "O_NVGoggles_ghex_F"]] select _nv; [_baseSoldier,[_helmet, _facewear, _uniform, _uniformItems, _vest, _vestItems, _backpack, _backpackItems, _rifle, _attachments, _secondaryWeapons, _gear]]; }; }; comment "------------------------------------------------------------------------------------------------------------- array format: [aimingAccuracy, aimingShake, aimingSpeed, commanding, courage, reloadSpeed, spotDistance, spotTime] ---------------------------------------------------------------------------------------------------------------------"; _skill = [0.55,0.55,0.55,0.5,0.5,0.5,0.5,0.5]; _info pushBack _skill; _info
  8. Does the BIS revive work? I am trying to add it through the EDEN editor to my multiplayer mission, but it doesn't seem to be working. Every time my player dies I just go to the respawn screen. However, a little medical cross appears right under the stamina bar when I die, which seems to briefly indicate an incapacitated state. Here is what I have tried: -ticking/unticking the checkbox for "revive enabled" on the playable unit. -using the "Revive" respawn template in description.ext. -trying every combination of settings in the revive options in the multiplayer attributes pane of the EDEN editor. -enabling/disabling respawn on custom position both in description.ext and in the EDEN editor. Is it possible that I have to actually have more than one player on my team to enter the incapacitated state?
  9. jwllorens

    BIS Revive working?

    Hmm, interesting. You don't have anything in there that I didn't try. According to the wiki, the revive respawn template is deprecated which seems to be why I get an error that the template doesn't exist. I haven't actually tested my mission in a dedicated server environment yet but I'll play around with it.
  10. jwllorens

    BIS Revive working?

    Would you mind posting what you have in description.ext? Thanks.
  11. I've found it somewhat irritating how difficult it is in ArmA to get a vehicle turret, or an infantry for that matter, to aim a certain weapon at a position and fire. Does anyone have a working function for this? All I want is to make the vehicle turret aim at a position such that it will compensate for the ballistics of the projectile fired by a specific muzzle and for the velocity of the vehicle itself. I want to be able to call this function and have it override any behavior the AI in the turret is currently executing, such as targeting an enemy or seeking cover, ect. Even getting the AI to aim reliably at enemies is challenging, and seems downright impossible if you want them to aim at a noncombatant or three-dimensional world position. If not a function to do this, is there a function that will return ballistic information contained within the config file for a weapon/muzzle/projectile, and a function to aim a turret in an exact direction corresponding to a vector? I could dust off my engineering dynamics books and try my hand as some vector math to do all the work in between, to find the unit vector direction to aim the turret given config file ballistics information and a position, which could be fun.
  12. That works for the 120mm cannon, but doesn't seem to work for the LMG. It also doesn't seem to work for other smaller caliber guns such as the 40mm on the Marshall. The gunner doesn't seem to want to fire unless doWatch is called on an enemy. Also, I can't tell if doWatch is adjusting the aim for distance or tank movement, it doesn't seem to be. I'm also having trouble getting the doWatch to work if the turret is already targetting something and is in combat. I've tried setCombatMode, setBehaviour, disableAI. Certain combinations fix this problem, but then they render the "fire" command useless. fireAtTarget is more reliable, but the aim of the turret is always way off since fireAtTarget doesn't actually force the unit to aim and just fires the weapon wherever the muzzle is pointed.
  13. Ok, now it works as intended. fn_setRoleVar.sqf disableSerialization; params [ ["_unit", objNull, [objNull], 1] ]; _rList = uiNamespace getVariable (["BIS_RscRespawnControlsMap_ctrlRoleList", "BIS_RscRespawnControlsSpectate_ctrlRoleList"] select (uiNamespace getVariable ["BIS_RscRespawnControlsSpectate_shown", false])); _rName = _rList lbText (lbCurSel _rList); _unit setVariable ["JWL_respawnRole", (toUpper _rName), true]; true onPlayerRespawn.sqf params [ ["_newUnit", objNull, [objNull], 1], ["_oldUnit", objNull, [objNull], 1] ]; _newUnit spawn JWL_fnc_setRoleVar; init.sqf (just for testing purposes) null = [] spawn { while {true} do { sleep 1; hintSilent (player getVariable ["RespawnRole", "NOT SET"]); }; }; Will spam "NOT SET" until you select a loadout and spawn. Afterwards, will spam the role you selected. "MEDIC," "AUTORIFLEMAN," "GRENADIER" ect. If your respawn with a new role, it will spam the new role name instead. Works great because you can call player getVariable "RespawnRole" and it returns the role of the player. Nice! Awesome! Thanks so much for your help. This will allow me to use the BIS respawn system which I think is very clean and useable and do some cool stuff on top of it, like making sure pilots are the only ones that can fly planes and medics get the proper medic bonus for reviving.
  14. On the wiki it says that the parameters for onPlayerRespawn.sqf are [<newUnit>, <oldUnit>, <respawn>, <respawnDelay>]. So parameter #0 should be the new unit and not the old unit, correct? Meaning that it shouldn't be objNull at the start, it should be the new unit that is created when the player respawns the first time. EDIT: Ok, I found the problem, I think, but something isn't adding up. The variable wasn't being assigned to the unit before I was calling hint (getvariable "whatever"); Since I spawned a new thread, hint was getting executed before that thread had completed execution and therefore before setVariable was being called on the unit. Adding a short sleep into onPlayerRespawn.sqf fixed the problem. However, I found something interesting that seems to not support this assumption, despite this fix working. What is interesting is also that it didn't work on the first respawn at the start, but worked on every subsequent respawn. If the order of execution was the problem, then I would expect it to fail every time if I was referencing the newly created unit every time. Changing onPlayerRespawn.sqf to: params [ ["_newUnit", objNull, [objNull], 1], ["_oldUnit", objNull, [objNull], 1] ]; _newUnit spawn JWL_fnc_setRoleVar; waitUntil {(_newUnit getVariable ["JWL_respawnRole", "NOT SET"]) != "NOT SET"}; hint str [_oldUnit, _newUnit, (_newUnit getVariable ["JWL_respawnRole", "NOT SET"])]; yields interesting results. "Rifleman" is always returned even at the start. However, _newUnit and _oldUnit appear to ALWAYS be the same thing. Even at the start of the game after the first respawn. I will have to play with this and add in another role, and see if it always accurately returns the correct role. EDIT 2: Ok. So I got it working. You were right about _newUnit and _oldUnit, they seem to be flipped compared to what is on the wiki. Maybe that should be changed. However, despite the script working, there are still some strange questions. Using the first parameter, assuming it is the new unit, I get the correct result on the FIRST spawn in the game, but every subsequent spawn shows the role selected from my LAST life and not the current one, suggesting that the first parameter is the old unit and not the new (current) one. However, using the first parameter should mean the function is assigning a variable to objNull on the first spawn of the game, so why is it working when I call getVariable on it? It also doesn't explain why the waitUntil command fixes the problem of not retrieving a variable on the first spawn, when this problem should be encountered on every subsequent spawn if it is an execution order problem. I would assume that the new unit would NEVER have the variable assigned to it before calling getVariable if this were the problem, on any respawn.
  15. Ok, a quick update. Changing that last line in onPlayerRespawn.sqf from hint (_newUnit getVariable "JWL_respawnRole"); to hint (_newUnit getVariable ["JWL_respawnRole", "NOT SET"]); shows NOT SET when selecting the first loadout and spawning in, but shows the selected loadout every subsequent respawn. So onPlayerRespawn.sqf not firing on the first respawn is NOT the problem. EDIT AGAIN: Ok, using "BIS_RscRespawnControlsMap_ctrlRoleList" instead of "BIS_RscRespawnControlsMap_ctrlComboLoadout" returns the name of the role rather than the name of the loadout. So that is one problem fixed.
  16. That makes sense to me. The function is working reasonably well, but there are two problems. One is related to the function, and the other seems to be related to the event script onPlayerRespawn.sqf. The first problem is the function is returning the loadout name from the loadout listbox rather than the role listbox. I am guessing I will have to look at the functions to see if there are different variables to use. This isn't too much of a problem and can be circumvented, but is not optimal. For example, I have a "medic" role, and in this role I have several medic loadouts the player can choose from, depending on various "upgrades" that have been scripted for that side. In order to add the medic skill (healing units to full health with a medkit) that is by default given to combat life saver units placed in the editor, I would have to check to see if the string returned by the function matches one of many different strings corresponding to the different loadouts under the medic "role" category. It would be a lot more optimal to simply check the role instead. The other problem is that onPlayerRespawn.sqf does not seem to fire when the player respawns at the start of the game. I have respawnOnStart = 1; set in description.ext yet the script still seems to not fire the first time. Any thoughts? EDIT: I set the function up as a file and added it to functions library in description.ext. Here is the file. disableSerialization; params [ ["_unit", objNull, [objNull], 1] ]; _respawnCombo = uiNamespace getVariable (["BIS_RscRespawnControlsMap_ctrlComboLoadout", "BIS_RscRespawnControlsSpectate_ctrlComboLoadout"] select (uiNamespace getVariable ["BIS_RscRespawnControlsSpectate_shown", false])); _respawnTemplateDisplayName = _respawnCombo lbText (lbCurSel _respawnCombo); _unit setVariable ["JWL_respawnRole", _respawnTemplateDisplayName, true]; I spawned the function, rather than calling it, because I got a serialization error. I don't know if this makes a difference, but I wanted to be safe and make sure that I was calling disableSerialization in a separate thread from onPlayerRespawn.sqf. I spawned it from onPlayerRespawn.sqf like this: params [ ["_newUnit", objNull, [objNull], 1] ]; _newUnit spawn JWL_fnc_setRoleVar; hint (_newUnit getVariable "JWL_respawnRole"); //Nothing is shown when spawning at the beginning of the mission, but shows "Rifleman (SPAR16)" after every subsequent respawn.
  17. Wow! Amazing. How did you find those variables? Also, in the first line of the function, you are choosing between two variables, based on the state of "BIS_RscRespawnControlsSpectate_shown" which I assume returns a 1 or 0 based on something. What are you choosing between, and why? Basically, what do these two variables represent and what does your condition, which is the state of "BIS_RscRespawnControlsSpectate_shown", represent?
  18. On the BIS respawn screen, players choose a role in the center of the screen. Then on the right side, they choose a loadout. I want to be able to determine either the role or the loadout they have chosen after they respawn through a script. This will allow me to do all sorts of things, such as limiting players from picking up and using certain weapons, driving certain vehicles, giving them the medic heal ability or the engineer repair ability, ect. But I don't know how to determine what role a player has selected at the repsawn screen via script.
  19. I am trying to get an armed blackfish to circle a position counterclockwise and get the gunners do dump rounds on anything near the position. By default, an AI piloted armed blackfish is USELESS, as it attempts to line its nose up with enemies like a normal jet. So I took up the challenge. Shouldn't be too hard, right? Just a counterclockwise loiter, put the driver in his own group and set him up to ignore combat so he flies smoothly in a circle, then set the gunners to engage everything they see. Nope. It isn't that simple. I can't get the pilot to fly smoothly. He goes counterclockwise in a circle around the position, but he rolls a lot which gives the gunners very little gun time. I would be fine with that if the gunners could actually hit anything and actually fired their weapons. Most of the time, the left gunner doesn't use the 20mm or 105mm at all, and the right gunner just fires a couple of 40mm rounds here and there. To top it off, they wont engage infantry unless they have somehow miraculously spotted a vehicle in the area AND THEN disabled it, then they will start shooting at infantry. And that's not all, apparently the 40mm gun doesn't do splash damage, so nothing ever gets killed unless its a direct hit with a 40mm round. Since the AI don't compensate for the speed of the plane, that pretty much doesn't happen unless by accident. Ok, so here is what I have so far. I want a function that takes a Blackfish object, a position, and a duration as arguments. The function should add a waypoint. When that waypoint becomes active, the fish should fly to it, circle it counterclockwise, and fire all of it's guns at everything in the area in a way that is at least visually impressive. It should remain in the area until the duration specified in the arguments has elapsed. Then, it needs to resume normal operation. params [ ["_fish", objNull, [objNull], 1], ["_pos", [0,0,0], [[]], 3], ["_dur", 60, [0], 1] ]; _rad = 300; _alt = 400; _grp = (group (driver _fish)); _wp = _grp addWaypoint [_pos, 0]; _wpi = _wp call JWL_fnc_indexWaypoint; _wp setWaypointType "LOITER"; _wp setWaypointLoiterType "CIRCLE_L"; _wp setWaypointSpeed "FULL"; _wp setWaypointLoiterRadius _rad; [_grp, _wpi, _pos, _fish, _dur, _alt] spawn { params [ "_grp", "_wpi", "_pos", "_fish", "_dur", "_alt" ]; _phase = 0; _time = 0; _plt = ["TARGET","AUTOTARGET","AUTOCOMBAT","FSM"]; _gnrs = ["AIMINGERROR"]; _rgpd = false; /* Start main loop. Run every 3 seconds. */ while {true} do { sleep 3; /* check to see if the Blackfish is alive. If not, terminate the script. */ if (!(alive _fish)) then { systemChat "BLACKFISH DESTROYED - TERMINATING"; terminate _thisScript; }; /* Start the main IF statement. Check to see if the current waypoint is in fact the waypoint that was created earlier in the script, if yes then proceed with the phase. Otherwise, check to see if the waypoint exists. If yes, reset the phase, else terminate the loop. */ if ((waypointName [_grp, (currentWaypoint _grp)]) == _wpi) then { systemChat "WAYPOINT ACTIVE - EVALUATING..."; _fish flyInHeight _alt; /* Check distance of blackfish to the waypoint. Only perform this check before in range. Limit speed and regroup the crew once in range and start a new check. */ if (_phase == 0) then { if (((position _fish) distance _pos) <= 1750) then { systemChat "SPEED LIMITED - AI REGROUPED"; _grp2 = createGroup west; { if (_x != (driver _fish)) then { _unit = _x; [_x] joinSilent _grp2; { _unit disableAI _x } forEach _gnrs; }; } forEach (crew _fish); { (driver _fish) disableAI _x } forEach _plt; _grp2 setCombatMode "RED"; _grp2 setBehaviour "AWARE"; _grp setBehaviour "CARELESS"; _grp setSpeedMode "LIMITED"; //Barely helps _fish limitSpeed 10; //Doesn't seem to work during loiter _rgpd = true; _phase = 1; }; }; /* If previous range check passed and speed limited, start checking a shorter range. Only perform this check until the fish is in range. Once in range, flip a bool and start the "timer" check to limit the loiter time. */ if (_phase == 1) then { if (((position _fish) distance _pos) <= 1250) then { systemChat "BLACKFISH IN RANGE - TIMER STARTED"; _time = diag_tickTime + _dur; _phase = 2; }; }; /* If previous range check passed and speed limited, start checking current time. if time limit reached, reform the group and do some cleanup, and delete the WP. */ if (_phase == 2) then { systemChat "BLACKFISH IN RANGE - ENGAGING"; //maybe do some targetting stuff if (diag_tickTime >= _time) then { systemChat "WAYPOINT TIMED OUT"; { if (_x != (driver _fish)) then { _unit = _x; [_x] joinSilent _grp; { _unit enableAI _x } forEach _gnrs; }; } forEach (crew _fish); { (driver _fish) enableAI _x } forEach _plt; _grp setCombatMode "YELLOW"; _grp setBehaviour "AWARE"; _grp setSpeedMode "FULL"; _fish limitSpeed 600; terminate _thisScript; }; }; /* ELSE statement for main IF statement. If current waypoint is not the created loiter waypoint, then check to see if that waypoint still exists. If not, end the script, if yes, then reset the phase to 0. */ } else { _wpValid = false; { if (waypointName _x == _wpi) then {_wpValid = true}; }forEach (waypoints _grp); if (_wpValid) then { systemChat "WAYPOINT INACTIVE - WAITING"; _rgpd = false; _phase = 0; } else { systemChat "WAYPOINT DELETED - TERMINATING"; if (_rgpd) then { { if (_x != (driver _fish)) then { _unit = _x; [_x] joinSilent _grp; { _unit enableAI _x } forEach _gnrs; }; } forEach (crew _fish); { (driver _fish) enableAI _x } forEach _plt; _grp setCombatMode "YELLOW"; _grp setBehaviour "AWARE"; _grp setSpeedMode "FULL"; _fish limitSpeed 600; }; terminate _thisScript; }; }; }; }; This function psuedo-works, but isn't giving me the desired effect. Also, JWL_fnc_indexWaypoint is a short little function that takes a waypoint, assigns a number unique to that group to the waypoint, and sets the waypoint name as that number and returns the number as a string. comment "------------------------------------------------------------------------------------------------------------- Helper function to index a waypoints for reference in custom waypoint functions.. The index is stored as the waypoint name. Useful to check identity of self-deleting unique waypoints of the same type. Arguments: waypoint Return: index ---------------------------------------------------------------------------------------------------------------------"; _grp = (_this select 0); _curVal = _grp getVariable "JWL_WPCount"; _name = 0; if (isNil "_curVal") then [{ _grp setVariable ["JWL_WPCount",0,true]; _name = str 0; },{ _grp setVariable ["JWL_WPCount",(_curVal + 1),true]; _name = str (_curVal + 1); }]; _this setWaypointName _name; _name Anyone want to run these functions and see what I am talking about, and maybe give some input on what to do about it? There are only so many commands to call on the AI, and most of them make it worse. I am thinking I am going to have to create helipad objects and force the gunners to fire at it manually which will be some really heavy scripting.
  20. Hate to bump, but any thoughts? Can I somehow call a setVariable on the unit that takes some variable which contains the class loadout name that I defined in description.ext?
  21. I can't even get it working at all. https://forums.bistudio.com/topic/192834-bis-revive-working/#entry3067379
  22. He isn't trying to make an AI blackfish fly in circles, he is trying to create a script that will "autopilot" the blackfish to act as if it was piloted by an AI at a loiter waypoint, but while a human player is piloting it. Like the auto-land action for jets, which takes over control of the plane while a human is in the cockpit. My guess would be a loop that uses setVelocity and setVectorDirAndUp with a bit of vector geometry math.
  23. Thanks for explaining! Anyways, here is a function to disable or enable friendly fire on a specific unit. It works, I tested it. Units of the same side are unable to damage a unit that you call the function on. You can also turn the friendly fire back on. params [ ["_unit", objNull, [objNull], 1], ["_tf", false, [true], 1] ]; _ret = false; if (vehicle _unit == _unit) then { if (_tf) then { _unit setVariable ["FF_disabled", ( _unit addEventHandler [ "HandleDamage", { if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}]; } ]) ]; _ret = true; } else { _eh = _unit getVariable "FF_disabled"; if (!(isNil "_eh")) then { _unit removeEventHandler ["HandleDamage", _eh]; _unit setVariable ["FF_disabled", nil]; }; }; }; _ret So what I did was add the function to my function library in the mission. Inside of description.ext, I put: class cfgFunctions { #include "functions\functions.hpp" }; Then I made a folder in the mission directory and named it "functions". Then inside that folder I created a text file and named it "functions.hpp" Inside of "functions.hpp" I put the following code: class JWL { tag = "JWL"; class functions { file = "functions"; class disableFriendlyFire {}; //----------------------------------------------------------------------------------- //Here are all my other functions. //They are defined by simply putting "class myFunction {};" After the line above. //I can call them with "returnValue = [parameter1, parameter2, ect] call JWL_fnc_myFunction; //----------------------------------------------------------------------------------- }; }; Ok. Now the game expects to find the function as a file within a folder named functions that is in the mission folder. It will look for an sqf file with the name fn_myFunction, or in this case, fn_disableFriendlyFire. So I made a file named fn_disableFriendlyFire.sqf and I put this code inside it: params [ ["_unit", objNull, [objNull], 1], ["_tf", false, [true], 1] ]; _ret = false; if (vehicle _unit == _unit) then { if (_tf) then { _unit setVariable ["FF_disabled", ( _unit addEventHandler [ "HandleDamage", { if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}]; } ]) ]; _ret = true; } else { _eh = _unit getVariable "FF_disabled"; if (!(isNil "_eh")) then { _unit removeEventHandler ["HandleDamage", _eh]; _unit setVariable ["FF_disabled", nil]; }; }; }; _ret Now, to use the function, I simply put "[unit, true] call JWL_fnc_disableFriendlyFire;" in the script somewhere, where unit is the unit that I want to turn friendly fire off. If I want to turn friendly fire back on for that unit, I do the same thing but with a slight change: "[unit, false] call JWL disableFriendlyFire;" Now I can call this function in the init field of a unit that I place in the editor with "[this, true] call JWL_fnc_disableFriendlyFire;" or I can call it after spawning a unit using createUnit Array in a script. If I wanted to do this to all currently existing (at the time I run the script) AI units on the Blufor side, for example, I would use a forEach loop in a script. Like this: { [_x, true] call JWL_fnc_disableFriendlyFire; } forEach (allUnits select {(!isPlayer _x) && (side _x == west)}); A few things to note: -If you disable friendly fire on a unit, you must call the function from the same machine that disabled friendly fire if you want to enable it again on that unit. -The function will not work on vehicles. Only infantry units.
  24. I'm new to ArmA scripting. Would you mind explaining a few things to me? Why are you calling "params" in the EH code? Just to clean it up so instead of (_this select #) you have readable variables? My biggest question though is the array you are returning with the little function "(allUnits select {!isPlayer _x})" Say you have an array [A,B,C]. Imagine that A and B are not players, but C is a player. Wouldnt (select {!isPlayer _x}) return 0 for A and B, and therefore value A would be selected or value B would be selected as it is the first (and only) value of the array inside the main array? But for C, (select {!isPlayer _x}) would return 1, which would select the value in the second slot of the array at value C, which does not exist. The code, therefore, would perform as intended, but wouldn't this throw an error? Basically, wouldn't this iterate through all units in the game, but select an array value that is out of bounds if {!isPlayer _x} returns false? As such, wouldn't this throw an error each time it encounters a player unit in the allUnits array? And for the OP. I am working on a function to disable or enable friendly fire on a single unit by passing a unit and a boolean to the function. You could use a script to call this on all AI units if you wanted. I'll post it when it is ready and give an example of calling the function on multiple non-player units.
  25. Make sure the unit isn't captive, as the above poster has said. Units on which you have called setCaptive=true; will basically join the civillian side and the script command "side" will return civilian if called on the unit. As a result, the little function I posted before will do its job, but when the event handler is called it will return nothing and the normal damage value will be applied to the unit. Basically, any unit with setCaptive = true; will behave unexpectedly and will only be immune to damage from civilian players. Speaking of which, it is good practice to always return something from a function, so here is a slight rewrite of the above script. I am not familiar with how HandleDamage works, but this might work a bit better because it returns the normal damage value if the side of the attacker and target are different, else it returns 0. { if (!(isPlayer _x)) then { _x addEventHandler ["HandleDamage", { if ((side (_this select 0)) != (side (_this select 3))) then [{_this select 2},{0}]; }]; }; } forEach allUnits;