// ACE - Common // #define ENABLE_PERFORMANCE_COUNTERS // #define DEBUG_MODE_FULL #include "script_component.hpp" ////////////////////////////////////////////////// // Get Map Data ////////////////////////////////////////////////// //Find MGRS zone and 100km grid for current map [] call FUNC(getMGRSdata); //Prepare variables for FUNC(getMapGridFromPos)/FUNC(getMapPosFromGrid) [] call FUNC(getMapGridData); ////////////////////////////////////////////////// // Eventhandlers ////////////////////////////////////////////////// //Status Effect EHs: [QGVAR(setStatusEffect), LINKFUNC(statusEffect_set)] call CBA_fnc_addEventHandler; ["forceWalk", false, ["ace_advanced_fatigue", "ACE_SwitchUnits", "ACE_Attach", "ace_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_Sandbag", "ACE_refuel", "ACE_rearm", "ACE_Trenches", "ace_medical_fracture"]] call FUNC(statusEffect_addType); ["blockSprint", false, ["ace_advanced_fatigue", "ace_dragging", "ace_medical_fracture"]] call FUNC(statusEffect_addType); ["setCaptive", true, [QEGVAR(captives,Handcuffed), QEGVAR(captives,Surrendered)]] call FUNC(statusEffect_addType); ["blockDamage", false, ["fixCollision", "ACE_cargo"]] call FUNC(statusEffect_addType); ["blockEngine", false, ["ACE_Refuel"]] call FUNC(statusEffect_addType); ["blockThrow", false, ["ACE_Attach", "ACE_concertina_wire", "ace_dragging", "ACE_Explosives", "ACE_Ladder", "ACE_rearm", "ACE_refuel", "ACE_Sandbag", "ACE_Trenches", "ACE_tripod"]] call FUNC(statusEffect_addType); ["setHidden", true, ["ace_unconscious"]] call FUNC(statusEffect_addType); ["blockRadio", false, [QEGVAR(captives,Handcuffed), QEGVAR(captives,Surrendered), "ace_unconscious"]] call FUNC(statusEffect_addType); ["blockSpeaking", false, ["ace_unconscious"]] call FUNC(statusEffect_addType); ["disableWeaponAssembly", false, ["ace_common", "ace_common_lockVehicle", "ace_csw"]] call FUNC(statusEffect_addType); ["lockInventory", true, [], true] call FUNC(statusEffect_addType); [QGVAR(forceWalk), { params ["_object", "_set"]; TRACE_2("forceWalk EH",_object,_set); _object forceWalk (_set > 0); }] call CBA_fnc_addEventHandler; [QGVAR(blockSprint), { //Name reversed from `allowSprint` because we want NOR logic params ["_object", "_set"]; TRACE_2("blockSprint EH",_object,_set); _object allowSprint (_set == 0); }] call CBA_fnc_addEventHandler; [QGVAR(setAnimSpeedCoef), { params ["_object", "_set"]; _object setAnimSpeedCoef _set; }] call CBA_fnc_addEventHandler; [QGVAR(setCaptive), { params ["_object", "_set"]; TRACE_2("setCaptive EH",_object,_set); _object setCaptive (_set > 0); }] call CBA_fnc_addEventHandler; [QGVAR(setHidden), { params ["_object", "_set"]; TRACE_2("setHidden EH",_object,_set); // May report nil. Default to factor 1. private _vis = [_object getUnitTrait "camouflageCoef"] param [0, 1]; if (_set > 0) then { if (_vis != 0) then { _object setVariable [QGVAR(oldVisibility), _vis]; _object setUnitTrait ["camouflageCoef", 0]; { if (side _x != side group _object) then { _x forgetTarget _object; }; } forEach allGroups; }; } else { _vis = _object getVariable [QGVAR(oldVisibility), _vis]; _object setUnitTrait ["camouflageCoef", _vis]; }; }] call CBA_fnc_addEventHandler; [QGVAR(blockRadio), { params ["_object", "_set"]; TRACE_2("blockRadio EH",_object,_set); if (_object isEqualTo ACE_Player && {_set > 0}) then { call FUNC(endRadioTransmission); }; if (["task_force_radio"] call FUNC(isModLoaded)) then { _object setVariable ["tf_unable_to_use_radio", _set > 0, true]; }; if (["acre_main"] call FUNC(isModLoaded)) then { _object setVariable ["acre_sys_core_isDisabledRadio", _set > 0, true]; }; }] call CBA_fnc_addEventHandler; [QGVAR(blockSpeaking), { params ["_object", "_set"]; TRACE_2("blockSpeaking EH",_object,_set); if (["acre_main"] call FUNC(isModLoaded)) then { _object setVariable ["acre_sys_core_isDisabled", _set > 0, true]; }; if (["task_force_radio"] call FUNC(isModLoaded)) then { _object setVariable ["tf_voiceVolume", parseNumber (_set == 0), true]; }; }] call CBA_fnc_addEventHandler; [QGVAR(blockDamage), { //Name reversed from `allowDamage` because we want NOR logic params ["_object", "_set"]; if ((_object isKindOf "CAManBase") && {(["ace_medical"] call FUNC(isModLoaded))}) then { TRACE_2("blockDamage EH (using medical)",_object,_set); _object setVariable [QEGVAR(medical,allowDamage), (_set == 0), true]; } else { TRACE_2("blockDamage EH (using allowDamage)",_object,_set); _object allowDamage (_set == 0); }; }] call CBA_fnc_addEventHandler; [QGVAR(blockEngine), { params ["_vehicle", "_set"]; _vehicle setVariable [QGVAR(blockEngine), _set > 0, true]; _vehicle engineOn false; }] call CBA_fnc_addEventHandler; [QGVAR(setMass), { params ["_object", "_mass"]; _object setMass _mass; }] call CBA_fnc_addEventHandler; [QGVAR(disableWeaponAssembly), { params ["_object", "_set"]; _object enableWeaponDisassembly (_set < 1); }] call CBA_fnc_addEventHandler; [QGVAR(lockInventory), { params ["_object", "_set"]; TRACE_2("lockInventory EH",_object,_set); _object lockInventory (_set > 0); }] call CBA_fnc_addEventHandler; //Add a fix for BIS's zeus remoteControl module not reseting variables on DC when RC a unit //This variable is used for isPlayer checks if (isServer) then { addMissionEventHandler ["HandleDisconnect", { params ["_dcPlayer"]; private _zeusLogic = getAssignedCuratorLogic _dcPlayer; if ((!isNil "_zeusLogic") && {!isNull _zeusLogic}) then { { if ((_x getvariable ["bis_fnc_moduleRemoteControl_owner", objnull]) isEqualTo _dcPlayer) exitWith { INFO_3("[%1] DC - Was Zeus [%2] while controlling unit [%3] - manually clearing `bis_fnc_moduleRemoteControl_owner`",[_x] call FUNC(getName),_dcPlayer,_x); _x setVariable ["bis_fnc_moduleRemoteControl_owner", nil, true]; }; } forEach (curatorEditableObjects _zeusLogic); }; }]; }; // Event to log Fix Headbug output [QGVAR(headbugFixUsed), { params ["_profileName", "_animation"]; INFO_2("Headbug Used: Name: %1, Animation: %2",_profileName,_animation); }] call CBA_fnc_addEventHandler; [QGVAR(fixCollision), LINKFUNC(fixCollision)] call CBA_fnc_addEventHandler; [QGVAR(fixFloating), LINKFUNC(fixFloating)] call CBA_fnc_addEventHandler; [QGVAR(fixPosition), LINKFUNC(fixPosition)] call CBA_fnc_addEventHandler; ["ace_loadPersonEvent", LINKFUNC(loadPersonLocal)] call CBA_fnc_addEventHandler; ["ace_unloadPersonEvent", LINKFUNC(unloadPersonLocal)] call CBA_fnc_addEventHandler; [QGVAR(lockVehicle), { _this setVariable [QGVAR(lockStatus), locked _this]; _this lock 2; if ([] isNotEqualTo getArray (configOf _this >> "assembleInfo" >> "dissasembleTo")) then { [_this, "disableWeaponAssembly", QGVAR(lockVehicle), true] call FUNC(statusEffect_set); }; }] call CBA_fnc_addEventHandler; [QGVAR(unlockVehicle), { _this lock (_this getVariable [QGVAR(lockStatus), locked _this]); if ([] isNotEqualTo getArray (configOf _target >> "assembleInfo" >> "dissasembleTo")) then { [_this, "disableWeaponAssembly", QGVAR(lockVehicle), false] call FUNC(statusEffect_set); }; }] call CBA_fnc_addEventHandler; [QGVAR(setDir), {(_this select 0) setDir (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(setFuel), {(_this select 0) setFuel (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(engineOn), {(_this select 0) engineOn (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(setSpeaker), {(_this select 0) setSpeaker (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(selectLeader), {(_this select 0) selectLeader (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(setVelocity), {(_this select 0) setVelocity (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(playMove), {(_this select 0) playMove (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(playMoveNow), {(_this select 0) playMoveNow (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(playAction), {(_this select 0) playAction (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(playActionNow), {(_this select 0) playActionNow (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(switchMove), {(_this select 0) switchMove (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(setVectorDirAndUp), {(_this select 0) setVectorDirAndUp (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(addWeaponItem), {(_this select 0) addWeaponItem [(_this select 1), (_this select 2)]}] call CBA_fnc_addEventHandler; [QGVAR(setVanillaHitPointDamage), { params ["_object", "_hitPointAnddamage"]; private _damageDisabled = !isDamageAllowed _object; if (_damageDisabled) then { _object allowDamage true; }; _object setHitPointDamage _hitPointAnddamage; if (_damageDisabled) then { _object allowDamage false; }; }] call CBA_fnc_addEventHandler; // Request framework [QGVAR(requestCallback), LINKFUNC(requestCallback)] call CBA_fnc_addEventHandler; [QGVAR(receiveRequest), LINKFUNC(receiveRequest)] call CBA_fnc_addEventHandler; [QGVAR(systemChatGlobal), {systemChat _this}] call CBA_fnc_addEventHandler; if (isServer) then { [QGVAR(hideObjectGlobal), {(_this select 0) hideObjectGlobal (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(enableSimulationGlobal), {(_this select 0) enableSimulationGlobal (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(setShotParents), {(_this select 0) setShotParents [_this select 1, _this select 2]}] call CBA_fnc_addEventHandler; ["ace_setOwner", {(_this select 0) setOwner (_this select 1)}] call CBA_fnc_addEventHandler; [QGVAR(serverLog), LINKFUNC(serverLog)] call CBA_fnc_addEventHandler; [QGVAR(claimSafe), LINKFUNC(claimSafeServer)] call CBA_fnc_addEventHandler; }; ////////////////////////////////////////////////// // Set up remote execution ////////////////////////////////////////////////// // Synced ACE events // Handle JIP scenario if (!isServer) then { ["ace_playerJIP", { INFO("JIP event synchronization initialized"); ["ACEa", [player]] call CBA_fnc_serverEvent; }] call CBA_fnc_addEventHandler; } else { ["ACEa", LINKFUNC(_handleRequestAllSyncedEvents)] call CBA_fnc_addEventHandler; }; ["ACEe", LINKFUNC(_handleSyncedEvent)] call CBA_fnc_addEventHandler; ["ACEs", LINKFUNC(_handleRequestSyncedEvent)] call CBA_fnc_addEventHandler; if (isServer) then { [LINKFUNC(syncedEventPFH), 0.5, []] call CBA_fnc_addPerFrameHandler; }; ////////////////////////////////////////////////// // Check files, previous installed version etc. ////////////////////////////////////////////////// private _currentVersion = getText (configFile >> "CfgPatches" >> QUOTE(ADDON) >> "versionStr"); private _previousVersion = profileNamespace getVariable ["ACE_VersionNumberString", ""]; // check previous version number from profile if (_currentVersion != _previousVersion) then { INFO_2("Updating ACE from [%1] to [%2]",_previousVersion,_currentVersion); [_previousVersion] call FUNC(cbaSettings_transferUserSettings); profileNamespace setVariable ["ACE_VersionNumberString", _currentVersion]; }; call FUNC(checkFiles); ////////////////////////////////////////////////// // Set up ace_settingsInitialized eventhandler ////////////////////////////////////////////////// ["CBA_settingsInitialized", { [ GVAR(checkPBOsAction), GVAR(checkPBOsCheckAll), GVAR(checkPBOsWhitelist) ] call FUNC(checkPBOs) }] call CBA_fnc_addEventHandler; /***************************************************************************/ /***************************************************************************/ /** everything that only player controlled machines need, goes below this **/ /***************************************************************************/ /***************************************************************************/ if (!hasInterface) exitWith {}; ////////////////////////////////////////////////// // Set up mouse wheel eventhandler ////////////////////////////////////////////////// call FUNC(assignedItemFix); // @todo remove? enableCamShake true; //FUNC(showHud) needs to be refreshed if it was set during mission init ["ace_infoDisplayChanged", { if (GVAR(showHudHash) isNotEqualTo createHashMap) then { [] call FUNC(showHud); }; }] call CBA_fnc_addEventHandler; ////////////////////////////////////////////////// // Eventhandler to set player names ////////////////////////////////////////////////// // Set the name for the current player ["unit", { params ["_newPlayer","_oldPlayer"]; if (alive _newPlayer) then { [FUNC(setName), [_newPlayer]] call CBA_fnc_execNextFrame; }; if (alive _oldPlayer) then { [FUNC(setName), [_oldPlayer]] call CBA_fnc_execNextFrame; }; }, true] call CBA_fnc_addPlayerEventHandler; ////////////////////////////////////////////////// // Set up numerous eventhanders for player controlled units ////////////////////////////////////////////////// TRACE_1("adding unit playerEH to set ace_player",isNull cba_events_oldUnit); ["unit", { ACE_player = (_this select 0); }, true] call CBA_fnc_addPlayerEventHandler; // Clear uniqueItems cache on loadout change ["loadout", { GVAR(uniqueItemsCache) = nil; }] call CBA_fnc_addPlayerEventHandler; // Backwards compatiblity for old ace event GVAR(OldIsCamera) = false; ["featureCamera", { params ["_player", "_cameraName"]; GVAR(OldIsCamera) = _cameraName != ""; ["ace_activeCameraChanged", [_player, GVAR(OldIsCamera)]] call CBA_fnc_localEvent; }, true] call CBA_fnc_addPlayerEventHandler; // Add event handler for UAV control change ACE_controlledUAV = [objNull, objNull, [], ""]; addMissionEventHandler ["PlayerViewChanged", { // On non-server client this command is semi-broken // arg index 5 should be the controlled UAV, but it will often be objNull (delay from locality switching?) // On PlayerViewChanged event, start polling for new uav state for a few seconds (should be done within a few frames) params ["", "", "", "", "_newCameraOn", "_UAV"]; TRACE_2("PlayerViewChanged",_newCameraOn,_UAV); [{ if (isNull player) exitWith {true}; private _UAV = getConnectedUAV player; if (!alive player) then {_UAV = objNull;}; private _position = [player] call FUNC(getUavControlPosition); private _seatAI = objNull; private _turret = []; switch (toLowerANSI _position) do { case (""): { _UAV = objNull; // set to objNull if not actively controlling }; case ("driver"): { _turret = [-1]; _seatAI = driver _UAV; }; case ("gunner"): { _turret = [0]; _seatAI = gunner _UAV; }; }; private _newArray = [_UAV, _seatAI, _turret, _position]; if (_newArray isEqualTo ACE_controlledUAV) exitWith {false}; // no change yet TRACE_2("Seat Change",_newArray,ACE_controlledUAV); ACE_controlledUAV = _newArray; ["ACE_controlledUAV", _newArray] call CBA_fnc_localEvent; // stay in the loop as we might switch from gunner -> driver, and there may be a empty position event in-between false }, {}, [], 3, {TRACE_1("timeout",_this);}] call CBA_fnc_waitUntilAndExecute; }]; ////////////////////////////////////////////////// // Eventhandlers for player controlled machines ////////////////////////////////////////////////// [QGVAR(displayTextStructured), LINKFUNC(displayTextStructured)] call CBA_fnc_addEventHandler; [QGVAR(displayTextPicture), LINKFUNC(displayTextPicture)] call CBA_fnc_addEventHandler; ["ace_unconscious", { params ["_unit", "_isUnconscious"]; if (local _unit && {!_isUnconscious}) then { [_unit, false, QFUNC(loadPerson), west /* dummy side */] call FUNC(switchToGroupSide); }; }] call CBA_fnc_addEventHandler; ["ace_useItem", LINKFUNC(useItem)] call CBA_fnc_addEventHandler; ////////////////////////////////////////////////// // Add various canInteractWith conditions ////////////////////////////////////////////////// ["isNotDead", { params ["_unit"]; alive _unit }] call FUNC(addCanInteractWithCondition); ["notOnMap", {!visibleMap}] call FUNC(addCanInteractWithCondition); ["isNotInside", { params ["_unit", "_target"]; // Players can always interact with himself if not boarded isNull objectParent _unit || // Players can always interact with his vehicle {objectParent _unit isEqualTo _target} || // Players can always interact with passengers of the same vehicle {_unit isNotEqualTo _target && {!isNull objectParent _target} && {objectParent _unit isEqualTo objectParent _target}} || // Players can always interact with connected UAV {!(isNull (ACE_controlledUAV select 0))} }] call FUNC(addCanInteractWithCondition); ["isNotInZeus", {isNull curatorCamera}] call FUNC(addCanInteractWithCondition); ["isNotUnconscious", { params ["_unit"]; lifeState _unit isNotEqualTo "INCAPACITATED" }] call FUNC(addCanInteractWithCondition); ////////////////////////////////////////////////// // Set up reload mutex ////////////////////////////////////////////////// GVAR(isReloading) = false; GVAR(reloadMutex_lastMagazines) = []; // When reloading, the new magazine is removed from inventory, an animation plays and then the old magazine is added // If the animation is interrupted, the new magazine will be lost ["loadout", { params ["_unit", "_newLoadout"]; private _mags = magazines _unit; // if our magazine count dropped by 1, we might be reloading if ((count GVAR(reloadMutex_lastMagazines)) - (count _mags) == 1) then { private _weapon = currentWeapon _unit; private _muzzle = currentMuzzle _unit; if (_weapon == "") exitWith {}; private _wpnMzlConfig = configFile >> "CfgWeapons" >> _weapon; if (_muzzle != _weapon) then { _wpnMzlConfig = _wpnMzlConfig >> _muzzle; }; private _compatMags = [_wpnMzlConfig] call CBA_fnc_compatibleMagazines; private _lastCompatMagCount = {_x in _compatMags} count GVAR(reloadMutex_lastMagazines); private _curCompatMagCount = {_x in _compatMags} count _mags; TRACE_3("",_wpnMzlConfig,_lastCompatMagCount,_curCompatMagCount); if (_lastCompatMagCount - _curCompatMagCount != 1) exitWith {}; // check if magazines for our specific muzzle dropped by 1 private _gesture = getText (_wpnMzlConfig >> "reloadAction"); if (_gesture == "") exitWith {}; //Ignore weapons with no reload gesture (binoculars) private _isLauncher = _weapon isKindOf ["Launcher", configFile >> "CfgWeapons"]; private _duration = 0; if (_isLauncher) then { _duration = getNumber (configfile >> "CfgMovesMaleSdr" >> "States" >> _gesture >> "speed"); }; if (_duration == 0) then { _duration = getNumber (configfile >> "CfgGesturesMale" >> "States" >> _gesture >> "speed"); }; if (_duration != 0) then { _duration = if (_duration < 0) then { abs _duration } else { 1 / _duration }; } else { _duration = 6; }; TRACE_2("Reloading, blocking gestures",_weapon,_duration); GVAR(reloadingETA) = CBA_missionTime + _duration; if (!GVAR(isReloading)) then { GVAR(isReloading) = true; [{ CBA_missionTime > GVAR(reloadingETA) },{ GVAR(isReloading) = false; }] call CBA_fnc_waitUntilAndExecute; }; }; GVAR(reloadMutex_lastMagazines) = _mags; }, true] call CBA_fnc_addPlayerEventHandler; ////////////////////////////////////////////////// // Start the sway loop ////////////////////////////////////////////////// ["CBA_settingsInitialized", { ["multiplier", { switch (true) do { case (isWeaponRested ACE_player): { GVAR(swayFactor) * GVAR(restedSwayFactor) }; case (isWeaponDeployed ACE_player): { GVAR(swayFactor) * GVAR(deployedSwayFactor) }; default { GVAR(swayFactor) }; }; }, QUOTE(ADDON)] call FUNC(addSwayFactor); [{ // frame after settingsInitialized to ensure all other addons have added their factors if (GVAR(enableSway)) then { call FUNC(swayLoop); }; // check for pre-3.16 sway factors being added if (!isNil {missionNamespace getVariable "ACE_setCustomAimCoef"}) then { WARNING("ACE_setCustomAimCoef no longer supported - use ace_common_fnc_addSwayFactor"); WARNING_1("source: %1",(missionNamespace getVariable "ACE_setCustomAimCoef") apply {_x}); }; }] call CBA_fnc_execNextFrame; }] call CBA_fnc_addEventHandler; ////////////////////////////////////////////////// // Set up PlayerJIP eventhandler ////////////////////////////////////////////////// // Lastly, do JIP events // JIP Detection and event trigger. Run this at the very end, just in case anything uses it // Note: usage of player is most likely on purpose if (didJip) then { // We are jipping! Get ready and wait, and throw the event [{ if(!isNull player && GVAR(settingsInitFinished)) then { ["ace_playerJIP", [player]] call CBA_fnc_localEvent; [_this select 1] call CBA_fnc_removePerFrameHandler; }; }, 0, []] call CBA_fnc_addPerFrameHandler; }; ////////////////////////////////////////////////// // CBA key input handling ////////////////////////////////////////////////// //Device Handler: GVAR(deviceKeyHandlingArray) = []; GVAR(deviceKeyCurrentIndex) = -1; // Register localizations for the Keybinding categories ["ACE3 Equipment", LLSTRING(ACEKeybindCategoryEquipment)] call CBA_fnc_registerKeybindModPrettyName; ["ACE3 Common", LLSTRING(ACEKeybindCategoryCommon)] call CBA_fnc_registerKeybindModPrettyName; ["ACE3 Weapons", LLSTRING(ACEKeybindCategoryWeapons)] call CBA_fnc_registerKeybindModPrettyName; ["ACE3 Movement", LLSTRING(ACEKeybindCategoryMovement)] call CBA_fnc_registerKeybindModPrettyName; ["ACE3 Scope Adjustment", LLSTRING(ACEKeybindCategoryScopeAdjustment)] call CBA_fnc_registerKeybindModPrettyName; ["ACE3 Vehicles", LLSTRING(ACEKeybindCategoryVehicles)] call CBA_fnc_registerKeybindModPrettyName; ["ACE3 Equipment", QGVAR(openDevice), LLSTRING(toggleHandheldDevice), { [] call FUNC(deviceKeyFindValidIndex); if (GVAR(deviceKeyCurrentIndex) == -1) exitWith {false}; [] call ((GVAR(deviceKeyHandlingArray) select GVAR(deviceKeyCurrentIndex)) select 3); true }, {false}, [0xC7, [false, false, false]], false] call CBA_fnc_addKeybind; //Home Key ["ACE3 Equipment", QGVAR(closeDevice), LLSTRING(closeHandheldDevice), { [] call FUNC(deviceKeyFindValidIndex); if (GVAR(deviceKeyCurrentIndex) == -1) exitWith {false}; [] call ((GVAR(deviceKeyHandlingArray) select GVAR(deviceKeyCurrentIndex)) select 4); true }, {false}, [0xC7, [false, true, false]], false] call CBA_fnc_addKeybind; //CTRL + Home Key ["ACE3 Equipment", QGVAR(cycleDevice), LLSTRING(cycleHandheldDevices), { [1] call FUNC(deviceKeyFindValidIndex); if (GVAR(deviceKeyCurrentIndex) == -1) exitWith {false}; private _displayName = ((GVAR(deviceKeyHandlingArray) select GVAR(deviceKeyCurrentIndex)) select 0); private _iconImage = ((GVAR(deviceKeyHandlingArray) select GVAR(deviceKeyCurrentIndex)) select 1); [_displayName, _iconImage] call FUNC(displayTextPicture); true }, {false}, [0xC7, [true, false, false]], false] call CBA_fnc_addKeybind; //SHIFT + Home Key ["ACE3 Weapons", QGVAR(unloadWeapon), LSTRING(unloadWeapon), { private _unit = ACE_player; // Conditions if !([_unit, objNull, ["isNotInside"]] call FUNC(canInteractWith)) exitWith {false}; if !(_unit call CBA_fnc_canUseWeapon) exitWith {false}; (weaponState _unit) params ["_weapon", "_muzzle", "", "_magazine", "_ammo"]; // Check if there is any ammo if (_ammo < 1) exitWith {false}; // Check if the unit has a weapon if (_weapon == "") exitWith {false}; // Check if the unit has a weapon selected if !(_weapon in [primaryWeapon _unit, handgunWeapon _unit, secondaryWeapon _unit]) exitWith {false}; // Statement [_unit, _weapon, _muzzle, _magazine, _ammo, false] call FUNC(unloadUnitWeapon); true }, {false}, [19, [false, false, true]], false] call CBA_fnc_addKeybind; // Alt + R ["CBA_loadoutSet", { params ["_unit", "_loadout"]; _loadout params ["_primaryWeaponArray"]; if ((_primaryWeaponArray param [0, ""]) == "ACE_FakePrimaryWeapon") then { TRACE_1("Ignoring fake gun",_primaryWeaponArray); _loadout set [0, []]; }; }] call CBA_fnc_addEventHandler; GVAR(commonPostInited) = true;