Merge branch 'master' into pr/9758

This commit is contained in:
johnb432 2024-02-08 11:11:13 +01:00
commit 370f141776
77 changed files with 1233 additions and 345 deletions

View File

@ -60,7 +60,7 @@ if (!hasInterface) exitWith {};
}, true] call CBA_fnc_addPlayerEventHandler; }, true] call CBA_fnc_addPlayerEventHandler;
// - Duty factors ------------------------------------------------------------- // - Duty factors -------------------------------------------------------------
if (["ace_medical"] call EFUNC(common,isModLoaded)) then { if (GVAR(medicalLoaded)) then {
[QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1 [QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1
linearConversion [0, 1, (_this getVariable [QEGVAR(medical,pain), 0]), 1, 1.1, true]; linearConversion [0, 1, (_this getVariable [QEGVAR(medical,pain), 0]), 1, 1.1, true];
}] call FUNC(addDutyFactor); }] call FUNC(addDutyFactor);

View File

@ -13,5 +13,6 @@ GVAR(dutyList) = createHashMap;
GVAR(setAnimExclusions) = []; GVAR(setAnimExclusions) = [];
GVAR(inertia) = 0; GVAR(inertia) = 0;
GVAR(inertiaCache) = createHashMap; GVAR(inertiaCache) = createHashMap;
GVAR(medicalLoaded) = ["ace_medical"] call EFUNC(common,isModLoaded);
ADDON = true; ADDON = true;

View File

@ -23,6 +23,12 @@ if (!alive ACE_player) exitWith {
_staminaBarContainer ctrlCommit 1; _staminaBarContainer ctrlCommit 1;
}; };
private _oxygen = 0.9; // Default AF oxygen saturation
if (GVAR(medicalLoaded) && {EGVAR(medical_vitals,simulateSpo2)}) then {
_oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100;
};
private _currentWork = REE; private _currentWork = REE;
private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6; private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6;
@ -42,8 +48,8 @@ GVAR(muscleDamage) = (GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.
private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage)); private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage));
// Calculate available power // Calculate available power
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * OXYGEN * _muscleIntegritySqrt; private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * OXYGEN * _muscleIntegritySqrt; private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
// Calculate how much power is consumed from each reserve // Calculate how much power is consumed from each reserve
private _ae1Power = _currentWork min _ae1PathwayPowerFatigued; private _ae1Power = _currentWork min _ae1PathwayPowerFatigued;
@ -58,8 +64,8 @@ GVAR(anReserve) = GVAR(anReserve) - _anPower / WATTSPERATP;
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 1.1; GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 1.1;
// Aerobic ATP reserve recovery // Aerobic ATP reserve recovery
GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + OXYGEN * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0; GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + _oxygen * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0;
GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + OXYGEN * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0; GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + _oxygen * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0;
// Anaerobic ATP reserver and fatigue recovery // Anaerobic ATP reserver and fatigue recovery
GVAR(anReserve) = ((GVAR(anReserve) GVAR(anReserve) = ((GVAR(anReserve)
@ -70,9 +76,9 @@ GVAR(anFatigue) = ((GVAR(anFatigue)
- (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor) - (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
) min 1) max 0; ) min 1) max 0;
private _aeReservePercentage = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2; GVAR(aeReservePercentage) = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2;
private _anReservePercentage = GVAR(anReserve) / AN_MAXRESERVE; GVAR(anReservePercentage) = GVAR(anReserve) / AN_MAXRESERVE;
private _perceivedFatigue = 1 - (_anReservePercentage min _aeReservePercentage); private _perceivedFatigue = 1 - (GVAR(anReservePercentage) min GVAR(aeReservePercentage));
[ACE_player, _perceivedFatigue, _currentSpeed, GVAR(anReserve) == 0] call FUNC(handleEffects); [ACE_player, _perceivedFatigue, _currentSpeed, GVAR(anReserve) == 0] call FUNC(handleEffects);

View File

@ -15,3 +15,17 @@ class Extended_PostInit_EventHandlers {
init = QUOTE(call COMPILE_SCRIPT(XEH_postInit)); init = QUOTE(call COMPILE_SCRIPT(XEH_postInit));
}; };
}; };
class Extended_Killed_EventHandlers {
class CAManBase {
class ADDON {
killed = QUOTE((_this select 0) call FUNC(handleDeployInterrupt));
};
};
};
class Extended_DisplayLoad_EventHandlers {
class RscDisplayMission {
ADDON = QUOTE(_this call COMPILE_SCRIPT(XEH_missionDisplayLoad));
};
};

View File

@ -2,10 +2,15 @@ PREP(addCargoItem);
PREP(addCargoVehiclesActions); PREP(addCargoVehiclesActions);
PREP(canLoadItemIn); PREP(canLoadItemIn);
PREP(canUnloadItem); PREP(canUnloadItem);
PREP(deployCancel);
PREP(deployConfirm);
PREP(getCargoSpaceLeft); PREP(getCargoSpaceLeft);
PREP(getNameItem); PREP(getNameItem);
PREP(getSelectedItem);
PREP(getSizeItem); PREP(getSizeItem);
PREP(handleDestroyed); PREP(handleDestroyed);
PREP(handleDeployInterrupt);
PREP(handleScrollWheel);
PREP(initObject); PREP(initObject);
PREP(initVehicle); PREP(initVehicle);
PREP(loadItem); PREP(loadItem);
@ -16,6 +21,7 @@ PREP(removeCargoItem);
PREP(renameObject); PREP(renameObject);
PREP(setSize); PREP(setSize);
PREP(setSpace); PREP(setSpace);
PREP(startDeploy);
PREP(startLoadIn); PREP(startLoadIn);
PREP(startUnload); PREP(startUnload);
PREP(unloadCarryItem); PREP(unloadCarryItem);

View File

@ -0,0 +1,11 @@
#include "script_component.hpp"
params ["_display"];
_display displayAddEventHandler ["MouseZChanged", {(_this select 1) call FUNC(handleScrollWheel)}];
_display displayAddEventHandler ["MouseButtonDown", {
// Right clicking cancels deployment
if (_this select 1 == 1) then {
ACE_player call FUNC(handleDeployInterrupt);
};
}];

View File

@ -17,10 +17,10 @@
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
["ace_unloadCargo", { ["ace_unloadCargo", {
params ["_item", "_vehicle", ["_unloader", objNull]]; params ["_item", "_vehicle", ["_unloader", objNull], ["_place", []]];
TRACE_3("UnloadCargo EH",_item,_vehicle,_unloader); TRACE_4("UnloadCargo EH",_item,_vehicle,_unloader,_place);
private _unloaded = [_item, _vehicle, _unloader] call FUNC(unloadItem); // returns true if successful private _unloaded = [_item, _vehicle, _unloader, _place] call FUNC(unloadItem); // returns true if successful
// Show hint as feedback // Show hint as feedback
private _hint = [LSTRING(unloadingFailed), LSTRING(unloadedItem)] select _unloaded; private _hint = [LSTRING(unloadingFailed), LSTRING(unloadedItem)] select _unloaded;
@ -36,13 +36,25 @@
}; };
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
// Direction must be set before setting position according to wiki
[QGVAR(setDirAndUnload), {
params ["_item", "_emptyPosAGL", "_direction"];
_item setDir _direction;
[QGVAR(serverUnload), [_item, _emptyPosAGL]] call CBA_fnc_serverEvent;
}] call CBA_fnc_addEventHandler;
// hideObjectGlobal must be executed before setPos to ensure light objects are rendered correctly
// Do both on server to ensure they are executed in the correct order
[QGVAR(serverUnload), { [QGVAR(serverUnload), {
params ["_item", "_emptyPosAGL"]; params ["_item", "_emptyPosAGL"];
_item hideObjectGlobal false; _item hideObjectGlobal false;
_item setPosASL (AGLtoASL _emptyPosAGL); _item setPosASL (AGLtoASL _emptyPosAGL);
[_item, "blockDamage", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set); // Let objects remain invulernable for a short while after placement
[EFUNC(common,statusEffect_set), [_item, "blockDamage", QUOTE(ADDON), false], 2] call CBA_fnc_waitAndExecute;
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
[QGVAR(paradropItem), { [QGVAR(paradropItem), {
@ -166,3 +178,38 @@ if (isServer) then {
_bodyBag setVariable [QGVAR(customName), [_target, false, true] call EFUNC(common,getName), true]; _bodyBag setVariable [QGVAR(customName), [_target, false, true] call EFUNC(common,getName), true];
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
}; };
// Set variables, even on machines without interfaces, just to be safe
GVAR(selectedItem) = objNull;
GVAR(itemPreviewObject) = objNull;
GVAR(deployPFH) = -1;
GVAR(deployDistance) = -1;
GVAR(deployDirection) = 0;
GVAR(deployHeight) = 0;
GVAR(canDeploy) = false;
if (!hasInterface) exitWith {};
// Cancel object deployment if interact menu opened
["ace_interactMenuOpened", {ACE_player call FUNC(handleDeployInterrupt)}] call CBA_fnc_addEventHandler;
// Cancel deploy on player change. This does work when returning to lobby, but not when hard disconnecting
["unit", LINKFUNC(handleDeployInterrupt)] call CBA_fnc_addPlayerEventHandler;
["vehicle", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
["weapon", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
// When changing feature cameras, stop deployment
["featureCamera", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addPlayerEventHandler;
// Handle falling unconscious while trying to deploy
["ace_unconscious", {(_this select 0) call FUNC(handleDeployInterrupt)}] call CBA_fnc_addEventHandler;
// Handle surrendering and handcuffing
["ace_captiveStatusChanged", {
params ["_unit", "_state"];
// If surrendered or handcuffed, stop deployment
if (_state) then {
_unit call FUNC(handleDeployInterrupt);
};
}] call CBA_fnc_addEventHandler;

View File

@ -0,0 +1,39 @@
#include "..\script_component.hpp"
/*
* Author: Garth 'L-H' de Wet, Ruthberg, commy2, Smith
* Cancels unloading when deploying.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_deployCancel
*
* Public: No
*/
if (GVAR(deployPFH) == -1) exitWith {};
// Remove deployment pfh
GVAR(deployPFH) call CBA_fnc_removePerFrameHandler;
GVAR(deployPFH) = -1;
params ["_unit"];
// Enable running again
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
[_unit, "blockThrow", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
// Delete placement dummy
deleteVehicle GVAR(itemPreviewObject);
// Remove mouse button actions
call EFUNC(interaction,hideMouseHint);
[_unit, "DefaultAction", _unit getVariable [QGVAR(deploy), -1]] call EFUNC(common,removeActionEventHandler);
_unit setVariable [QGVAR(deploy), -1];
_unit setVariable [QGVAR(isDeploying), false, true];

View File

@ -0,0 +1,56 @@
#include "..\script_component.hpp"
/*
* Author: Garth 'L-H' de Wet, Ruthberg, commy2, Smith
* Confirms unloading when deploying.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_deployConfirm
*
* Public: No
*/
if (GVAR(deployPFH) == -1) exitWith {};
params ["_unit"];
// Delete placement dummy and unload real item from cargo at dummy position
if (!isNull GVAR(itemPreviewObject) && {[GVAR(selectedItem), GVAR(interactionVehicle), _unit, false, true] call FUNC(canUnloadItem)}) then {
// Position is AGL for unloading event
private _position = ASLToAGL getPosASL GVAR(itemPreviewObject);
private _direction = getDir GVAR(itemPreviewObject);
private _duration = GVAR(loadTimeCoefficient) * (GVAR(selectedItem) call FUNC(getSizeItem));
// If unload time is 0, don't show a progress bar
if (_duration <= 0) exitWith {
["ace_unloadCargo", [GVAR(selectedItem), GVAR(interactionVehicle), _unit, [_position, _direction]]] call CBA_fnc_localEvent;
};
[
_duration,
[GVAR(selectedItem), GVAR(interactionVehicle), _unit, [_position, _direction]],
{
TRACE_1("deploy finish",_this);
["ace_unloadCargo", _this select 0] call CBA_fnc_localEvent;
},
{
TRACE_1("deploy fail",_this);
},
format [LLSTRING(unloadingItem), [GVAR(selectedItem), true] call FUNC(getNameItem), getText (configOf GVAR(interactionVehicle) >> "displayName")],
{
(_this select 0) params ["_item", "_vehicle", "_unit"];
[_item, _vehicle, _unit, false, true] call FUNC(canUnloadItem) // don't check for a suitable unloading position when deploying
},
["isNotSwimming"]
] call EFUNC(common,progressBar);
};
// Cleanup EHs and preview object
_unit call FUNC(deployCancel);

View File

@ -0,0 +1,29 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal, Smith
* Get selected item from cargo menu.
*
* Arguments:
* None
*
* Return Value:
* Classname of selected item or selected object <STRING> or <OBJECT> (default: nil)
*
* Example:
* call ace_cargo_fnc_getSelectedItem
*
* Public: No
*/
disableSerialization;
private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith {};
private _loaded = GVAR(interactionVehicle) getVariable [QGVAR(loaded), []];
if (_loaded isEqualTo []) exitWith {};
// This can be an object or a classname string
_loaded param [lbCurSel (_display displayCtrl 100), nil]

View File

@ -0,0 +1,30 @@
#include "..\script_component.hpp"
/*
* Author: commy2, Smith
* Handle various interruption types.
*
* Arguments:
* 0: (New) unit <OBJECT>
* 1: Old unit (for player change) <OBJECT> (default: objNull)
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_handleDeployInterrupt
*
* Public: No
*/
params ["_newPlayer", ["_oldPlayer", objNull]];
TRACE_2("params",_newPlayer,_oldPlayer);
if (!local _newPlayer) exitWith {};
if (_newPlayer getVariable [QGVAR(isDeploying), false]) then {
_newPlayer call FUNC(deployCancel);
};
if (_oldPlayer getVariable [QGVAR(isDeploying), false]) then {
_oldPlayer call FUNC(deployCancel);
};

View File

@ -0,0 +1,58 @@
#include "..\script_component.hpp"
/*
* Author: L-H, commy2, Smith
* Handles rotation of object to unload.
*
* Arguments:
* 0: Scroll amount <NUMBER>
*
* Return Value:
* If the scroll was handled <BOOL>
*
* Example:
* 1.2 call ace_cargo_fnc_handleScrollWheel
*
* Public: No
*/
if (GVAR(deployPFH) == -1) exitWith {false};
params ["_scrollAmount"];
private _deployedItem = GVAR(itemPreviewObject);
if (!CBA_events_control) then {
private _unit = ACE_player;
// Raise/lower
// Move deployed item 15 cm per scroll interval
_scrollAmount = _scrollAmount * 0.15;
private _position = getPosASL _deployedItem;
private _maxHeight = (_unit modelToWorldVisualWorld [0, 0, 0]) select 2;
_position set [2, ((_position select 2) + _scrollAmount min (_maxHeight + 1.5)) max _maxHeight];
// Move up/down object and reattach at current position
detach _deployedItem;
// Uses this method of selecting position because setPosATL did not have immediate effect
private _positionChange = _position vectorDiff (getPosASL _deployedItem);
private _selectionPosition = _unit worldToModel (ASLtoAGL getPosWorld _deployedItem);
_selectionPosition = _selectionPosition vectorAdd _positionChange;
_deployedItem attachTo [_unit, _selectionPosition];
// Reset the deploy direction
private _direction = _deployedItem getVariable [QGVAR(deployDirection_temp), 0];
_deployedItem setDir _direction;
} else {
// Rotate
private _direction = _deployedItem getVariable [QGVAR(deployDirection_temp), 0];
_scrollAmount = _scrollAmount * 10;
_direction = _direction + _scrollAmount;
_deployedItem setDir _direction;
_deployedItem setVariable [QGVAR(deployDirection_temp), _direction];
};
true

View File

@ -22,11 +22,17 @@ private _type = typeOf _vehicle;
private _config = configOf _vehicle; private _config = configOf _vehicle;
// If vehicle had space given to it via eden/public, then override config hasCargo setting // If vehicle had space given to it via eden/public, then override config hasCargo setting
private _hasCargoPublic = _vehicle getVariable [QGVAR(hasCargo), false]; private _hasCargoPublic = _item getVariable QGVAR(hasCargo);
private _hasCargoPublicDefined = !isNil "_canLoadPublic";
if (_hasCargoPublicDefined && {!(_hasCargoPublic isEqualType false)}) then {
WARNING_4("%1[%2] - Variable %3 is %4 - Should be bool",_item,_type,QGVAR(hasCargo),_hasCargoPublic);
};
private _hasCargoConfig = getNumber (_config >> QGVAR(hasCargo)) == 1; private _hasCargoConfig = getNumber (_config >> QGVAR(hasCargo)) == 1;
// Nothing to do here if vehicle has no cargo space // Nothing to do here if vehicle has no cargo space
if !(_hasCargoConfig || _hasCargoPublic) exitWith {}; if !((_hasCargoPublicDefined && {_hasCargoPublic in [true, 1]}) || {!_hasCargoPublicDefined && {_hasCargoConfig}}) exitWith {};
// Check if cargo is in cargo holder types (checked when trying to search for loadable objects) // Check if cargo is in cargo holder types (checked when trying to search for loadable objects)
private _addCargoType = GVAR(cargoHolderTypes) findIf {_type isKindOf _x} == -1; private _addCargoType = GVAR(cargoHolderTypes) findIf {_type isKindOf _x} == -1;

View File

@ -25,6 +25,9 @@ if (GVAR(interactionParadrop)) then {
(_display displayCtrl 12) ctrlSetText LLSTRING(paradropButton); (_display displayCtrl 12) ctrlSetText LLSTRING(paradropButton);
}; };
// Disable deploy option if paradropping or in Zeus
(_display displayCtrl 13) ctrlEnable (GVAR(enableDeploy) && !GVAR(interactionParadrop) && {isNull curatorCamera});
[{ [{
params ["_vehicle", "_pfhID"]; params ["_vehicle", "_pfhID"];
@ -33,7 +36,6 @@ if (GVAR(interactionParadrop)) then {
private _display = uiNamespace getVariable QGVAR(menuDisplay); private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith { if (isNil "_display") exitWith {
GVAR(interactionVehicle) = nil;
GVAR(interactionParadrop) = nil; GVAR(interactionParadrop) = nil;
_pfhID call CBA_fnc_removePerFrameHandler; _pfhID call CBA_fnc_removePerFrameHandler;
@ -41,18 +43,18 @@ if (GVAR(interactionParadrop)) then {
// Close menu if in invalid state // Close menu if in invalid state
if ( if (
!alive _vehicle || !alive ACE_player ||
{!alive _vehicle} ||
{locked _vehicle >= 2} || {locked _vehicle >= 2} ||
{!(_vehicle getVariable [QGVAR(hasCargo), true])} || // if the cargo menu could be opened, the vehicle has QGVAR(hasCargo) in its config or the variable is set using FUNC(setSpace) {!(_vehicle getVariable [QGVAR(hasCargo), true])} || // if the cargo menu could be opened, the vehicle has QGVAR(hasCargo) in its config or the variable is set using FUNC(setSpace)
{ {
isNull findDisplay 312 && // if in Zeus, ignore the following checks isNull curatorCamera && // if in Zeus, ignore the checks that follow
{([ACE_player, _vehicle] call EFUNC(interaction,getInteractionDistance)) >= MAX_LOAD_DISTANCE} && {([ACE_player, _vehicle] call EFUNC(interaction,getInteractionDistance)) >= MAX_LOAD_DISTANCE} &&
{(vehicle ACE_player) != _vehicle} {(vehicle ACE_player) != _vehicle}
} }
) exitWith { ) exitWith {
closeDialog 0; closeDialog 0;
GVAR(interactionVehicle) = nil;
GVAR(interactionParadrop) = nil; GVAR(interactionParadrop) = nil;
_pfhID call CBA_fnc_removePerFrameHandler; _pfhID call CBA_fnc_removePerFrameHandler;

View File

@ -0,0 +1,86 @@
#include "..\script_component.hpp"
/*
* Author: Garth 'L-H' de Wet, Ruthberg, commy2, Smith
* Starts the deploy process for unloading an object.
*
* Arguments:
* 0: Unit deploying <OBJECT>
*
* Return Value:
* None
*
* Example:
* player call ace_cargo_fnc_startDeploy
*
* Public: No
*/
// Deny creating preview item as it will destroy player vehicle instantly by collision
if (GVAR(interactionParadrop)) exitWith {};
params ["_unit"];
// Don't allow deploying if already deploying
if (_unit getVariable [QGVAR(isDeploying), false]) exitWith {};
// This can be an object or a classname string
private _item = call FUNC(getSelectedItem);
if (isNil "_item") exitWith {};
// Close opened cargo menu
closeDialog 0;
GVAR(selectedItem) = _item;
private _classname = _item;
if (_classname isEqualType objNull) then {
_classname = typeOf _classname;
};
// Prevent the placing unit from running
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
// Create a local preview object
private _itemPreviewObject = createVehicleLocal [_classname, [0, 0, 0], [], 0, "CAN_COLLIDE"];
GVAR(itemPreviewObject) = _itemPreviewObject;
// Prevent collisions with object
_itemPreviewObject disableCollisionWith _unit;
_itemPreviewObject enableSimulation false;
_itemPreviewObject setMass 1e-12;
// Detect radius of zone where collision can damage the player
private _itemPreviewObjectRadius = 1 max ((boundingBoxReal [_itemPreviewObject, "FireGeometry"]) select 2);
// Add height offset of model
private _offset = ((_itemPreviewObject modelToWorldVisual [0, 0, 0]) select 2) - ((_unit modelToWorldVisual [0, 0, 0]) select 2) + 1;
// Attach object
_itemPreviewObject attachTo [_unit, [0, 1.5 * _itemPreviewObjectRadius, _offset]];
// PFH that runs while the deployment is in progress
GVAR(deployPFH) = [{
(_this select 0) params ["_unit", "_vehicle", "_item", "_itemPreviewObject"];
if !(
!isNull _itemPreviewObject &&
{[_item, _vehicle, _unit, false, true] call FUNC(canUnloadItem)} // don't check for a suitable unloading position when deploying
) exitWith {
_unit call FUNC(deployCancel);
};
}, 0.5, [_unit, GVAR(interactionVehicle), _item, _itemPreviewObject]] call CBA_fnc_addPerFrameHandler;
// Add mouse button action and hint
[LLSTRING(unloadObject), localize "STR_DISP_CANCEL", LLSTRING(scrollAction)] call EFUNC(interaction,showMouseHint);
_unit setVariable [QGVAR(deploy), [
_unit, "DefaultAction",
{GVAR(deployPFH) != -1},
{[_this select 0] call FUNC(deployConfirm)}
] call EFUNC(common,addActionEventHandler)];
_unit setVariable [QGVAR(isDeploying), true, true];

View File

@ -15,18 +15,8 @@
* Public: No * Public: No
*/ */
disableSerialization;
private _display = uiNamespace getVariable QGVAR(menuDisplay);
if (isNil "_display") exitWith {};
private _loaded = GVAR(interactionVehicle) getVariable [QGVAR(loaded), []];
if (_loaded isEqualTo []) exitWith {};
// This can be an object or a classname string // This can be an object or a classname string
private _item = _loaded param [lbCurSel (_display displayCtrl 100), nil]; private _item = call FUNC(getSelectedItem);
if (isNil "_item") exitWith {}; if (isNil "_item") exitWith {};
@ -60,11 +50,11 @@ if (GVAR(interactionParadrop)) exitWith {
}, },
format [LLSTRING(unloadingItem), [_item, true] call FUNC(getNameItem), getText (configOf GVAR(interactionVehicle) >> "displayName")], format [LLSTRING(unloadingItem), [_item, true] call FUNC(getNameItem), getText (configOf GVAR(interactionVehicle) >> "displayName")],
{ {
(_this select 0) params ["", "_target"]; (_this select 0) params ["", "_vehicle"];
if ((acos ((vectorUp _target) select 2)) > 30) exitWith {false}; // check flight level if ((acos ((vectorUp _vehicle) select 2)) > 30) exitWith {false}; // check flight level
if (((getPos _target) select 2) < 25) exitWith {false}; // check height if (((getPos _vehicle) select 2) < 25) exitWith {false}; // check height
if ((speed _target) < -5) exitWith {false}; // check reverse if ((speed _vehicle) < -5) exitWith {false}; // check reverse
true true
}, },
@ -74,7 +64,7 @@ if (GVAR(interactionParadrop)) exitWith {
}; };
// If in zeus // If in zeus
if (!isNull findDisplay 312) exitWith { if (!isNull curatorCamera) exitWith {
// Do not check distance to unit, but do check for valid position // Do not check distance to unit, but do check for valid position
if !([_item, GVAR(interactionVehicle), objNull, true] call FUNC(canUnloadItem)) exitWith { if !([_item, GVAR(interactionVehicle), objNull, true] call FUNC(canUnloadItem)) exitWith {
[[LSTRING(unloadingFailed), [_item, true] call FUNC(getNameItem)], 3] call EFUNC(common,displayTextStructured); [[LSTRING(unloadingFailed), [_item, true] call FUNC(getNameItem)], 3] call EFUNC(common,displayTextStructured);

View File

@ -7,6 +7,9 @@
* 0: Item to be unloaded <STRING> or <OBJECT> (default: "") * 0: Item to be unloaded <STRING> or <OBJECT> (default: "")
* 1: Holder object (vehicle) <OBJECT> (default: objNull) * 1: Holder object (vehicle) <OBJECT> (default: objNull)
* 2: Unloader <OBJECT> (default: objNull) * 2: Unloader <OBJECT> (default: objNull)
* 3: Deploy parameters <ARRAY> (default: [])
* - 0: Position AGL <ARRAY>
* - 1: Direction <NUMBER>
* *
* Return Value: * Return Value:
* Object unloaded <BOOL> * Object unloaded <BOOL>
@ -17,8 +20,10 @@
* Public: Yes * Public: Yes
*/ */
params [["_item", "", [objNull, ""]], ["_vehicle", objNull, [objNull]], ["_unloader", objNull, [objNull]]]; params [["_item", "", [objNull, ""]], ["_vehicle", objNull, [objNull]], ["_unloader", objNull, [objNull]], ["_deploy", []]];
TRACE_3("params",_item,_vehicle,_unloader); _deploy params ["_emptyPosAGL", "_direction"];
TRACE_4("params",_item,_vehicle,_unloader,_deploy);
// Get config sensitive case name // Get config sensitive case name
if (_item isEqualType "") then { if (_item isEqualType "") then {
@ -41,9 +46,18 @@ if (_itemSize < 0) exitWith {
false // return false // return
}; };
// This covers testing vehicle stability and finding a safe position private _deployed = _deploy isNotEqualTo [];
private _emptyPosAGL = [_vehicle, _item, _unloader] call EFUNC(common,findUnloadPosition);
TRACE_1("findUnloadPosition",_emptyPosAGL); if (!_deployed) then {
// This covers testing vehicle stability and finding a safe position
for "_i" from 1 to 3 do {
_emptyPosAGL = [_vehicle, _item, _unloader] call EFUNC(common,findUnloadPosition);
if (_emptyPosAGL isNotEqualTo []) exitWith {};
};
TRACE_1("findUnloadPosition",_emptyPosAGL);
};
if (_emptyPosAGL isEqualTo []) exitWith { if (_emptyPosAGL isEqualTo []) exitWith {
// Display text saying there are no safe places to exit the vehicle // Display text saying there are no safe places to exit the vehicle
@ -67,9 +81,12 @@ private _object = _item;
if (_object isEqualType objNull) then { if (_object isEqualType objNull) then {
detach _object; detach _object;
// hideObjectGlobal must be executed before setPos to ensure light objects are rendered correctly // If player unloads via deployment, set direction first, then unload
// Do both on server to ensure they are executed in the correct order if (_deployed) then {
[QGVAR(serverUnload), [_object, _emptyPosAGL]] call CBA_fnc_serverEvent; [QGVAR(setDirAndUnload), [_object, _emptyPosAGL, _direction], _object] call CBA_fnc_targetEvent;
} else {
[QGVAR(serverUnload), [_object, _emptyPosAGL]] call CBA_fnc_serverEvent;
};
if (["ace_zeus"] call EFUNC(common,isModLoaded)) then { if (["ace_zeus"] call EFUNC(common,isModLoaded)) then {
// Get which curators had this object as editable // Get which curators had this object as editable
@ -81,6 +98,12 @@ if (_object isEqualType objNull) then {
}; };
} else { } else {
_object = createVehicle [_item, _emptyPosAGL, [], 0, "NONE"]; _object = createVehicle [_item, _emptyPosAGL, [], 0, "NONE"];
// If player unloads via deployment, set direction. Must happen before setPosASL command according to wiki
if (_deployed) then {
_object setDir _direction;
};
_object setPosASL (AGLtoASL _emptyPosAGL); _object setPosASL (AGLtoASL _emptyPosAGL);
[QEGVAR(common,fixCollision), _object] call CBA_fnc_localEvent; [QEGVAR(common,fixCollision), _object] call CBA_fnc_localEvent;
@ -88,7 +111,9 @@ if (_object isEqualType objNull) then {
}; };
// Dragging integration // Dragging integration
[_unloader, _object] call FUNC(unloadCarryItem); if (!_deployed) then {
[_unloader, _object] call FUNC(unloadCarryItem);
};
// Invoke listenable event // Invoke listenable event
["ace_cargoUnloaded", [_object, _vehicle, "unload"]] call CBA_fnc_globalEvent; ["ace_cargoUnloaded", [_object, _vehicle, "unload"]] call CBA_fnc_globalEvent;

View File

@ -6,7 +6,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(ModuleSettings_enable), LSTRING(ModuleSettings_enable_Description)], [LSTRING(ModuleSettings_enable), LSTRING(ModuleSettings_enable_Description)],
_category, _category,
true, true,
true, 1,
{[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(enable), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
@ -16,7 +16,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(loadTimeCoefficient), LSTRING(loadTimeCoefficient_description)], [LSTRING(loadTimeCoefficient), LSTRING(loadTimeCoefficient_description)],
_category, _category,
[0, 10, 5, 1], [0, 10, 5, 1],
true, 1,
{[QGVAR(loadTimeCoefficient), _this, true] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(loadTimeCoefficient), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
@ -26,7 +26,7 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(paradropTimeCoefficent), LSTRING(paradropTimeCoefficent_description)], [LSTRING(paradropTimeCoefficent), LSTRING(paradropTimeCoefficent_description)],
_category, _category,
[0, 10, 2.5, 1], [0, 10, 2.5, 1],
true, 1,
{[QGVAR(paradropTimeCoefficent), _this, true] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(paradropTimeCoefficent), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
@ -36,26 +36,36 @@ private _category = [ELSTRING(main,Category_Logistics), LSTRING(openMenu)];
[LSTRING(openAfterUnload), LSTRING(openAfterUnload_description)], [LSTRING(openAfterUnload), LSTRING(openAfterUnload_description)],
_category, _category,
[[0, 1, 2, 3], [ELSTRING(common,never), LSTRING(unloadObject), LSTRING(paradropButton), ELSTRING(common,both)], 0], [[0, 1, 2, 3], [ELSTRING(common,never), LSTRING(unloadObject), LSTRING(paradropButton), ELSTRING(common,both)], 0],
false, 0,
{[QGVAR(openAfterUnload), _this, true] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(openAfterUnload), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[
QGVAR(enableRename),
"CHECKBOX",
[LSTRING(ModuleSettings_enableRename), LSTRING(ModuleSettings_enableRename_Description)],
_category,
true,
false,
{[QGVAR(enableRename), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[ [
QGVAR(carryAfterUnload), QGVAR(carryAfterUnload),
"CHECKBOX", "CHECKBOX",
[LSTRING(carryAfterUnload), LSTRING(carryAfterUnload_description)], [LSTRING(carryAfterUnload), LSTRING(carryAfterUnload_description)],
_category, _category,
true, true,
false, 0,
{[QGVAR(carryAfterUnload), _this] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(carryAfterUnload), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] call CBA_fnc_addSetting;
[
QGVAR(enableDeploy),
"CHECKBOX",
[LSTRING(enableDeploy), LSTRING(enableDeploy_description)],
_category,
true,
1,
{[QGVAR(enableDeploy), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;
[
QGVAR(enableRename),
"CHECKBOX",
[LSTRING(ModuleSettings_enableRename), LSTRING(ModuleSettings_enableRename_Description)],
_category,
true,
0,
{[QGVAR(enableRename), _this, true] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting;

View File

@ -17,7 +17,7 @@ class GVAR(menu) {
}; };
class CenterBackground: HeaderBackground { class CenterBackground: HeaderBackground {
y = "2.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; y = "2.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)";
h = "13.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; h = "14.2 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
text = "#(argb,8,8,3)color(0,0,0,0.8)"; text = "#(argb,8,8,3)color(0,0,0,0.8)";
colorText[] = {0, 0, 0, "(profilenamespace getVariable ['GUI_BCG_RGB_A',0.9])"}; colorText[] = {0, 0, 0, "(profilenamespace getVariable ['GUI_BCG_RGB_A',0.9])"};
colorBackground[] = {0, 0, 0, "(profilenamespace getVariable ['GUI_BCG_RGB_A',0.9])"}; colorBackground[] = {0, 0, 0, "(profilenamespace getVariable ['GUI_BCG_RGB_A',0.9])"};
@ -72,7 +72,7 @@ class GVAR(menu) {
idc = 11; idc = 11;
x = "13.1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; x = "13.1 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)";
y = "14.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)"; y = "14.1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)";
w = "5 * (((safezoneW / safezoneH) min 1.2) / 40)"; w = "6 * (((safezoneW / safezoneH) min 1.2) / 40)";
h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)"; h = "1 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25)";
size = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)"; size = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)";
SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 0.7)"; SizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 0.7)";
@ -96,8 +96,15 @@ class GVAR(menu) {
class btnUnload: btnCancel { class btnUnload: btnCancel {
text = CSTRING(unloadObject); text = CSTRING(unloadObject);
idc = 12; idc = 12;
x = "20.9 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)"; x = "19.9 * (((safezoneW / safezoneH) min 1.2) / 40) + (safezoneX + (safezoneW - ((safezoneW / safezoneH) min 1.2))/2)";
action = QUOTE(ACE_player call FUNC(startUnload)); action = QUOTE(ACE_player call FUNC(startUnload));
}; };
class btnPlace: btnUnload {
text = CSTRING(deployObject);
idc = 13;
y = "15.2 * ((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) + (safezoneY + (safezoneH - (((safezoneW / safezoneH) min 1.2) / 1.2))/2)";
action = QUOTE(ACE_player call FUNC(startDeploy));
colorDisabled[] = {0.25, 0.25, 0.25, 1};
};
}; };
}; };

View File

@ -33,6 +33,40 @@
<Chinesesimp>卸载</Chinesesimp> <Chinesesimp>卸载</Chinesesimp>
<Turkish>Boşalt</Turkish> <Turkish>Boşalt</Turkish>
</Key> </Key>
<Key ID="STR_ACE_Cargo_deployObject">
<English>Deploy</English>
</Key>
<Key ID="STR_ACE_Cargo_ScrollAction">
<English>Raise/Lower | (Ctrl + Scroll) Rotate</English>
<German>Heben/Senken | (Strg + Scrollen) Drehen</German>
<Italian>Alza/Abbassa | (Ctrl + Rotellina) Ruota</Italian>
<French>Lever/Baisser | (Ctrl + Scroll) Rotation</French>
<Japanese>上げる/下げる | (Ctrl + スクロール) 回転</Japanese>
<Czech>Zvednout/Snížit | (Ctrl + Kolečko myši) Otáčet</Czech>
<Russian>Поднять/опустить | (Ctrl + Скролл) Крутить</Russian>
<Polish>Wyżej/niżej | (Ctrl + Kółko myszy) obracanie</Polish>
<Turkish>Yükselt/Alçalt | (Ctrl + Tekerlek) Döndür</Turkish>
<Spanish>Subir/Bajar | (Ctrl + Scroll) Rotar</Spanish>
<Chinesesimp>抬起/放低 |Ctrl + 鼠标滚轮)旋转</Chinesesimp>
<Korean>높이기/내리기 | (컨트롤 + 스크롤) 회전</Korean>
<Portuguese>Subir/Abaixar | (Ctrl + Scroll) Rotacionar</Portuguese>
</Key>
<Key ID="STR_ACE_Cargo_BlockedAction">
<English>Blocked</English>
<Spanish>Obstruido</Spanish>
<Portuguese>Bloqueado</Portuguese>
<Russian>Заблокировано</Russian>
<Czech>Blokováno</Czech>
<Polish>Zablokowany</Polish>
<Italian>Bloccato</Italian>
<German>Blockiert</German>
<French>Bloqué</French>
<Japanese>取り付け不可</Japanese>
<Korean>막힘</Korean>
<Chinesesimp>断开</Chinesesimp>
<Chinese>斷開</Chinese>
<Turkish>Bloke Edilmiş</Turkish>
</Key>
<Key ID="STR_ACE_Cargo_renamedObject"> <Key ID="STR_ACE_Cargo_renamedObject">
<English>Renamed to:&lt;br/&gt;%1</English> <English>Renamed to:&lt;br/&gt;%1</English>
<Japanese>名前を次に変更:&lt;br/&gt;%1</Japanese> <Japanese>名前を次に変更:&lt;br/&gt;%1</Japanese>
@ -528,5 +562,11 @@
<French>Active si les éléments de cargaison sont portés ou traînés après le déchargement.</French> <French>Active si les éléments de cargaison sont portés ou traînés après le déchargement.</French>
<Portuguese>Controla se os itens de carga são carregados ou arrastados após a descarga.</Portuguese> <Portuguese>Controla se os itens de carga são carregados ou arrastados após a descarga.</Portuguese>
</Key> </Key>
<Key ID="STR_ACE_Cargo_enableDeploy">
<English>Enable deploy</English>
</Key>
<Key ID="STR_ACE_Cargo_enableDeploy_description">
<English>Controls whether cargo items can be unloaded via the deploy method.</English>
</Key>
</Package> </Package>
</Project> </Project>

View File

@ -4,7 +4,7 @@ class CfgVehicles {
class ACE_SelfActions { class ACE_SelfActions {
class GVAR(deploy) { class GVAR(deploy) {
displayName = CSTRING(PlaceTripod_displayName); displayName = CSTRING(PlaceTripod_displayName);
condition = QUOTE(call FUNC(assemble_canDeployTripod)); condition = QUOTE(call FUNC(canDeployTripod));
statement = QUOTE(call FUNC(assemble_deployTripod)); statement = QUOTE(call FUNC(assemble_deployTripod));
exceptions[] = {}; exceptions[] = {};
}; };
@ -36,7 +36,7 @@ class CfgVehicles {
condition = "true"; condition = "true";
class GVAR(pickUp) { class GVAR(pickUp) {
displayName = CSTRING(Pickup_displayName); displayName = CSTRING(Pickup_displayName);
condition = QUOTE(call FUNC(assemble_canPickupTripod)); condition = QUOTE(call FUNC(canPickupTripod));
statement = QUOTE(call FUNC(assemble_pickupTripod)); statement = QUOTE(call FUNC(assemble_pickupTripod));
}; };
class GVAR(mountWeapon) { class GVAR(mountWeapon) {
@ -125,10 +125,11 @@ class CfgVehicles {
class StaticWeapon: LandVehicle { class StaticWeapon: LandVehicle {
class ACE_Actions { class ACE_Actions {
class ACE_MainActions { class ACE_MainActions {
// Workaround for static weapons' Get In memory point being at the front of the gun
class GVAR(getIn) { class GVAR(getIn) {
displayName = CSTRING(GetIn_displayName); displayName = CSTRING(GetIn_displayName);
condition = QUOTE(call FUNC(canGetIn)); condition = QUOTE(call FUNC(canGetIn));
statement = QUOTE(call FUNC(getIn)); statement = QUOTE(_player moveInTurret [ARR_2(_target,[0])]);
}; };
}; };
}; };

View File

@ -6,9 +6,9 @@ PREP(ai_handleFired);
PREP(ai_handleGetIn); PREP(ai_handleGetIn);
PREP(ai_reload); PREP(ai_reload);
PREP(assemble_canDeployTripod); PREP(canDeployTripod);
PREP(assemble_canDeployWeapon); PREP(assemble_canDeployWeapon);
PREP(assemble_canPickupTripod); PREP(canPickupTripod);
PREP(assemble_canPickupWeapon); PREP(assemble_canPickupWeapon);
PREP(assemble_deployTripod); PREP(assemble_deployTripod);
PREP(assemble_deployWeapon); PREP(assemble_deployWeapon);
@ -17,13 +17,12 @@ PREP(assemble_pickupTripod);
PREP(assemble_pickupWeapon); PREP(assemble_pickupWeapon);
PREP(canGetIn); PREP(canGetIn);
PREP(getIn);
PREP(getCarryMagazine); PREP(getCarryMagazine);
PREP(proxyWeapon); PREP(proxyWeapon);
PREP(reload_actionsLoad); PREP(getLoadActions);
PREP(reload_actionsUnload); PREP(getUnloadActions);
PREP(reload_canLoadMagazine); PREP(reload_canLoadMagazine);
PREP(reload_canUnloadMagazine); PREP(reload_canUnloadMagazine);
PREP(reload_getLoadableMagazines); PREP(reload_getLoadableMagazines);
@ -33,5 +32,5 @@ PREP(reload_handleRemoveTurretMag);
PREP(reload_handleReturnAmmo); PREP(reload_handleReturnAmmo);
PREP(reload_loadMagazine); PREP(reload_loadMagazine);
PREP(staticWeaponInit); PREP(initVehicle);
PREP(staticWeaponInit_unloadExtraMags); PREP(staticWeaponInit_unloadExtraMags);

View File

@ -6,18 +6,27 @@ GVAR(vehicleMagCache) = createHashMap;
TRACE_3("settingsInit",GVAR(defaultAssemblyMode),GVAR(handleExtraMagazines),GVAR(ammoHandling)); TRACE_3("settingsInit",GVAR(defaultAssemblyMode),GVAR(handleExtraMagazines),GVAR(ammoHandling));
["StaticWeapon", "Init", { ["StaticWeapon", "Init", {
// needs a small delay for network syncing, or we end up with duplicate mags with ammo handling // needs a small delay for network syncing, or we end up with duplicate mags with ammo handling
[LINKFUNC(staticWeaponInit), _this, 1] call CBA_fnc_waitAndExecute; [LINKFUNC(initVehicle), _this, 1] call CBA_fnc_waitAndExecute;
}, true, [], true] call CBA_fnc_addClassEventHandler; }, true, [], true] call CBA_fnc_addClassEventHandler;
GVAR(quickmountEnabled) = (
missionNamespace getVariable [QEGVAR(quickmount,enabled), false] &&
{(missionNamespace getVariable [QEGVAR(quickmount,enableMenu), -1]) in [1,3]}
);
}] call CBA_fnc_addEventHandler; }] call CBA_fnc_addEventHandler;
["CBA_SettingChanged", {
GVAR(quickmountEnabled) = (
missionNamespace getVariable [QEGVAR(quickmount,enabled), false] &&
{(missionNamespace getVariable [QEGVAR(quickmount,enableMenu), -1]) in [1,3]}
);
}] call CBA_fnc_addEventHandler;
// Event handlers: // Event handlers:
[QGVAR(addTurretMag), LINKFUNC(reload_handleAddTurretMag)] call CBA_fnc_addEventHandler; [QGVAR(addTurretMag), LINKFUNC(reload_handleAddTurretMag)] call CBA_fnc_addEventHandler;
[QGVAR(removeTurretMag), LINKFUNC(reload_handleRemoveTurretMag)] call CBA_fnc_addEventHandler; [QGVAR(removeTurretMag), LINKFUNC(reload_handleRemoveTurretMag)] call CBA_fnc_addEventHandler;
[QGVAR(returnAmmo), LINKFUNC(reload_handleReturnAmmo)] call CBA_fnc_addEventHandler; [QGVAR(returnAmmo), LINKFUNC(reload_handleReturnAmmo)] call CBA_fnc_addEventHandler;
#ifdef DEBUG_MODE_FULL #ifdef DEBUG_MODE_FULL
call compile preprocessFileLineNumbers QPATHTOF(dev\checkStaticWeapons.sqf); call compile preprocessFileLineNumbers QPATHTOF(dev\checkStaticWeapons.sqf);
#endif #endif

View File

@ -7,14 +7,14 @@ INFO("Checking static weapons");
private _staticWeaponConfigs = configProperties [configFile >> "CfgVehicles", "(isClass _x) && {(configName _x) isKindOf 'StaticWeapon'}", true]; private _staticWeaponConfigs = configProperties [configFile >> "CfgVehicles", "(isClass _x) && {(configName _x) isKindOf 'StaticWeapon'}", true];
private _staticPublic = _staticWeaponConfigs select {(getNumber (_x >> "scope")) == 2}; private _staticPublic = _staticWeaponConfigs select {(getNumber (_x >> "scope")) == 2};
INFO_2("Static Weapons [%1] - CSW Enabled [%2]",count _staticPublic,{(getNumber (_x >> "ace_csw" >> "enabled")) == 1} count _staticPublic); INFO_2("Static Weapons [%1] - CSW Enabled [%2]",count _staticPublic,{(getNumber (_x >> QUOTE(ADDON) >> "enabled")) == 1} count _staticPublic);
INFO("------ Checking static weapons inheritance ------"); INFO("------ Checking static weapons inheritance ------");
private _explicitBases = []; private _explicitBases = [];
private _inherited = []; private _inherited = [];
{ {
private _config = _x; private _config = _x;
private _configEnabled = (getNumber (_config >> "ace_csw" >> "enabled")) == 1; private _configEnabled = (getNumber (_config >> QUOTE(ADDON) >> "enabled")) == 1;
if (_configEnabled) then { if (_configEnabled) then {
private _configExplicit = (count configProperties [_config, "configName _x == 'ace_csw'", false]) == 1; private _configExplicit = (count configProperties [_config, "configName _x == 'ace_csw'", false]) == 1;
if (_configExplicit) then { if (_configExplicit) then {
@ -69,7 +69,7 @@ private _logAll = false;
{ {
//IGNORE_PRIVATE_WARNING ["_x", "_y"]; //IGNORE_PRIVATE_WARNING ["_x", "_y"];
INFO_2("[%1] has no carry varient - Used in %2",_x,_y); INFO_2("[%1] has no carry variant - Used in %2",_x,_y);
} forEach _hash; } forEach _hash;
INFO("------ End -------"); INFO("------ End -------");

View File

@ -12,12 +12,12 @@
* Public: No * Public: No
*/ */
params ["_staticWeapon", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"]; params ["_vehicle", "_weapon", "", "", "", "_magazine", "", "_gunner"];
TRACE_8("firedEH:",_staticWeapon,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile,_gunner); TRACE_4("firedEH:",_vehicle,_weapon,_magazine,_gunner);
if (someAmmo _vehicle) exitWith {};
if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {}; if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {};
if (someAmmo _staticWeapon) exitWith {};
TRACE_2("need ammo",someAmmo _staticWeapon,magazinesAllTurrets _staticWeapon); TRACE_1("need ammo",magazinesAllTurrets _vehicle);
[_staticWeapon, _gunner, _weapon, _magazine] call FUNC(ai_reload); [_vehicle, _gunner, _weapon, _magazine] call FUNC(ai_reload);

View File

@ -11,12 +11,13 @@
* *
* Public: No * Public: No
*/ */
params ["_staticWeapon", "_role", "_gunner"];
TRACE_3("getInEH:",_staticWeapon,_role,_gunner);
params ["_vehicle", "", "_gunner"];
TRACE_2("getInEH:",_vehicle,_gunner);
if (someAmmo _vehicle) exitWith {};
if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {}; if ((!local _gunner) || {[_gunner] call EFUNC(common,isPlayer)}) exitWith {};
if (someAmmo _staticWeapon) exitWith {};
TRACE_2("need ammo",someAmmo _staticWeapon,magazinesAllTurrets _staticWeapon); TRACE_1("need ammo",magazinesAllTurrets _vehicle);
[_staticWeapon, _gunner, currentWeapon _staticWeapon] call FUNC(ai_reload); [_vehicle, _gunner, currentWeapon _vehicle] call FUNC(ai_reload);

View File

@ -14,6 +14,7 @@
* *
* Public: No * Public: No
*/ */
params ["_staticWeapon", "_gunner", "_weapon", ["_magazine", ""]]; params ["_staticWeapon", "_gunner", "_weapon", ["_magazine", ""]];
private _turretPath = [_gunner] call EFUNC(common,getTurretIndex); private _turretPath = [_gunner] call EFUNC(common,getTurretIndex);

View File

@ -1,21 +0,0 @@
#include "..\script_component.hpp"
/*
* Author:tcvm
* Checks if the player can deploy the tripod.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* Can deploy <BOOL>
*
* Example:
* [player] call ace_csw_fnc_assemble_canDeployTripod
*
* Public: No
*/
params ["_player"];
(getText(configFile >> "CfgWeapons" >> (secondaryWeapon _player) >> QUOTE(ADDON) >> "type") == "mount")

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* Checks if you can deploy a weapon on the tripod * Checks if you can deploy a weapon on the tripod
* *
* Arguments: * Arguments:
@ -22,4 +22,3 @@ if (isNil "_carryWeaponClassname") then { _carryWeaponClassname = secondaryWeapo
// If the current launcher has a config-value that defines the tripod, it is a CSW // If the current launcher has a config-value that defines the tripod, it is a CSW
(alive _target) && (alive _target) &&
{(getText(configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "assembleTo" >> (typeOf _target))) != ""} {(getText(configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "assembleTo" >> (typeOf _target))) != ""}

View File

@ -1,22 +0,0 @@
#include "..\script_component.hpp"
/*
* Author:tcvm
* Checks if the player can pick-up the tripod.
*
* Arguments:
* 0: Tripod <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* Can pickup <BOOL>
*
* Example:
* [tripod, player] call ace_csw_fnc_assemble_canPickupTripod
*
* Public: No
*/
params ["_tripod", "_player"];
((secondaryWeapon _player) isEqualTo "") && {alive _tripod}

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* If the CSW is mounted or in use this will not allow you to dismount the weapon * If the CSW is mounted or in use this will not allow you to dismount the weapon
* *
* Arguments: * Arguments:
@ -23,4 +23,3 @@ private _notCrewed = (crew _staticWeapon) isEqualTo [];
private _deadCrew = !(alive (gunner _staticWeapon)); // need to eject body??? private _deadCrew = !(alive (gunner _staticWeapon)); // need to eject body???
_assemblyMode && {_notCrewed || _deadCrew} _assemblyMode && {_notCrewed || _deadCrew}

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* Deploys the tripod * Deploys the tripod
* *
* Arguments: * Arguments:
@ -40,7 +40,7 @@
_cswTripod setVariable [QGVAR(secondaryWeaponMagazine), _secondaryWeaponMagazine]; _cswTripod setVariable [QGVAR(secondaryWeaponMagazine), _secondaryWeaponMagazine];
}; };
if (!GVAR(defaultAssemblyMode)) then { if (!GVAR(defaultAssemblyMode)) then {
[_cswTripod, "disableWeaponAssembly", "ace_csw", true] call EFUNC(common,statusEffect_set); [_cswTripod, "disableWeaponAssembly", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
}; };
private _posATL = _player getRelPos [2, 0]; private _posATL = _player getRelPos [2, 0];

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* Deploys the current CSW * Deploys the current CSW
* *
* Arguments: * Arguments:

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* Picks up the tripod and adds it to the player launcher slot * Picks up the tripod and adds it to the player launcher slot
* *
* Arguments: * Arguments:
@ -44,4 +44,3 @@
TRACE_3("",_pickupTime,typeOf _tripod,_tripodClassname); TRACE_3("",_pickupTime,typeOf _tripod,_tripodClassname);
[TIME_PROGRESSBAR(_pickupTime), [_tripod, _player, _tripodClassname], _onFinish, {}, localize LSTRING(PickupTripod_progressBar), _condition] call EFUNC(common,progressBar); [TIME_PROGRESSBAR(_pickupTime), [_tripod, _player, _tripodClassname], _onFinish, {}, localize LSTRING(PickupTripod_progressBar), _condition] call EFUNC(common,progressBar);
}, _this] call CBA_fnc_execNextFrame; }, _this] call CBA_fnc_execNextFrame;

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* Dismounts the weapon from the tripod and drops its backpack beside * Dismounts the weapon from the tripod and drops its backpack beside
* *
* Arguments: * Arguments:

View File

@ -0,0 +1,22 @@
#include "..\script_component.hpp"
/*
* Author: tcvm
* Checks if the unit can deploy a tripod
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* Can deploy <BOOL>
*
* Example:
* player call ace_csw_fnc_canDeployTripod
*
* Public: No
*/
params ["_unit"];
private _secondaryWeapon = secondaryWeapon _unit;
_secondaryWeapon != "" && {getText (configFile >> "CfgWeapons" >> _secondaryWeapon >> QUOTE(ADDON) >> "type") == "mount"} // return

View File

@ -1,28 +1,23 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* Checks if the player can get in the weapon * Checks if it's possible to get in the CSW
* *
* Arguments: * Arguments:
* 0: Static Weapon <OBJECT> * 0: Vehicle <OBJECT>
* *
* Return Value: * Return Value:
* None * None
* *
* Example: * Example:
* [cursorObject] call ace_csw_fnc_canGetIn * cursorObject call ace_csw_fnc_canGetIn
* *
* Public: No * Public: No
*/ */
// hide this action if quick mount is enabled // Hide this action if quick mount is enabled
if ((missionNamespace getVariable [QEGVAR(quickmount,enabled), false]) && {(missionNamespace getVariable [QEGVAR(quickmount,enableMenu), -1]) in [1, 3]}) exitWith { if (GVAR(quickmountEnabled)) exitWith {false};
false
};
params ["_staticWeapon"]; params ["_vehicle"];
alive _staticWeapon alive _vehicle && {!(alive (gunner _vehicle))} && {(locked _vehicle) < 2} && {!(_vehicle lockedTurret [0])} && {0.3 < ((vectorUp _vehicle) select 2)} // return
&& {!(alive (gunner _staticWeapon))}
&& {(locked _staticWeapon) < 2}
&& {0.3 < ((vectorUp _staticWeapon) select 2)}

View File

@ -0,0 +1,21 @@
#include "..\script_component.hpp"
/*
* Author: tcvm
* Checks if the unit can pickup the tripod
*
* Arguments:
* 0: Tripod <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* Can pickup <BOOL>
*
* Example:
* [cursorObject, player] call ace_csw_fnc_canPickupTripod
*
* Public: No
*/
params ["_tripod", "_unit"];
((secondaryWeapon _unit) == "") && {alive _tripod} // return

View File

@ -1,24 +0,0 @@
#include "..\script_component.hpp"
/*
* Author:tcvm
* An action for the player to get in the CSW
* Due to the fact that the default static weapons "Get In" memory point is at the front of
* the gun and can't be acssesed from the back, I am implementing this to get around that issue.
*
* Arguments:
* 0: Static Weapon <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* [cursorObject, player] call ace_csw_fnc_getIn
*
* Public: No
*/
params ["_staticWeapon", "_player"];
TRACE_2("getIn",_staticWeapon,_player);
_player moveInTurret [_staticWeapon, [0]];

View File

@ -1,42 +1,42 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: PabstMirror * Author: PabstMirror
* Gets sub actions for what the player can load into the static weapon * Gets sub actions for what the unit can load into the CSW
* *
* Arguments: * Arguments:
* 0: Static Weapon <OBJECT> * 0: Vehicle <OBJECT>
* 1: Player <OBJECT> * 1: Unit <OBJECT>
* *
* Return Value: * Return Value:
* Actions <ARRAY> * Actions <ARRAY>
* *
* Example: * Example:
* [cursorObject, player] call ace_csw_fnc_reload_actionsLoad * [cursorObject, player] call ace_csw_fnc_getLoadActions
* *
* Public: No * Public: No
*/ */
params ["_vehicle", "_player"]; params ["_vehicle", "_unit"];
private _actions = []; private _loadableMagazines = [_vehicle, _unit] call FUNC(reload_getLoadableMagazines);
private _loadableMagazines = [_vehicle, _player] call FUNC(reload_getLoadableMagazines); if (_loadableMagazines isEqualTo []) exitWith {[]};
private _statement = { private _statement = {
params ["_target", "_player", "_params"]; params ["_target", "_player", "_args"];
_params params ["_carryMag", "_turretPath", "", "_magSource"]; _args params ["_carryMag", "_turretPath", "", "_magSource"];
[_target, _turretPath, _carryMag, _magSource, _player] call FUNC(reload_loadMagazine); [_target, _turretPath, _carryMag, _magSource, _player] call FUNC(reload_loadMagazine);
}; };
private _condition = { private _condition = {
params ["_target", "_player", "_params"]; params ["_target", "_player", "_args"];
_params params ["_carryMag", "_turretPath", "", "_magSource"]; _args params ["_carryMag", "_turretPath", "", "_magSource"];
([_target, _turretPath, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) select 0 ([_target, _turretPath, _carryMag, _magSource] call FUNC(reload_canLoadMagazine)) select 0
}; };
private _cfgMagazines = configFile >> "CfgMagazines"; // micro-optimization private _cfgMagazines = configFile >> "CfgMagazines"; // micro-optimization
private _actions = [];
{ {
_x params ["_carryMag", "", "_loadInfo"]; _x params ["_carryMag", "", "_loadInfo"];
_loadInfo params ["", "", "", "_isBeltLinking"]; _loadInfo params ["", "", "", "_isBeltLinking"];

View File

@ -0,0 +1,74 @@
#include "..\script_component.hpp"
/*
* Author: PabstMirror
* Gets sub actions for what can be unloaded from the CSW
*
* Arguments:
* 0: Vehicle <OBJECT>
*
* Return Value:
* Actions <ARRAY>
*
* Example:
* cursorObject call ace_csw_fnc_getUnloadActions
*
* Public: No
*/
params ["_vehicle"];
private _statement = {
params ["_target", "_player", "_args"];
_args params ["_vehMag", "_turretPath", "_carryMag"];
TRACE_5("starting unload",_target,_turretPath,_player,_carryMag,_vehMag);
private _timeToUnload = 1;
if (!isNull (configOf _target >> QUOTE(ADDON) >> "ammoUnloadTime")) then {
_timeToUnload = getNumber (configOf _target >> QUOTE(ADDON) >> "ammoUnloadTime");
};
[
TIME_PROGRESSBAR(_timeToUnload),
[_target, _turretPath, _player, _carryMag, _vehMag],
{
(_this select 0) params ["_target", "_turretPath", "", "_carryMag", "_vehMag"];
TRACE_5("unload progressBar finish",_target,_turretPath,_carryMag,_vehMag,_player);
[QGVAR(removeTurretMag), [_target, _turretPath, _carryMag, _vehMag, _player]] call CBA_fnc_globalEvent;
},
{TRACE_1("unload progressBar fail",_this);},
format [localize LSTRING(unloadX), getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName")],
{(_this select 0) call FUNC(reload_canUnloadMagazine)},
["isNotInside"]
] call EFUNC(common,progressBar);
};
private _condition = {
params ["_target", "_player", "_args"];
_args params ["_vehMag", "_turretPath", "_carryMag"];
[_target, _turretPath, _player, _carryMag, _vehMag] call FUNC(reload_canUnloadMagazine)
};
private _actions = [];
private _handledMagTypes = [];
private _cfgMagazines = configFile >> "CfgMagazines";
// Go through magazines on static weapon and check if any are unloadable
{
_x params ["_xMag", "_xTurret", "_xAmmo"];
if ((_xAmmo > 0) && {!(_xMag in _handledMagTypes)}) then {
_handledMagTypes pushBack _xMag;
private _carryMag = _xMag call FUNC(getCarryMagazine);
if (_carryMag == "") exitWith {};
private _displayName = getText (_cfgMagazines >> _carryMag >> "displayName");
private _text = format [LLSTRING(unloadX), _displayName];
private _picture = getText (_cfgMagazines >> _carryMag >> "picture");
private _action = [format ["unload_%1", _forEachIndex], _text, _picture, _statement, _condition, {}, [_xMag, _xTurret, _carryMag]] call EFUNC(interact_menu,createAction);
_actions pushBack [_action, [], _vehicle];
};
} forEach (magazinesAllTurrets _vehicle);
TRACE_1("unloadActions",count _actions);
_actions

View File

@ -1,59 +1,63 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: tcvm * Author: tcvm
* Initializes weapon to disable weapon disassembling * Initializes CSW systems on vehicle
* *
* Arguments: * Arguments:
* 0: Weapon <OBJECT> * 0: Vehicle <OBJECT>
* *
* Return Value: * Return Value:
* None * None
* *
* Example: * Example:
* [weapon] call ace_csw_fnc_staticWeaponInit * cursorObject call ace_csw_fnc_initVehicle
* *
* Public: No * Public: No
*/ */
params ["_staticWeapon"]; params ["_vehicle"];
if (isNull _staticWeapon) exitWith { WARNING_1("%1 became null",_staticWeapon) }; if (!alive _vehicle) exitWith { WARNING_1("%1 not alive",_vehicle); };
private _typeOf = typeOf _staticWeapon; if (!simulationEnabled _vehicle) exitWith {
private _configOf = configOf _staticWeapon; [{simulationEnabled _this}, FUNC(initVehicle), _vehicle] call CBA_fnc_waitUntilAndExecute;
private _configEnabled = (getNumber (_configOf >> "ace_csw" >> "enabled")) == 1;
private _assemblyConfig = _configEnabled && {(getText (_configOf >> "ace_csw" >> "disassembleWeapon")) != ""};
TRACE_4("staticWeaponInit",_staticWeapon,_typeOf,_configEnabled,_assemblyConfig);
if (_configEnabled && {GVAR(ammoHandling) == 2}) then {
TRACE_1("adding AI fired handler",_staticWeapon);
_staticWeapon addEventHandler ["Fired", LINKFUNC(ai_handleFired)];
_staticWeapon addEventHandler ["GetIn", LINKFUNC(ai_handleGetIn)]; // handle AI getting inside weapon with no ammo
}; };
TRACE_2("",local _staticWeapon,_staticWeapon turretLocal [0]); private _typeOf = typeOf _vehicle;
if (_configEnabled && {_staticWeapon turretLocal [0]}) then { // if turret is local to us, then handle mags/weapon private _configOf = configOf _vehicle;
private _configEnabled = (getNumber (_configOf >> QUOTE(ADDON) >> "enabled")) == 1;
private _assemblyConfig = _configEnabled && {(getText (_configOf >> QUOTE(ADDON) >> "disassembleWeapon")) != ""};
TRACE_4("initVehicle",_vehicle,_typeOf,_configEnabled,_assemblyConfig);
if (_configEnabled && {GVAR(ammoHandling) == 2}) then {
TRACE_1("adding AI fired handler",_vehicle);
_vehicle addEventHandler ["Fired", LINKFUNC(ai_handleFired)];
_vehicle addEventHandler ["GetIn", LINKFUNC(ai_handleGetIn)]; // handle AI getting inside weapon with no ammo
};
TRACE_2("",local _vehicle,_vehicle turretLocal [0]);
if (_configEnabled && {_vehicle turretLocal [0]}) then { // if turret is local to us, then handle mags/weapon
[{ [{
params ["_staticWeapon"]; params ["_vehicle"];
if (!alive _staticWeapon) exitWith { TRACE_1("dead/deleted",_staticWeapon); }; if (!alive _vehicle) exitWith { TRACE_1("dead/deleted",_vehicle); };
// Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default] // Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default]
private _assemblyModeIndex = _staticWeapon getVariable [QGVAR(assemblyMode), 3]; private _assemblyModeIndex = _vehicle getVariable [QGVAR(assemblyMode), 3];
private _emptyWeapon = _assemblyModeIndex isEqualTo 2; private _emptyWeapon = _assemblyModeIndex isEqualTo 2;
private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select _assemblyModeIndex; private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select _assemblyModeIndex;
TRACE_2("turretLocal",_staticWeapon,_assemblyMode); TRACE_2("turretLocal",_vehicle,_assemblyMode);
[_staticWeapon, [0], _assemblyMode, _emptyWeapon] call FUNC(proxyWeapon); [_vehicle, [0], _assemblyMode, _emptyWeapon] call FUNC(proxyWeapon);
[_staticWeapon, _assemblyMode, _emptyWeapon] call FUNC(staticWeaponInit_unloadExtraMags); [_vehicle, _assemblyMode, _emptyWeapon] call FUNC(staticWeaponInit_unloadExtraMags);
}, [_staticWeapon]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly }, [_vehicle]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly
}; };
if (_assemblyConfig) then { if (_assemblyConfig) then {
[{ [{
params ["_staticWeapon"]; params ["_vehicle"];
if (!alive _staticWeapon) exitWith { TRACE_1("dead/deleted",_staticWeapon); }; if (!alive _vehicle) exitWith { TRACE_1("dead/deleted",_vehicle); };
private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_staticWeapon getVariable [QGVAR(assemblyMode), 3]); private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_vehicle getVariable [QGVAR(assemblyMode), 3]);
TRACE_2("assemblyConfig present",_staticWeapon,_assemblyMode); TRACE_2("assemblyConfig present",_vehicle,_assemblyMode);
if (_assemblyMode) then { // Disable vanilla assembly if assemblyMode enabled if (_assemblyMode) then { // Disable vanilla assembly if assemblyMode enabled
[_staticWeapon, "disableWeaponAssembly", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); [_vehicle, "disableWeaponAssembly", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
}; };
}, [_staticWeapon]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly }, [_vehicle]] call CBA_fnc_execNextFrame; // need to wait a frame to allow setting object vars during assembly
}; };
// Add interactions for players // Add interactions for players
@ -76,7 +80,7 @@ if (hasInterface && {!(_typeOf in GVAR(initializedStaticTypes))}) then {
}; };
private _childenCode = { private _childenCode = {
BEGIN_COUNTER(getActions); // can remove for final release BEGIN_COUNTER(getActions); // can remove for final release
private _ret = (call FUNC(reload_actionsLoad)) + (call FUNC(reload_actionsUnload)); private _ret = (call FUNC(getLoadActions)) + (call FUNC(getUnloadActions));
END_COUNTER(getActions); END_COUNTER(getActions);
_ret _ret
}; };

View File

@ -1,10 +1,10 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author: tcvm, PabstMirror * Author: tcvm, PabstMirror
* Handles the use of proxy weapons to fix engine-reload times * Handles the use of proxy weapons to bypass engine reload times
* *
* Arguments: * Arguments:
* 0: Weapon <OBJECT> * 0: Vehicle <OBJECT>
* 1: Turret <ARRAY> * 1: Turret <ARRAY>
* 2: Proxy weapon needed <BOOL> * 2: Proxy weapon needed <BOOL>
* 2: Weapon should be emptied <BOOL> * 2: Weapon should be emptied <BOOL>
@ -13,34 +13,34 @@
* None * None
* *
* Example: * Example:
* [weapon, [0], true, false] call ace_csw_fnc_proxyWeapon * [cursorObject, [0], true, false] call ace_csw_fnc_proxyWeapon
* *
* Public: No * Public: No
*/ */
params ["_staticWeapon", "_turret", "_needed", "_emptyWeapon"]; params ["_vehicle", "_turret", "_needed", "_emptyWeapon"];
TRACE_4("proxyWeapon",_staticWeapon,_turret,_needed,_emptyWeapon); TRACE_4("proxyWeapon",_vehicle,_turret,_needed,_emptyWeapon);
if (_staticWeapon getVariable [format [QGVAR(proxyHandled_%1), _turret], false]) exitWith { TRACE_1("already handled",typeOf _staticWeapon); }; if (_vehicle getVariable [format [QGVAR(proxyHandled_%1), _turret], false]) exitWith { TRACE_1("already handled",typeOf _vehicle); };
private _proxyWeapon = getText (configOf _staticWeapon >> "ace_csw" >> "proxyWeapon"); private _proxyWeapon = getText (configOf _vehicle >> QUOTE(ADDON) >> "proxyWeapon");
TRACE_2("",typeOf _staticWeapon,_proxyWeapon); TRACE_2("",typeOf _vehicle,_proxyWeapon);
if (_proxyWeapon == "") exitWith {}; if (_proxyWeapon == "") exitWith {};
private _currentWeapon = (_staticWeapon weaponsTurret [0]) param [0, "#none"]; private _currentWeapon = (_vehicle weaponsTurret [0]) param [0, "#none"];
if ((missionNamespace getVariable [_proxyWeapon, objNull]) isEqualType {}) then { // check if string is a function if ((missionNamespace getVariable [_proxyWeapon, objNull]) isEqualType {}) then { // check if string is a function
TRACE_1("Calling proxyWeapon function",_proxyWeapon); TRACE_1("Calling proxyWeapon function",_proxyWeapon);
// This function may replace magazines or do other things to the static weapon // This function may replace magazines or do other things to the static weapon
_proxyWeapon = [_staticWeapon, _turret, _currentWeapon, _needed, _emptyWeapon] call (missionNamespace getVariable _proxyWeapon); _proxyWeapon = [_vehicle, _turret, _currentWeapon, _needed, _emptyWeapon] call (missionNamespace getVariable _proxyWeapon);
_needed = _proxyWeapon != ""; _needed = _proxyWeapon != "";
}; };
if (!_needed) exitWith { TRACE_2("not needed",_needed,_proxyWeapon); }; if (!_needed) exitWith { TRACE_2("not needed",_needed,_proxyWeapon); };
// Rearm compatibility, prevent reloading entire static and breaking CSW // Rearm compatibility, prevent reloading entire static and breaking CSW
_staticWeapon setVariable [QEGVAR(rearm,scriptedLoadout), true, true]; _vehicle setVariable [QEGVAR(rearm,scriptedLoadout), true, true];
TRACE_2("swapping to proxy weapon",_currentWeapon,_proxyWeapon); TRACE_2("swapping to proxy weapon",_currentWeapon,_proxyWeapon);
_staticWeapon removeWeaponTurret [_currentWeapon, _turret]; _vehicle removeWeaponTurret [_currentWeapon, _turret];
_staticWeapon addWeaponTurret [_proxyWeapon, _turret]; _vehicle addWeaponTurret [_proxyWeapon, _turret];
_staticWeapon setVariable [format [QGVAR(proxyHandled_%1), _turret], true, true]; _vehicle setVariable [format [QGVAR(proxyHandled_%1), _turret], true, true];

View File

@ -1,75 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: PabstMirror
* Gets sub actions for what the player can unload from the static weapon
*
* Arguments:
* 0: Target <OBJECT>
* 1: Player <OBJECT>
*
* Return Value:
* Actions <ARRAY>
*
* Example:
* [cursorObject, player] call ace_csw_fnc_reload_actionsUnload
*
* Public: No
*/
params ["_vehicle", "_player"];
private _statement = {
params ["_target", "_player", "_params"];
_params params ["_vehMag", "_turretPath", "_carryMag"];
TRACE_5("starting unload",_target,_turretPath,_player,_carryMag,_vehMag);
private _timeToUnload = 1;
if (!isNull(configOf _target >> QUOTE(ADDON) >> "ammoUnloadTime")) then {
_timeToUnload = getNumber(configOf _target >> QUOTE(ADDON) >> "ammoUnloadTime");
};
[
TIME_PROGRESSBAR(_timeToUnload),
[_target, _turretPath, _player, _carryMag, _vehMag],
{
(_this select 0) params ["_target", "_turretPath", "", "_carryMag", "_vehMag"];
TRACE_5("unload progressBar finish",_target,_turretPath,_carryMag,_vehMag,_player);
[QGVAR(removeTurretMag), [_target, _turretPath, _carryMag, _vehMag, _player]] call CBA_fnc_globalEvent;
},
{TRACE_1("unload progressBar fail",_this);},
format [localize LSTRING(unloadX), getText (configFile >> "CfgMagazines" >> _carryMag >> "displayName")],
{(_this select 0) call FUNC(reload_canUnloadMagazine)},
["isNotInside"]
] call EFUNC(common,progressBar);
};
private _condition = {
params ["_target", "_player", "_params"];
_params params ["_vehMag", "_turretPath", "_carryMag"];
[_target, _turretPath, _player, _carryMag, _vehMag] call FUNC(reload_canUnloadMagazine)
};
private _actions = [];
private _handeledMagTypes = [];
private _cfgMagazines = configFile >> "CfgMagazines";
// Go through magazines on static weapon and check if any are unloadable
{
_x params ["_xMag", "_xTurret", "_xAmmo"];
if ((_xAmmo > 0) && {!(_xMag in _handeledMagTypes)}) then {
_handeledMagTypes pushBack _xMag;
private _carryMag = _xMag call FUNC(getCarryMagazine);
if (_carryMag == "") exitWith {};
private _displayName = getText (_cfgMagazines >> _carryMag >> "displayName");
private _text = format [LLSTRING(unloadX), _displayName];
private _picture = getText (_cfgMagazines >> _carryMag >> "picture");
private _action = [format ["unload_%1", _forEachIndex], _text, _picture, _statement, _condition, {}, [_xMag, _xTurret, _carryMag]] call EFUNC(interact_menu,createAction);
_actions pushBack [_action, [], _vehicle];
};
} forEach (magazinesAllTurrets _vehicle);
TRACE_1("unloadActions",count _actions);
_actions

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm, PabstMirror * Author: tcvm, PabstMirror
* Handles adding ammo to a turret * Handles adding ammo to a turret
* Called from a global event but only runs where turret is local * Called from a global event but only runs where turret is local
* *

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp" #include "..\script_component.hpp"
/* /*
* Author:tcvm * Author: tcvm
* Handles removing ammo from a turret * Handles removing ammo from a turret
* Called from a global event but only runs where turret is local * Called from a global event but only runs where turret is local
* *

View File

@ -21,5 +21,4 @@ params ["_target", "_unit"];
&& {!alive (gunner _target)} && {!alive (gunner _target)}
&& {!(_target getVariable [QGVAR(fired), false])} && {!(_target getVariable [QGVAR(fired), false])}
&& {!(_target getVariable [QGVAR(sightAttached), ((typeOf _target) == QGVAR(staticAssembled))])} && {!(_target getVariable [QGVAR(sightAttached), ((typeOf _target) == QGVAR(staticAssembled))])}
&& EFUNC(csw,assemble_canPickupTripod) && EFUNC(csw,canPickupTripod)

View File

@ -10,6 +10,7 @@ PREP(cancelPlacement);
PREP(canDefuse); PREP(canDefuse);
PREP(canDetonate); PREP(canDetonate);
PREP(connectExplosive); PREP(connectExplosive);
PREP(cycleActiveTrigger);
PREP(defuseExplosive); PREP(defuseExplosive);
PREP(detonateExplosive); PREP(detonateExplosive);
PREP(detonateExplosiveAll); PREP(detonateExplosiveAll);

View File

@ -8,8 +8,11 @@ PREP_RECOMPILE_START;
#include "XEH_PREP.hpp" #include "XEH_PREP.hpp"
PREP_RECOMPILE_END; PREP_RECOMPILE_END;
#include "initKeybinds.inc.sqf"
#include "initSettings.inc.sqf" #include "initSettings.inc.sqf"
GVAR(activeTrigger) = "";
GVAR(detonationHandlers) = []; GVAR(detonationHandlers) = [];
GVAR(excludedMines) = []; GVAR(excludedMines) = [];

View File

@ -49,18 +49,43 @@ private _explosivesList = [];
}; };
}; };
} forEach _result; } forEach _result;
if (_detonator != "ACE_DeadManSwitch") then {
// Add action to detonate all explosives tied to the detonator // If the detonator is not active, is a clacker and has assigned explosives, generate an interaction to make it the active detonator for use with the "trigger all" keybind
if (count _explosivesList > 0) then { if (
_children pushBack [ _detonator != GVAR(activeTrigger) &&
{_detonator != "Cellphone"} &&
{
_explosivesList isNotEqualTo [] ||
{_detonator == "ACE_DeadManSwitch" && {_unit getVariable [QGVAR(deadmanInvExplosive), ""] != ""}}
}
) then {
_children pushBack [
[ [
"Explosive_All", QGVAR(setActiveTrigger),
localize LSTRING(DetonateAll), LLSTRING(SetActiveTrigger),
getText(ConfigFile >> "CfgWeapons" >> _detonator >> "picture"), "",
{(_this select 2) call FUNC(detonateExplosiveAll);}, {GVAR(activeTrigger) = (_this select 2) select 0;},
{true}, {true},
{}, {},
[_unit,_range,_explosivesList, _detonator] [_detonator]
] call EFUNC(interact_menu,createAction),
[],
_unit
];
};
if (_detonator != "ACE_DeadManSwitch") then {
// Add action to detonate all explosives tied to the detonator
if (count _explosivesList > 1) then {
_children pushBack [
[
"Explosive_All",
LLSTRING(DetonateAll),
getText (configFile >> "CfgWeapons" >> _detonator >> "picture"),
{(_this select 2) call FUNC(detonateExplosiveAll);},
{true},
{},
[_unit, _range, _explosivesList, _detonator]
] call EFUNC(interact_menu,createAction), ] call EFUNC(interact_menu,createAction),
[], [],
_unit _unit
@ -69,15 +94,15 @@ if (_detonator != "ACE_DeadManSwitch") then {
} else { } else {
//Add action to detonate all explosives (including the inventory explosive): //Add action to detonate all explosives (including the inventory explosive):
_children pushBack [ _children pushBack [
[ [
"Explosive_All_Deadman", "Explosive_All_Deadman",
localize LSTRING(DetonateAll), LLSTRING(DetonateAll),
getText(ConfigFile >> "CfgWeapons" >> _detonator >> "picture"), getText (configFile >> "CfgWeapons" >> _detonator >> "picture"),
{[_player] call FUNC(onIncapacitated)}, {[_player] call FUNC(onIncapacitated)},
{true} {true}
] call EFUNC(interact_menu,createAction), ] call EFUNC(interact_menu,createAction),
[], [],
_unit _unit
]; ];
//Adds actions for the explosives you can connect to the deadman switch. //Adds actions for the explosives you can connect to the deadman switch.
@ -89,7 +114,7 @@ if (_detonator != "ACE_DeadManSwitch") then {
_connectedInventoryExplosive = _unit getVariable [QGVAR(deadmanInvExplosive), ""]; _connectedInventoryExplosive = _unit getVariable [QGVAR(deadmanInvExplosive), ""];
if (_connectedInventoryExplosive != "") then { if (_connectedInventoryExplosive != "") then {
//Add the disconect action //Add the disconnect action
private _magConfig = configFile >> "CfgMagazines" >> _connectedInventoryExplosive; private _magConfig = configFile >> "CfgMagazines" >> _connectedInventoryExplosive;
private _name = if ((getText (_magConfig >> "displayNameShort")) != "") then { private _name = if ((getText (_magConfig >> "displayNameShort")) != "") then {
getText (_magConfig >> "displayNameShort") getText (_magConfig >> "displayNameShort")
@ -99,17 +124,20 @@ if (_detonator != "ACE_DeadManSwitch") then {
private _picture = getText (_magConfig >> "picture"); private _picture = getText (_magConfig >> "picture");
_children pushBack [ _children pushBack [
([ ([
"Deadman_disconnect", "Deadman_disconnect",
format ["%1 %2", localize "str_disp_disconnect", _name], format ["%1 %2", localize "str_disp_disconnect", _name],
_picture, _picture,
{ {
params ["_player"]; params ["_player"];
TRACE_1("clear",_player); TRACE_1("clear",_player);
_player setVariable [QGVAR(deadmanInvExplosive), "", true]; _player setVariable [QGVAR(deadmanInvExplosive), "", true];
}, },
{true} {true}
] call EFUNC(interact_menu,createAction)), [], _unit]; ] call EFUNC(interact_menu,createAction)),
[],
_unit
];
} else { } else {
//Add all magazines that would work with the deadman switch //Add all magazines that would work with the deadman switch

View File

@ -0,0 +1,53 @@
#include "..\script_component.hpp"
/*
* Author: mrschick
* Cycles the "Active Trigger" of a unit and shows a CBA Hint that displays the new Active Trigger.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* [ACE_player] call ace_explosives_fnc_cycleActiveTrigger;
*
* Public: No
*/
params ["_unit"];
TRACE_1("params",_unit);
private _detonators = _unit call FUNC(getDetonators);
// Remove ACE_Cellphone from list, as it should never be the active trigger due to having its own keybind
_detonators deleteAt (_detonators findIf {_x == "ACE_Cellphone"});
// Reset Active Trigger if none available
if (_detonators isEqualTo []) exitWith {
GVAR(activeTrigger) = "";
};
private _activeTrigger = GVAR(activeTrigger);
private _index = _detonators findIf {_x == _activeTrigger};
private _count = count _detonators;
if (_activeTrigger != "" && {_index != -1} && {_count > 1}) then {
// If active trigger is set and among current detonators, switch to the next one
if (_index < _count - 1) then {
_index = _index + 1;
} else {
_index = 0;
};
_activeTrigger = _detonators select _index;
} else {
// Assign first detonator in list as the active one
_activeTrigger = _detonators select 0;
};
GVAR(activeTrigger) = _activeTrigger;
private _triggerConfig = configFile >> "CfgWeapons" >> _activeTrigger;
private _triggerName = getText (_triggerConfig >> "displayName");
private _triggerIcon = getText (_triggerConfig >> "picture");
[format ["%1: %2", LLSTRING(ActiveTrigger), _triggerName], _triggerIcon] call EFUNC(common,displayTextPicture);

View File

@ -22,6 +22,15 @@ TRACE_3("params",_explosive,_magazine,_trigger);
private _config = ConfigFile >> "ACE_Triggers" >> _trigger; private _config = ConfigFile >> "ACE_Triggers" >> _trigger;
// Make selected trigger the active one (for keybind) if it's the first to be connected
private _activeTrigger = GVAR(activeTrigger);
if (
_activeTrigger == "" &&
{(["Command", "MK16_Transmitter", "DeadManSwitch"] findIf {_x == _trigger}) != -1}
) then {
GVAR(activeTrigger) = getArray (_config >> "requires") select 0;
};
// If the onSetup function returns true, it is handled elsewhere // If the onSetup function returns true, it is handled elsewhere
if (isText(_config >> "onSetup") && {[_explosive,_magazine] call compile getText (_config >> "onSetup")}) exitWith { if (isText(_config >> "onSetup") && {[_explosive,_magazine] call compile getText (_config >> "onSetup")}) exitWith {
TRACE_2("onSetup returned true",_explosive,_trigger); TRACE_2("onSetup returned true",_explosive,_trigger);

View File

@ -0,0 +1,50 @@
#include "\a3\ui_f\hpp\defineDIKCodes.inc"
["ACE3 Equipment", QGVAR(openCellphone), LLSTRING(cellphone_displayName), {
if (
!([ACE_player, "ACE_Cellphone"] call EFUNC(common,hasItem)) ||
!([ACE_player, objNull, ["isNotSwimming", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith))
) exitWith {};
closeDialog 0;
createDialog "Rsc_ACE_PhoneInterface";
true
}] call CBA_fnc_addKeybind; // Unbound
["ACE3 Equipment", QGVAR(detonateActiveClacker), LLSTRING(DetonateAllOnActive), {
// Prevent use of keybind while surrendering or captive
if !([ACE_player, objNull, ["isNotSwimming", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith)) exitWith {};
private _detonator = GVAR(activeTrigger);
if (_detonator == "" || !(_detonator in ([ACE_player] call FUNC(getDetonators)))) exitWith {};
// When using a Dead Man's Switch, skip all other logic and just call fnc_onIncapacitated, since it already handles everything that is required to detonate all connected explosives
if (_detonator == "ACE_DeadManSwitch") exitWith {
[ACE_player] call FUNC(onIncapacitated);
};
private _range = getNumber (configFile >> "CfgWeapons" >> _detonator >> QGVAR(Range));
private _explosivesList = [];
{
if (!isNull (_x select 0)) then {
private _required = getArray (configFile >> "ACE_Triggers" >> _x select 4 >> "requires");
if (_detonator in _required) then {
_explosivesList pushBack _x;
};
};
} forEach ([ACE_player] call FUNC(getPlacedExplosives));
[ACE_player, _range, _explosivesList, _detonator] call FUNC(detonateExplosiveAll);
true
}] call CBA_fnc_addKeybind; // Unbound
["ACE3 Equipment", QGVAR(cycleActiveClacker), LLSTRING(CycleActiveTrigger), {
if !([ACE_player, objNull, ["isNotSwimming", "isNotInside", "isNotSitting"]] call EFUNC(common,canInteractWith)) exitWith {};
[ACE_player] call FUNC(cycleActiveTrigger);
true
}] call CBA_fnc_addKeybind; // Unbound

View File

@ -68,6 +68,26 @@
<Chinese>引爆全部</Chinese> <Chinese>引爆全部</Chinese>
<Turkish>Hepsini Patlat</Turkish> <Turkish>Hepsini Patlat</Turkish>
</Key> </Key>
<Key ID="STR_ACE_Explosives_DetonateAllOnActive">
<English>Detonate All on Active Clacker</English>
<German>Alle auf Standardzünder zünden</German>
<Italian>Detona Tutti sul Detonatore Attivo</Italian>
</Key>
<Key ID="STR_ACE_Explosives_SetActiveTrigger">
<English>Set Active Clacker</English>
<German>Als Standardzünder wählen</German>
<Italian>Imposta Detonatore Attivo</Italian>
</Key>
<Key ID="STR_ACE_Explosives_CycleActiveTrigger">
<English>Cycle Active Clacker</English>
<German>Standardzünder wechseln</German>
<Italian>Cambia Detonatore Attivo</Italian>
</Key>
<Key ID="STR_ACE_Explosives_ActiveTrigger">
<English>Active Clacker</English>
<German>Standardzünder</German>
<Italian>Detonatore Attivo</Italian>
</Key>
<Key ID="STR_ACE_Explosives_DetonateCode"> <Key ID="STR_ACE_Explosives_DetonateCode">
<English>Explosive code: %1</English> <English>Explosive code: %1</English>
<German>Sprengstoffcode: %1</German> <German>Sprengstoffcode: %1</German>

View File

@ -3,6 +3,7 @@ PREP(addLaserTarget);
PREP(addMapHandler); PREP(addMapHandler);
PREP(dev_drawVisibleLaserTargets); PREP(dev_drawVisibleLaserTargets);
PREP(findLaserSource); PREP(findLaserSource);
PREP(getLaserCode);
PREP(handleLaserTargetCreation); PREP(handleLaserTargetCreation);
PREP(keyLaserCodeChange); PREP(keyLaserCodeChange);
PREP(laserOff); PREP(laserOff);
@ -13,6 +14,7 @@ PREP(onLaserDesignatorDraw);
PREP(rotateVectLine); PREP(rotateVectLine);
PREP(rotateVectLineGetMap); PREP(rotateVectLineGetMap);
PREP(seekerFindLaserSpot); PREP(seekerFindLaserSpot);
PREP(setLaserCode);
PREP(shootCone); PREP(shootCone);
PREP(shootRay); PREP(shootRay);
PREP(showVehicleHud); PREP(showVehicleHud);

View File

@ -0,0 +1,24 @@
#include "..\script_component.hpp"
/*
* Author: johnb43
* Gets the laser code of a laser source.
*
* Argument:
* 0: Laser source <OBJECT>
*
* Return Value:
* Laser code <NUMBER>
*
* Example:
* player call ace_laser_fnc_getLaserCode;
*
* Public: Yes
*/
params [["_laserSource", objNull, [objNull]]];
if (isNull _laserSource) exitWith {
-1
};
_laserSource getVariable [QGVAR(code), ACE_DEFAULT_LASER_CODE]

View File

@ -0,0 +1,21 @@
#include "..\script_component.hpp"
/*
* Author: johnb43
* Sets the laser code on a laser source.
*
* Argument:
* 0: Laser source <OBJECT>
* 1: Laser code <NUMBER>
*
* Return Value:
* None
*
* Example:
* [player, 1111] call ace_laser_fnc_setLaserCode;
*
* Public: Yes
*/
params [["_laserSource", objNull, [objNull]], ["_laserCode", ACE_DEFAULT_LASER_CODE, [0]]];
_laserSource setVariable [QGVAR(code), _laserCode, true];

View File

@ -42,6 +42,7 @@
#define GET_ARRAY(config,default) (if (isArray (config)) then {getArray (config)} else {default}) #define GET_ARRAY(config,default) (if (isArray (config)) then {getArray (config)} else {default})
#define DEFAULT_HEART_RATE 80 #define DEFAULT_HEART_RATE 80
#define DEFAULT_SPO2 97
#define DEFAULT_PERIPH_RES 100 #define DEFAULT_PERIPH_RES 100
// --- blood // --- blood
@ -153,6 +154,8 @@
#define VAR_WOUND_BLEEDING QEGVAR(medical,woundBleeding) #define VAR_WOUND_BLEEDING QEGVAR(medical,woundBleeding)
#define VAR_CRDC_ARRST QEGVAR(medical,inCardiacArrest) #define VAR_CRDC_ARRST QEGVAR(medical,inCardiacArrest)
#define VAR_HEART_RATE QEGVAR(medical,heartRate) #define VAR_HEART_RATE QEGVAR(medical,heartRate)
#define VAR_SPO2 QEGVAR(medical,spo2)
#define VAR_OXYGEN_DEMAND QEGVAR(medical,oxygenDemand)
#define VAR_PAIN QEGVAR(medical,pain) #define VAR_PAIN QEGVAR(medical,pain)
#define VAR_PAIN_SUPP QEGVAR(medical,painSuppress) #define VAR_PAIN_SUPP QEGVAR(medical,painSuppress)
#define VAR_PERIPH_RES QEGVAR(medical,peripheralResistance) #define VAR_PERIPH_RES QEGVAR(medical,peripheralResistance)
@ -175,6 +178,7 @@
#define GET_BLOOD_VOLUME(unit) (unit getVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME]) #define GET_BLOOD_VOLUME(unit) (unit getVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME])
#define GET_WOUND_BLEEDING(unit) (unit getVariable [VAR_WOUND_BLEEDING, 0]) #define GET_WOUND_BLEEDING(unit) (unit getVariable [VAR_WOUND_BLEEDING, 0])
#define GET_HEART_RATE(unit) (unit getVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE]) #define GET_HEART_RATE(unit) (unit getVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE])
#define GET_SPO2(unit) (unit getVariable [VAR_SPO2, DEFAULT_SPO2])
#define GET_HEMORRHAGE(unit) (unit getVariable [VAR_HEMORRHAGE, 0]) #define GET_HEMORRHAGE(unit) (unit getVariable [VAR_HEMORRHAGE, 0])
#define GET_PAIN(unit) (unit getVariable [VAR_PAIN, 0]) #define GET_PAIN(unit) (unit getVariable [VAR_PAIN, 0])
#define GET_PAIN_SUPPRESS(unit) (unit getVariable [VAR_PAIN_SUPP, 0]) #define GET_PAIN_SUPPRESS(unit) (unit getVariable [VAR_PAIN_SUPP, 0])

View File

@ -32,13 +32,15 @@ if (damage _unit > 0) then {
if (_isRespawn) then { if (_isRespawn) then {
TRACE_1("reseting all vars on respawn",_isRespawn); // note: state is handled by ace_medical_statemachine_fnc_resetStateDefault TRACE_1("reseting all vars on respawn",_isRespawn); // note: state is handled by ace_medical_statemachine_fnc_resetStateDefault
// - Blood and heart ---------------------------------------------------------- // - Vitals ------------------------------------------------------------------
_unit setVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME, true]; _unit setVariable [VAR_BLOOD_VOL, DEFAULT_BLOOD_VOLUME, true];
_unit setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true]; _unit setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true];
_unit setVariable [VAR_BLOOD_PRESS, [80, 120], true]; _unit setVariable [VAR_BLOOD_PRESS, [80, 120], true];
_unit setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true]; _unit setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true];
_unit setVariable [VAR_CRDC_ARRST, false, true]; _unit setVariable [VAR_CRDC_ARRST, false, true];
_unit setVariable [VAR_HEMORRHAGE, 0, true]; _unit setVariable [VAR_HEMORRHAGE, 0, true];
_unit setVariable [VAR_SPO2, DEFAULT_SPO2, true];
_unit setVariable [VAR_OXYGEN_DEMAND, 0, true];
// - Pain --------------------------------------------------------------------- // - Pain ---------------------------------------------------------------------
_unit setVariable [VAR_PAIN, 0, true]; _unit setVariable [VAR_PAIN, 0, true];

View File

@ -57,9 +57,19 @@ if (_active) then {
// Do "Unlock controls" user action, co-pilot will then have to do the "Take Controls" actions // Do "Unlock controls" user action, co-pilot will then have to do the "Take Controls" actions
_unit action ["UnlockVehicleControl", vehicle _unit]; _unit action ["UnlockVehicleControl", vehicle _unit];
}; };
// Disable AI talking (yes, this needs to be explicit)
if (!isPlayer _unit && {_unit checkAIFeature "RADIOPROTOCOL"}) then {
_unit disableAI "RADIOPROTOCOL";
_unit setVariable [QGVAR(reenableRadioProtocol), true, true];
};
} else { } else {
// Unit has woken up, no longer need to track this // Unit has woken up, no longer need to track this
_unit setVariable [QEGVAR(medical,lastWakeUpCheck), nil]; _unit setVariable [QEGVAR(medical,lastWakeUpCheck), nil];
if (_unit getVariable [QGVAR(reenableRadioProtocol), false]) then {
_unit enableAI "RADIOPROTOCOL";
};
}; };
// This event doesn't correspond to unconscious in statemachine // This event doesn't correspond to unconscious in statemachine

View File

@ -63,6 +63,8 @@ _patient setVariable [VAR_FRACTURES, DEFAULT_FRACTURE_VALUES, true];
_patient setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true]; _patient setVariable [VAR_HEART_RATE, DEFAULT_HEART_RATE, true];
_patient setVariable [VAR_BLOOD_PRESS, [80, 120], true]; _patient setVariable [VAR_BLOOD_PRESS, [80, 120], true];
_patient setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true]; _patient setVariable [VAR_PERIPH_RES, DEFAULT_PERIPH_RES, true];
_patient setVariable [VAR_SPO2, DEFAULT_SPO2, true];
_patient setVariable [VAR_OXYGEN_DEMAND, 0, true];
// IVs // IVs
_patient setVariable [QEGVAR(medical,ivBags), nil, true]; _patient setVariable [QEGVAR(medical,ivBags), nil, true];

View File

@ -0,0 +1,10 @@
class CfgWeapons {
class H_HelmetB;
class H_PilotHelmetFighter_B: H_HelmetB {
GVAR(oxygenSupply) = QUOTE(vehicle _this isKindOf 'Plane' || vehicle _this isKindOf 'Helicopter');
};
class Vest_Camo_Base;
class V_RebreatherB: Vest_Camo_Base {
GVAR(oxygenSupply) = QUOTE(eyePos _this select 2 < 0); // will only work for sea-level water
};
};

View File

@ -1,4 +1,6 @@
PREP(handleUnitVitals); PREP(handleUnitVitals);
PREP(scanConfig);
PREP(updateHeartRate); PREP(updateHeartRate);
PREP(updateOxygen);
PREP(updatePainSuppress); PREP(updatePainSuppress);
PREP(updatePeripheralResistance); PREP(updatePeripheralResistance);

View File

@ -6,4 +6,8 @@ PREP_RECOMPILE_START;
#include "XEH_PREP.hpp" #include "XEH_PREP.hpp"
PREP_RECOMPILE_END; PREP_RECOMPILE_END;
#include "initSettings.inc.sqf"
GVAR(oxygenSupplyConditionCache) = uiNamespace getVariable QGVAR(oxygenSupplyConditionCache);
ADDON = true; ADDON = true;

View File

@ -1,3 +1,9 @@
#include "script_component.hpp" #include "script_component.hpp"
#include "XEH_PREP.hpp" #include "XEH_PREP.hpp"
GVAR(oxygenSupplyConditionCache) = createHashMap;
call FUNC(scanConfig);
GVAR(oxygenSupplyConditionCache) = compileFinal GVAR(oxygenSupplyConditionCache);

View File

@ -23,5 +23,6 @@ class CfgPatches {
}; };
#include "CfgEventHandlers.hpp" #include "CfgEventHandlers.hpp"
#include "CfgWeapons.hpp"
#endif #endif

View File

@ -31,6 +31,9 @@ if (_syncValues) then {
_unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime]; _unit setVariable [QGVAR(lastMomentValuesSynced), CBA_missionTime];
}; };
// Update SPO2 intake and usage since last update
[_unit, _deltaT, _syncValues] call FUNC(updateOxygen);
private _bloodVolume = GET_BLOOD_VOLUME(_unit) + ([_unit, _deltaT, _syncValues] call EFUNC(medical_status,getBloodVolumeChange)); private _bloodVolume = GET_BLOOD_VOLUME(_unit) + ([_unit, _deltaT, _syncValues] call EFUNC(medical_status,getBloodVolumeChange));
_bloodVolume = 0 max _bloodVolume min DEFAULT_BLOOD_VOLUME; _bloodVolume = 0 max _bloodVolume min DEFAULT_BLOOD_VOLUME;

View File

@ -0,0 +1,23 @@
#include "..\script_component.hpp"
/*
* Author: LinkIsGrim
* Cache a hashmap of all oxygen-providing items for SpO2 simulation
*
* Arguments:
* None
*
* Return Value:
* None
*
* Public: No
*/
private _filter = toString {getText (_x >> QGVAR(oxygenSupply)) != ""};
{
private _cfgRoot = configFile >> _x;
{
private _condition = compile getText (_x >> QGVAR(oxygenSupply));
GVAR(oxygenSupplyConditionCache) set [configName _x, _condition];
} forEach (_filter configClasses _cfgRoot);
} forEach ["CfgWeapons", "CfgGoggles"];

View File

@ -37,6 +37,7 @@ if IN_CRDC_ARRST(_unit) then {
if (_bloodVolume > BLOOD_VOLUME_CLASS_4_HEMORRHAGE) then { if (_bloodVolume > BLOOD_VOLUME_CLASS_4_HEMORRHAGE) then {
GET_BLOOD_PRESSURE(_unit) params ["_bloodPressureL", "_bloodPressureH"]; GET_BLOOD_PRESSURE(_unit) params ["_bloodPressureL", "_bloodPressureH"];
private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL; private _meanBP = (2/3) * _bloodPressureH + (1/3) * _bloodPressureL;
private _spo2 = GET_SPO2(_unit);
private _painLevel = GET_PAIN_PERCEIVED(_unit); private _painLevel = GET_PAIN_PERCEIVED(_unit);
private _targetBP = 107; private _targetBP = 107;
@ -51,8 +52,11 @@ if IN_CRDC_ARRST(_unit) then {
if (_painLevel > 0.2) then { if (_painLevel > 0.2) then {
_targetHR = _targetHR max (80 + 50 * _painLevel); _targetHR = _targetHR max (80 + 50 * _painLevel);
}; };
// Increase HR to compensate for low blood oxygen
// Increase HR to compensate for higher oxygen demand (e.g. running, recovering from sprint)
private _oxygenDemand = _unit getVariable [VAR_OXYGEN_DEMAND, 0];
_targetHR = _targetHR + ((97 - _spo2) * 2) + (_oxygenDemand * -1000);
_targetHR = (_targetHR + _hrTargetAdjustment) max 0; _targetHR = (_targetHR + _hrTargetAdjustment) max 0;
_hrChange = round(_targetHR - _heartRate) / 2; _hrChange = round(_targetHR - _heartRate) / 2;
} else { } else {
_hrChange = -round(_heartRate / 10); _hrChange = -round(_heartRate / 10);

View File

@ -0,0 +1,75 @@
#include "..\script_component.hpp"
/*
* Author: Brett Mayson
* Update the oxygen levels
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Time since last update <NUMBER>
* 2: Sync value? <BOOL>
*
* ReturnValue:
* Current SPO2 <NUMBER>
*
* Example:
* [player, 1, false] call ace_medical_vitals_fnc_updateOxygen
*
* Public: No
*/
params ["_unit", "_deltaT", "_syncValue"];
if (!GVAR(simulateSpO2)) exitWith {}; // changing back to default is handled in initSettings.inc.sqf
#define IDEAL_PPO2 0.255
private _current = GET_SPO2(_unit);
private _heartRate = GET_HEART_RATE(_unit);
private _altitude = EGVAR(common,mapAltitude) + ((getPosASL _unit) select 2);
private _po2 = if (missionNamespace getVariable [QEGVAR(weather,enabled), false]) then {
private _temperature = _altitude call EFUNC(weather,calculateTemperatureAtHeight);
private _pressure = _altitude call EFUNC(weather,calculateBarometricPressure);
[_temperature, _pressure, EGVAR(weather,currentHumidity)] call EFUNC(weather,calculateOxygenDensity)
} else {
// Rough approximation of the partial pressure of oxygen in the air
0.25725 * (_altitude / 1000 + 1)
};
private _oxygenSaturation = (IDEAL_PPO2 min _po2) / IDEAL_PPO2;
// Check gear for oxygen supply
[goggles _unit, headgear _unit, vest _unit] findIf {
_x in GVAR(oxygenSupplyConditionCache) &&
{ACE_player call (GVAR(oxygenSupplyConditionCache) get _x)} &&
{ // Will only run this if other conditions are met due to lazy eval
_oxygenSaturation = 1;
_po2 = IDEAL_PPO2;
true
}
};
// Base oxygen consumption rate
private _negativeChange = BASE_OXYGEN_USE;
// Fatigue & exercise will demand more oxygen
// Assuming a trained male in midst of peak exercise will have a peak heart rate of ~180 BPM
// Ref: https://academic.oup.com/bjaed/article-pdf/4/6/185/894114/mkh050.pdf table 2, though we don't take stroke volume change into account
if (_unit == ACE_player && {missionNamespace getVariable [QEGVAR(advanced_fatigue,enabled), false]}) then {
_negativeChange = _negativeChange - ((1 - EGVAR(advanced_fatigue,aeReservePercentage)) * 0.1) - ((1 - EGVAR(advanced_fatigue,anReservePercentage)) * 0.05);
};
// Effectiveness of capturing oxygen
// increases slightly as po2 starts lowering
// but falls off quickly as po2 drops further
private _capture = 1 max ((_po2 / IDEAL_PPO2) ^ (-_po2 * 3));
private _positiveChange = _heartRate * 0.00368 * _oxygenSaturation * _capture;
private _breathingEffectiveness = 1;
private _rateOfChange = _negativeChange + (_positiveChange * _breathingEffectiveness);
private _spo2 = (_current + (_rateOfChange * _deltaT)) max 0 min 100;
_unit setVariable [VAR_OXYGEN_DEMAND, _negativeChange - BASE_OXYGEN_USE];
_unit setVariable [VAR_SPO2, _spo2, _syncValue];

View File

@ -0,0 +1,15 @@
[
QGVAR(simulateSpO2),
"CHECKBOX",
[LSTRING(simulateSpO2_DisplayName), LSTRING(simulateSpO2_Description)],
[ELSTRING(medical,Category), LSTRING(SubCategory)],
true,
1,
{
if (_this) exitWith {}; // skip if true
{
_x setVariable [VAR_OXYGEN_DEMAND, 0, true];
_x setVariable [VAR_SPO2, DEFAULT_SPO2, true];
} forEach (allUnits select {local _x})
} // reset oxygen demand on setting change
] call CBA_fnc_addSetting;

View File

@ -16,3 +16,5 @@
#include "\z\ace\addons\medical_engine\script_macros_medical.hpp" #include "\z\ace\addons\medical_engine\script_macros_medical.hpp"
#include "\z\ace\addons\main\script_macros.hpp" #include "\z\ace\addons\main\script_macros.hpp"
#define BASE_OXYGEN_USE -0.25

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="Medical_Vitals">
<Key ID="STR_ACE_Medical_Vitals_SubCategory">
<English>Vitals</English>
<Portuguese>Vitais</Portuguese>
</Key>
<Key ID="STR_ACE_Medical_Vitals_simulateSpO2_DisplayName">
<English>Enable SpO2 Simulation</English>
</Key>
<Key ID="STR_ACE_Medical_Vitals_simulateSpO2_Description">
<English>Enables oxygen saturation simulation, providing variable heart rate and oxygen demand based on physical activity and altitude. Required for Airway Management.</English>
</Key>
</Package>
</Project>

View File

@ -1,9 +1,9 @@
PREP(calculateAirDensity); PREP(calculateAirDensity);
PREP(calculateBarometricPressure); PREP(calculateBarometricPressure);
PREP(calculateDensityAltitude); PREP(calculateDensityAltitude);
PREP(calculateDewPoint); PREP(calculateDewPoint);
PREP(calculateHeatIndex); PREP(calculateHeatIndex);
PREP(calculateOxygenDensity);
PREP(calculateRoughnessLength); PREP(calculateRoughnessLength);
PREP(calculateSpeedOfSound); PREP(calculateSpeedOfSound);
PREP(calculateTemperatureAtHeight); PREP(calculateTemperatureAtHeight);

View File

@ -0,0 +1,20 @@
#include "..\script_component.hpp"
/*
* Author: Brett Mayson
* Calculates the oxygen density
*
* Arguments:
* 0: Temperature - °C <NUMBER>
* 1: Pressure - hPa <NUMBER>
* 2: Relative humidity - value between 0.0 and 1.0 <NUMBER>
*
* Return Value:
* Density of oxygen - kg * m^(-3) <NUMBER>
*
* Example:
* [0, 1020] call ace_weather_fnc_calculateOxygenDensity
*
* Public: No
*/
(_this call FUNC(calculateAirDensity)) * 0.21

View File

@ -35,6 +35,7 @@ Enables attaching explosives to vehicles.
- Interact with the explosive <kbd>&nbsp;Win</kbd> (ACE3 default key bind `Interact Key`). - Interact with the explosive <kbd>&nbsp;Win</kbd> (ACE3 default key bind `Interact Key`).
- Choose the arming method. - Choose the arming method.
- For clackers use Self Interaction `Explosives` &rarr; `Detonate` and choose the corresponding Firing Device. - For clackers use Self Interaction `Explosives` &rarr; `Detonate` and choose the corresponding Firing Device.
- Alternatively, use <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>C</kbd> (ACE3 default key bind `Detonate All on Active Clacker`) to detonate all explosives tied to the `Active Detonator`, which can be changed via the `Set Active Detonator` interaction on the desired Clacker / Dead Man Switch.
### 2.3 Defusing explosives ### 2.3 Defusing explosives
- A `Defusal Kit` is required. - A `Defusal Kit` is required.

View File

@ -0,0 +1,34 @@
---
layout: wiki
title: Laser
description: Explains the functions available for laser designators.
group: framework
order: 5
parent: wiki
mod: ace
version:
major: 3
minor: 16
patch: 4
---
## 1. Scripting
### 1.1. Get object's laser code
`ace_laser_fnc_getLaserCode`
| | Arguments | Type | Optional (default value)
---| --------- | ---- | ------------------------
0 | Unit/Vehicle | Object | Required
**R** | Laser code | Number | Return value
### 1.2. Set object's laser code
`ace_laser_fnc_setLaserCode`
| | Arguments | Type | Optional (default value)
---| --------- | ---- | ------------------------
0 | Unit/Vehicle | Object | Required
1 | Laser code | Number | Required
**R** | None | None | Return value