diff --git a/addons/common/functions/fnc_claimSafeServer.sqf b/addons/common/functions/fnc_claimSafeServer.sqf index e24a421549..6ebee7cb4f 100644 --- a/addons/common/functions/fnc_claimSafeServer.sqf +++ b/addons/common/functions/fnc_claimSafeServer.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: commy2, PabstMirror - * Unit claims the ownership over an object. This is used to prevent multiple players from draging the same ammo box or using up the same wheel when repairing etc. + * Unit claims the ownership over an object. This is used to prevent multiple players from dragging the same ammo box or using up the same wheel when repairing etc. * This function only runs on the server and handles the "ace_common_claimSafe" event. It provides a network safe way claiming objects as all claims are run on server. * Return event is passed [_unit, _target, _success] for new claims, no event on claim release * diff --git a/addons/dragging/XEH_PREP.hpp b/addons/dragging/XEH_PREP.hpp index f7e8d86a7d..a5afd0367e 100644 --- a/addons/dragging/XEH_PREP.hpp +++ b/addons/dragging/XEH_PREP.hpp @@ -28,6 +28,8 @@ PREP(resumeDrag); PREP(setCarryable); PREP(setDraggable); PREP(startCarry); +PREP(startCarryLocal); PREP(startCarryPFH); PREP(startDrag); +PREP(startDragLocal); PREP(startDragPFH); diff --git a/addons/dragging/XEH_postInit.sqf b/addons/dragging/XEH_postInit.sqf index f2c5b921ac..8690f90149 100644 --- a/addons/dragging/XEH_postInit.sqf +++ b/addons/dragging/XEH_postInit.sqf @@ -80,6 +80,9 @@ if (isNil QGVAR(maxWeightCarryRun)) then { }; }] call CBA_fnc_addEventHandler; +[QGVAR(startCarry), LINKFUNC(startCarryLocal)] call CBA_fnc_addEventHandler; +[QGVAR(startDrag), LINKFUNC(startDragLocal)] call CBA_fnc_addEventHandler; + [QGVAR(carryingContainerClosed), { params ["_container", "_owner"]; TRACE_2("carryingContainerClosed EH",_container,_owner); diff --git a/addons/dragging/functions/fnc_canCarry.sqf b/addons/dragging/functions/fnc_canCarry.sqf index 732b619e6f..64511fe410 100644 --- a/addons/dragging/functions/fnc_canCarry.sqf +++ b/addons/dragging/functions/fnc_canCarry.sqf @@ -18,7 +18,10 @@ params ["_unit", "_target"]; -if !((alive _target || {_target isKindOf "CAManBase"}) && {_target getVariable [QGVAR(canCarry), false]} && {isNull objectParent _target}) exitWith {false}; +private _alive = alive _target; +private _isPerson = _target isKindOf "CAManBase"; + +if !((_alive || _isPerson) && {_target getVariable [QGVAR(canCarry), false]} && {isNull objectParent _target}) exitWith {false}; if !([_unit, _target, []] call EFUNC(common,canInteractWith)) exitWith {false}; @@ -26,18 +29,19 @@ if !([_unit, _target, []] call EFUNC(common,canInteractWith)) exitWith {false}; // The fireman carry animation does not slow down for injured legs, so you could carry and run if ((_unit getHitPointDamage "HitLegs") >= 0.5) exitWith {false}; +// Units need to be unconscious or limping; Units also need to not be in ragdoll if alive, as that causes desync issues +if (_isPerson) exitWith { + !_alive || + {(isAwake _target) && // not ragdolled if alive + {!(lifeState _target in ["HEALTHY", "INJURED"]) || + {_target getHitPointDamage "HitLegs" >= 0.5}}} +}; + // Static weapons need to be empty for carrying (ignore UAV AI) if (_target isKindOf "StaticWeapon") exitWith { (crew _target) findIf {!unitIsUAV _x} == -1 }; -// Units need to be unconscious or limping; Units also need to not be in ragdoll, as that causes desync issues -if (_target isKindOf "CAManBase") exitWith { - (isAwake _target == alive _target) && // not ragdolled - {!(lifeState _target in ["HEALTHY", "INJURED"]) || - {_target getHitPointDamage "HitLegs" >= 0.5}} -}; - // Check max items for WeaponHolders if (["WeaponHolder", "WeaponHolderSimulated"] findIf {_target isKindOf _x} != -1) exitWith { (count (weaponCargo _target + magazineCargo _target + itemCargo _target)) <= MAX_DRAGGED_ITEMS diff --git a/addons/dragging/functions/fnc_canDrag.sqf b/addons/dragging/functions/fnc_canDrag.sqf index 1e2155a400..51aa2d8cde 100644 --- a/addons/dragging/functions/fnc_canDrag.sqf +++ b/addons/dragging/functions/fnc_canDrag.sqf @@ -18,22 +18,26 @@ params ["_unit", "_target"]; -if !((alive _target || {_target isKindOf "CAManBase"}) && {_target getVariable [QGVAR(canDrag), false]} && {isNull objectParent _target}) exitWith {false}; +private _alive = alive _target; +private _isPerson = _target isKindOf "CAManBase"; + +if !((_alive || _isPerson) && {_target getVariable [QGVAR(canDrag), false]} && {isNull objectParent _target}) exitWith {false}; if !([_unit, _target, ["isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; +// Units need to be unconscious or limping; Units also need to not be in ragdoll if alive, as that causes desync issues +if (_isPerson) exitWith { + !_alive || + {(isAwake _target) && // not ragdolled if alive + {!(lifeState _target in ["HEALTHY", "INJURED"]) || + {_target getHitPointDamage "HitLegs" >= 0.5}}} +}; + // Static weapons need to be empty for dragging (ignore UAV AI) if (_target isKindOf "StaticWeapon") exitWith { (crew _target) findIf {!unitIsUAV _x} == -1 }; -// Units need to be unconscious or limping; Units also need to not be in ragdoll, as that causes desync issues -if (_target isKindOf "CAManBase") exitWith { - (isAwake _target == alive _target) && // not ragdolled - {!(lifeState _target in ["HEALTHY", "INJURED"]) || - {_target getHitPointDamage "HitLegs" >= 0.5}} -}; - // Check max items for WeaponHolders if (["WeaponHolder", "WeaponHolderSimulated"] findIf {_target isKindOf _x} != -1) exitWith { (count (weaponCargo _target + magazineCargo _target + itemCargo _target)) <= MAX_DRAGGED_ITEMS diff --git a/addons/dragging/functions/fnc_createClone.sqf b/addons/dragging/functions/fnc_createClone.sqf index 4228356ac8..e22f553c82 100644 --- a/addons/dragging/functions/fnc_createClone.sqf +++ b/addons/dragging/functions/fnc_createClone.sqf @@ -4,7 +4,8 @@ * Creates a draggable / carryable clone of a dead unit. * * Arguments: - * 0: Dead unit + * 0: Unit dragging/carrying + * 1: Dead unit * * Return Value: * Cloned unit @@ -15,17 +16,19 @@ * Public: No */ -params ["_target"]; +params ["_unit", "_target"]; -// Get current position of unit, -10 m below surface -private _posATL = getPosATL _target; +private _posATL = getPosASL _target; + +// Create clone +private _clone = createVehicle [QGVAR(clone), ASLToAGL _posATL, [], 0, "CAN_COLLIDE"]; + +// Claim the clone +[_unit, _clone] call EFUNC(common,claim); + +// Move unit -10 m below terrain in order to hide it and remove its inventory access _posATL set [2, -10]; -private _clone = createVehicle [QGVAR(clone), _posATL]; - -// Clone loadout -[_clone, _target call CBA_fnc_getLoadout] call CBA_fnc_setLoadout; - // Hide unit until it can be moved below terrain private _isObjectHidden = isObjectHidden _target; @@ -48,13 +51,15 @@ if (_isInRemainsCollector) then { // Make sure clone has the same wound textures as the corpse private _targetDamage = damage _target; + if (_targetDamage != 0) then { - _clone setDamage (_targetDamage min 0.99); // Don't kill the clone + _clone setDamage (_targetDamage min 0.99); // don't kill the clone }; + private _relevantHitpoints = ["HitHead", "HitBody", "HitHands", "HitLegs"]; + { - private _hitpointDamage = _target getHitPointDamage _x; - _clone setHitPointDamage [_x, _hitpointDamage min 0.99]; + _clone setHitPointDamage [_x, (_target getHitPointDamage _x) min 0.99]; } forEach _relevantHitpoints; // Disable all damage @@ -65,16 +70,38 @@ _clone setVariable [QGVAR(original), [_target, _isInRemainsCollector, _isObjectH [QEGVAR(common,awake), [_target, true]] call CBA_fnc_globalEvent; [{ - params ["_target", "_posATL"]; + params ["_clone", "_target", "_posATL"]; + + // Remove clone from all zeuses + if (["ace_zeus"] call EFUNC(common,isModLoaded)) then { + [QEGVAR(zeus,removeObjects), [[_clone]]] call CBA_fnc_serverEvent; + }; // Make sure PhysX is on [QEGVAR(common,awake), [_target, true]] call CBA_fnc_globalEvent; - // Move unit below terrain in order to hide it and remove its inventory access - _target setPosATL _posATL; -}, [_target, _posATL], 0.25] call CBA_fnc_waitAndExecute; + // Clone loadout (sometimes default loadouts are randomised, so overwrite those) + [_clone, _target call CBA_fnc_getLoadout] call CBA_fnc_setLoadout; -// Sets the facial expression -[[QGVAR(cloneCreated), [_target, _clone]] call CBA_fnc_globalEventJIP, _clone] call CBA_fnc_removeGlobalEventJIP; + // Sets the facial expression + [[QGVAR(cloneCreated), [_target, _clone]] call CBA_fnc_globalEventJIP, _clone] call CBA_fnc_removeGlobalEventJIP; + + // Corpse is desynced, but it doesn't matter here + _target setPosATL _posATL; + + // Release claim on corpse + [objNull, _target] call EFUNC(common,claim); +}, [_clone, _target, _posATL], 0.25] call CBA_fnc_waitAndExecute; + +// Save which curators had this object as editable +if (["ace_zeus"] call EFUNC(common,isModLoaded)) then { + private _objectCurators = objectCurators _target; + + _target setVariable [QGVAR(objectCurators), _objectCurators, true]; + + if (_objectCurators isEqualTo []) exitWith {}; + + [QEGVAR(zeus,removeObjects), [[_target], _objectCurators]] call CBA_fnc_serverEvent; +}; _clone diff --git a/addons/dragging/functions/fnc_dropClone.sqf b/addons/dragging/functions/fnc_dropClone.sqf index b373856e0c..010ebebf3e 100644 --- a/addons/dragging/functions/fnc_dropClone.sqf +++ b/addons/dragging/functions/fnc_dropClone.sqf @@ -37,40 +37,49 @@ if (!isNull _target) then { _posASL = _posASL vectorAdd [0, 0, 0.05]; }; + // Set the unit's direction + [QEGVAR(common,setDir), [_target, getDir _unit + 180], _target] call CBA_fnc_targetEvent; + [{ - params ["_target", "", "", "", "_posASL", "_dir"]; + params ["_target", "_clone", "_isObjectHidden", "_simulationEnabled", "_posASL"]; // Make sure PhysX is on [QEGVAR(common,awake), [_target, true]] call CBA_fnc_globalEvent; - // Set the unit's direction - [QEGVAR(common,setDir), [_target, _dir], _target] call CBA_fnc_targetEvent; - // Bring unit back to clone's position _target setPosASL _posASL; - [{ - params ["_target", "_clone", "_isObjectHidden", "_simulationEnabled"]; + // Unhide unit + if (!_isObjectHidden) then { + [QEGVAR(common,hideObjectGlobal), [_target, false]] call CBA_fnc_serverEvent; + }; - if (!_isObjectHidden) then { - [QEGVAR(common,hideObjectGlobal), [_target, false]] call CBA_fnc_serverEvent; - }; + // Enable simulation again + if (_simulationEnabled) then { + [QEGVAR(common,enableSimulationGlobal), [_target, true]] call CBA_fnc_serverEvent; + }; - if (_simulationEnabled) then { - [QEGVAR(common,enableSimulationGlobal), [_target, true]] call CBA_fnc_serverEvent; - }; + // Detach first to prevent objNull in attachedObjects + detach _clone; + deleteVehicle _clone; + }, [_target, _clone, _isObjectHidden, _simulationEnabled, _posASL], 0.25] call CBA_fnc_waitAndExecute; - deleteVehicle _clone; - }, _this, 0.25] call CBA_fnc_waitAndExecute; - }, [_target, _clone, _isObjectHidden, _simulationEnabled, _posASL, getDir _unit + 180], 0.25] call CBA_fnc_waitAndExecute; + // Get which curators had this object as editable + if (["ace_zeus"] call EFUNC(common,isModLoaded)) then { + private _objectCurators = _target getVariable [QGVAR(objectCurators), []]; + + if (_objectCurators isEqualTo []) exitWith {}; + + [QEGVAR(zeus,addObjects), [[_target], _objectCurators]] call CBA_fnc_serverEvent; + }; if (_isInRemainsCollector) then { addToRemainsCollector [_target]; }; +} else { + // Detach first to prevent objNull in attachedObjects + detach _clone; + deleteVehicle _clone; }; -// Detach first to prevent objNull in attachedObjects -detach _clone; -deleteVehicle _clone; - _target diff --git a/addons/dragging/functions/fnc_pauseCarry.sqf b/addons/dragging/functions/fnc_pauseCarry.sqf index bfe27420f6..49c91e166f 100644 --- a/addons/dragging/functions/fnc_pauseCarry.sqf +++ b/addons/dragging/functions/fnc_pauseCarry.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* * Author: johnb43 - * Removes user input affecting dragging. + * Removes user input affecting carrying. * * Arguments: * 0: Unit diff --git a/addons/dragging/functions/fnc_setCarryable.sqf b/addons/dragging/functions/fnc_setCarryable.sqf index 174bdbf972..60b9854f41 100644 --- a/addons/dragging/functions/fnc_setCarryable.sqf +++ b/addons/dragging/functions/fnc_setCarryable.sqf @@ -56,8 +56,25 @@ GVAR(initializedClasses_carry) = _initializedClasses; private _icon = [QPATHTOF(UI\icons\box_carry.paa), QPATHTOF(UI\icons\person_carry.paa)] select (_object isKindOf "CAManBase"); -private _carryAction = [QGVAR(carry), LLSTRING(Carry), _icon, {[_player, _target] call FUNC(startCarry)}, {[_player, _target] call FUNC(canCarry)}] call EFUNC(interact_menu,createAction); -private _dropAction = [QGVAR(drop_carry), LLSTRING(Drop), "", {[_player, _target] call FUNC(dropObject_carry)}, {[_player, _target] call FUNC(canDrop_carry)}] call EFUNC(interact_menu,createAction); +private _carryAction = [ + QGVAR(carry), + LLSTRING(Carry), + _icon, + { + [_player, _target] call FUNC(startCarry) + }, { + [_player, _target] call FUNC(canCarry) +}] call EFUNC(interact_menu,createAction); + +private _dropAction = [ + QGVAR(drop_carry), + LLSTRING(Drop), + "", + { + [_player, _target] call FUNC(dropObject_carry) + }, { + [_player, _target] call FUNC(canDrop_carry) +}] call EFUNC(interact_menu,createAction); [_type, 0, ["ACE_MainActions"], _carryAction] call EFUNC(interact_menu,addActionToClass); [_type, 0, [], _dropAction] call EFUNC(interact_menu,addActionToClass); diff --git a/addons/dragging/functions/fnc_setDraggable.sqf b/addons/dragging/functions/fnc_setDraggable.sqf index a00e3005e9..e024ec5be2 100644 --- a/addons/dragging/functions/fnc_setDraggable.sqf +++ b/addons/dragging/functions/fnc_setDraggable.sqf @@ -56,8 +56,25 @@ GVAR(initializedClasses) = _initializedClasses; private _icon = [QPATHTOF(UI\icons\box_drag.paa), QPATHTOF(UI\icons\person_drag.paa)] select (_object isKindOf "CAManBase"); -private _dragAction = [QGVAR(drag), LLSTRING(Drag), _icon, {[_player, _target] call FUNC(startDrag)}, {[_player, _target] call FUNC(canDrag)}] call EFUNC(interact_menu,createAction); -private _dropAction = [QGVAR(drop), LLSTRING(Drop), "", {[_player, _target] call FUNC(dropObject)}, {[_player, _target] call FUNC(canDrop)}] call EFUNC(interact_menu,createAction); +private _dragAction = [ + QGVAR(drag), + LLSTRING(Drag), + _icon, + { + [_player, _target] call FUNC(startDrag) + }, { + [_player, _target] call FUNC(canDrag) +}] call EFUNC(interact_menu,createAction); + +private _dropAction = [ + QGVAR(drop), + LLSTRING(Drop), + "", + { + [_player, _target] call FUNC(dropObject); + }, { + [_player, _target] call FUNC(canDrop) +}] call EFUNC(interact_menu,createAction); [_type, 0, ["ACE_MainActions"], _dragAction] call EFUNC(interact_menu,addActionToClass); [_type, 0, [], _dropAction] call EFUNC(interact_menu,addActionToClass); diff --git a/addons/dragging/functions/fnc_startCarry.sqf b/addons/dragging/functions/fnc_startCarry.sqf index f9e6f115f4..5553593629 100644 --- a/addons/dragging/functions/fnc_startCarry.sqf +++ b/addons/dragging/functions/fnc_startCarry.sqf @@ -1,7 +1,7 @@ #include "..\script_component.hpp" /* - * Author: commy2, PiZZADOX - * Starts the carrying process. + * Author: johnb43 + * Starts the carrying process safely. * * Arguments: * 0: Unit that should do the carrying @@ -17,81 +17,6 @@ */ params ["_unit", "_target"]; -TRACE_2("params",_unit,_target); -// Exempt from weight check if object has override variable set -private _weight = 0; - -if !(_target getVariable [QGVAR(ignoreWeightCarry), false]) then { - _weight = _target call FUNC(getWeight); -}; - -// Exit if object weight is over global var value -if (_weight > GETMVAR(ACE_maxWeightCarry,1E11)) exitWith { - [LLSTRING(UnableToDrag)] call EFUNC(common,displayTextStructured); -}; - -private _timer = CBA_missionTime + 5; - -// Handle objects vs. persons -if (_target isKindOf "CAManBase") then { - // Create clone for dead units - if (!alive _target) then { - _target = _target call FUNC(createClone); - }; - - private _primaryWeapon = primaryWeapon _unit; - - // Add a primary weapon if the unit has none - if (_primaryWeapon == "") then { - _unit addWeapon "ACE_FakePrimaryWeapon"; - _primaryWeapon = "ACE_FakePrimaryWeapon"; - }; - - // Select primary, otherwise the drag animation actions don't work - _unit selectWeapon _primaryWeapon; - - // Move a bit closer and adjust direction when trying to pick up a person - [QEGVAR(common,setDir), [_target, getDir _unit + 180], _target] call CBA_fnc_targetEvent; - _target setPosASL (getPosASL _unit vectorAdd (vectorDir _unit)); - - [_unit, "AcinPknlMstpSnonWnonDnon_AcinPercMrunSnonWnonDnon", 2] call EFUNC(common,doAnimation); - [_target, "AinjPfalMstpSnonWrflDnon_carried_Up", 2] call EFUNC(common,doAnimation); - - _timer = CBA_missionTime + 10; -} else { - // Select no weapon and stop sprinting - private _previousWeaponIndex = [_unit] call EFUNC(common,getFiremodeIndex); - _unit setVariable [QGVAR(previousWeapon), _previousWeaponIndex, true]; - - _unit action ["SwitchWeapon", _unit, _unit, 299]; - - [_unit, "AmovPercMstpSnonWnonDnon", 0] call EFUNC(common,doAnimation); - - private _canRun = _weight call FUNC(canRun_carry); - - // Only force walking if we're overweight - [_unit, "forceWalk", QUOTE(ADDON), !_canRun] call EFUNC(common,statusEffect_set); - [_unit, "blockSprint", QUOTE(ADDON), _canRun] call EFUNC(common,statusEffect_set); -}; - -[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); - -// Prevent multiple players from accessing the same object -[_unit, _target, true] call EFUNC(common,claim); - -// Prevents dragging and carrying at the same time -_unit setVariable [QGVAR(isCarrying), true, true]; - -// Required for aborting animation -_unit setVariable [QGVAR(carriedObject), _target, true]; - -[FUNC(startCarryPFH), 0.2, [_unit, _target, _timer]] call CBA_fnc_addPerFrameHandler; - -// Disable collisions by setting the PhysX mass to almost zero -private _mass = getMass _target; - -if (_mass > 1) then { - _target setVariable [QGVAR(originalMass), _mass, true]; - [QEGVAR(common,setMass), [_target, 1e-12]] call CBA_fnc_globalEvent; // Force global sync -}; +// Try to claim the object +[QEGVAR(common,claimSafe), [_unit, _target, true, QGVAR(startCarry)]] call CBA_fnc_serverEvent; diff --git a/addons/dragging/functions/fnc_startCarryLocal.sqf b/addons/dragging/functions/fnc_startCarryLocal.sqf new file mode 100644 index 0000000000..af889cd358 --- /dev/null +++ b/addons/dragging/functions/fnc_startCarryLocal.sqf @@ -0,0 +1,97 @@ +#include "..\script_component.hpp" +/* + * Author: commy2, PiZZADOX + * Starts the carrying process. + * + * Arguments: + * 0: Unit that should do the carrying + * 1: Object to carry + * 2: If object was successfully claimed + * + * Return Value: + * None + * + * Example: + * [player, cursorTarget, true] call ace_dragging_fnc_startCarryLocal; + * + * Public: No + */ + +params ["_unit", "_target", "_claimed"]; +TRACE_3("params",_unit,_target,_claimed); + +if (!_claimed) exitWith {}; + +// Exempt from weight check if object has override variable set +private _weight = 0; + +if !(_target getVariable [QGVAR(ignoreWeightCarry), false]) then { + _weight = _target call FUNC(getWeight); +}; + +// Exit if object weight is over global var value +if (_weight > GETMVAR(ACE_maxWeightCarry,1E11)) exitWith { + [LLSTRING(UnableToDrag)] call EFUNC(common,displayTextStructured); +}; + +// Create clone for dead units +if (!alive _target) then { + _target = [_unit, _target] call FUNC(createClone); +}; + +private _timer = CBA_missionTime + 5; + +// Handle objects vs. persons +if (_target isKindOf "CAManBase") then { + private _primaryWeapon = primaryWeapon _unit; + + // Add a primary weapon if the unit has none + if (_primaryWeapon == "") then { + _unit addWeapon "ACE_FakePrimaryWeapon"; + _primaryWeapon = "ACE_FakePrimaryWeapon"; + }; + + // Select primary, otherwise the drag animation actions don't work + _unit selectWeapon _primaryWeapon; + + // Move a bit closer and adjust direction when trying to pick up a person + [QEGVAR(common,setDir), [_target, getDir _unit + 180], _target] call CBA_fnc_targetEvent; + _target setPosASL (getPosASL _unit vectorAdd (vectorDir _unit)); + + [_unit, "AcinPknlMstpSnonWnonDnon_AcinPercMrunSnonWnonDnon", 2] call EFUNC(common,doAnimation); + [_target, "AinjPfalMstpSnonWrflDnon_carried_Up", 2] call EFUNC(common,doAnimation); + + _timer = CBA_missionTime + 10; +} else { + // Select no weapon and stop sprinting + private _previousWeaponIndex = [_unit] call EFUNC(common,getFiremodeIndex); + _unit setVariable [QGVAR(previousWeapon), _previousWeaponIndex, true]; + + _unit action ["SwitchWeapon", _unit, _unit, 299]; + + [_unit, "AmovPercMstpSnonWnonDnon", 0] call EFUNC(common,doAnimation); + + private _canRun = _weight call FUNC(canRun_carry); + + // Only force walking if we're overweight + [_unit, "forceWalk", QUOTE(ADDON), !_canRun] call EFUNC(common,statusEffect_set); + [_unit, "blockSprint", QUOTE(ADDON), _canRun] call EFUNC(common,statusEffect_set); +}; + +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + +// Prevents dragging and carrying at the same time +_unit setVariable [QGVAR(isCarrying), true, true]; + +// Required for aborting animation +_unit setVariable [QGVAR(carriedObject), _target, true]; + +[FUNC(startCarryPFH), 0.2, [_unit, _target, _timer]] call CBA_fnc_addPerFrameHandler; + +// Disable collisions by setting the PhysX mass to almost zero +private _mass = getMass _target; + +if (_mass > 1) then { + _target setVariable [QGVAR(originalMass), _mass, true]; + [QEGVAR(common,setMass), [_target, 1e-12]] call CBA_fnc_globalEvent; // Force global sync +}; diff --git a/addons/dragging/functions/fnc_startDrag.sqf b/addons/dragging/functions/fnc_startDrag.sqf index 892fc6ad25..085aa605d8 100644 --- a/addons/dragging/functions/fnc_startDrag.sqf +++ b/addons/dragging/functions/fnc_startDrag.sqf @@ -1,10 +1,10 @@ #include "..\script_component.hpp" /* - * Author: commy2, PiZZADOX, Malbryn - * Starts the dragging process. + * Author: johnb43 + * Starts the dragging process safely. * * Arguments: - * 0: Unit that should do the dragging + * 0: Unit that should do the carrying * 1: Object to drag * * Return Value: @@ -17,93 +17,6 @@ */ params ["_unit", "_target"]; -TRACE_2("params",_unit,_target); -// Exempt from weight check if object has override variable set -private _weight = 0; - -if !(_target getVariable [QGVAR(ignoreWeightDrag), false]) then { - _weight = _target call FUNC(getWeight); -}; - -// Exit if object weight is over global var value -if (_weight > GETMVAR(ACE_maxWeightDrag,1E11)) exitWith { - [LLSTRING(UnableToDrag)] call EFUNC(common,displayTextStructured); -}; - -// Create clone for dead units -if (!alive _target) then { - _target = _target call FUNC(createClone); -}; - -private _primaryWeapon = primaryWeapon _unit; - -// Add a primary weapon if the unit has none -if !(GVAR(dragAndFire)) then { - if (_primaryWeapon == "") then { - _unit addWeapon "ACE_FakePrimaryWeapon"; - _primaryWeapon = "ACE_FakePrimaryWeapon"; - }; - - _unit selectWeapon _primaryWeapon; -} else { // Making sure the unit is holding a primary weapon or handgun - private _handgunWeapon = handgunWeapon _unit; - - if !(currentWeapon _unit in [_primaryWeapon, _handgunWeapon]) then { - if (_primaryWeapon != "") then { - // Use primary if possible - _unit selectWeapon _primaryWeapon; - } else { - if (_handgunWeapon != "") then { - // Use pistol if unit has no primary - _unit selectWeapon _handgunWeapon; - } else { - // Add fake weapon if no weapons besides launcher are available - _unit addWeapon "ACE_FakePrimaryWeapon"; - _unit selectWeapon "ACE_FakePrimaryWeapon"; - }; - }; - }; -}; - -// Save the weapon so we can monitor if it changes -_unit setVariable [QGVAR(currentWeapon), currentWeapon _unit]; - -[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); - -// Prevent multiple players from accessing the same object -[_unit, _target, true] call EFUNC(common,claim); - -// Can't play action that depends on weapon if it was added the same frame -if !(_unit call EFUNC(common,isSwimming)) then { - [{ - private _unitWeapon = _this getVariable [QGVAR(currentWeapon), ""]; - - if (_unitWeapon isKindOf ["Pistol", configFile >> "CfgWeapons"]) then { - [_this, "ACE_dragWithPistol"] call EFUNC(common,doGesture); - } else { - [_this, "ACE_dragWithRifle"] call EFUNC(common,doGesture); - }; - }, _unit] call CBA_fnc_execNextFrame; -}; - -// Move a bit closer and adjust direction when trying to pick up a person -if (_target isKindOf "CAManBase") then { - [QEGVAR(common,setDir), [_target, getDir _unit + 180], _target] call CBA_fnc_targetEvent; - _target setPosASL (getPosASL _unit vectorAdd (vectorDir _unit vectorMultiply 1.5)); - - [_target, "AinjPpneMrunSnonWnonDb_grab", 2] call EFUNC(common,doAnimation); -}; - -// Prevents dragging and carrying at the same time -_unit setVariable [QGVAR(isDragging), true, true]; - -[FUNC(startDragPFH), 0.2, [_unit, _target, CBA_missionTime + 5]] call CBA_fnc_addPerFrameHandler; - -// Disable collisions by setting the physx mass to almost zero -private _mass = getMass _target; - -if (_mass > 1) then { - _target setVariable [QGVAR(originalMass), _mass, true]; - [QEGVAR(common,setMass), [_target, 1e-12]] call CBA_fnc_globalEvent; // Force global sync -}; +// Try to claim the object +[QEGVAR(common,claimSafe), [_unit, _target, true, QGVAR(startDrag)]] call CBA_fnc_serverEvent; diff --git a/addons/dragging/functions/fnc_startDragLocal.sqf b/addons/dragging/functions/fnc_startDragLocal.sqf new file mode 100644 index 0000000000..d0e5e0e2e9 --- /dev/null +++ b/addons/dragging/functions/fnc_startDragLocal.sqf @@ -0,0 +1,109 @@ +#include "..\script_component.hpp" +/* + * Author: commy2, PiZZADOX, Malbryn + * Starts the dragging process. + * + * Arguments: + * 0: Unit that should do the dragging + * 1: Object to drag + * 2: If object was successfully claimed + * + * Return Value: + * None + * + * Example: + * [player, cursorTarget, true] call ace_dragging_fnc_startDragLocal; + * + * Public: No + */ + +params ["_unit", "_target", "_claimed"]; +TRACE_3("params",_unit,_target,_claimed); + +if (!_claimed) exitWith {}; + +// Exempt from weight check if object has override variable set +private _weight = 0; + +if !(_target getVariable [QGVAR(ignoreWeightDrag), false]) then { + _weight = _target call FUNC(getWeight); +}; + +// Exit if object weight is over global var value +if (_weight > GETMVAR(ACE_maxWeightDrag,1E11)) exitWith { + [LLSTRING(UnableToDrag)] call EFUNC(common,displayTextStructured); +}; + +// Create clone for dead units +if (!alive _target) then { + _target = [_unit, _target] call FUNC(createClone); +}; + +private _primaryWeapon = primaryWeapon _unit; + +// Add a primary weapon if the unit has none +if !(GVAR(dragAndFire)) then { + if (_primaryWeapon == "") then { + _unit addWeapon "ACE_FakePrimaryWeapon"; + _primaryWeapon = "ACE_FakePrimaryWeapon"; + }; + + _unit selectWeapon _primaryWeapon; +} else { // Making sure the unit is holding a primary weapon or handgun + private _handgunWeapon = handgunWeapon _unit; + + if !(currentWeapon _unit in [_primaryWeapon, _handgunWeapon]) then { + if (_primaryWeapon != "") then { + // Use primary if possible + _unit selectWeapon _primaryWeapon; + } else { + if (_handgunWeapon != "") then { + // Use pistol if unit has no primary + _unit selectWeapon _handgunWeapon; + } else { + // Add fake weapon if no weapons besides launcher are available + _unit addWeapon "ACE_FakePrimaryWeapon"; + _unit selectWeapon "ACE_FakePrimaryWeapon"; + }; + }; + }; +}; + +// Save the weapon so we can monitor if it changes +_unit setVariable [QGVAR(currentWeapon), currentWeapon _unit]; + +[_unit, "blockThrow", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set); + +// Can't play action that depends on weapon if it was added the same frame +if !(_unit call EFUNC(common,isSwimming)) then { + [{ + private _unitWeapon = _this getVariable [QGVAR(currentWeapon), ""]; + + if (_unitWeapon isKindOf ["Pistol", configFile >> "CfgWeapons"]) then { + [_this, "ACE_dragWithPistol"] call EFUNC(common,doGesture); + } else { + [_this, "ACE_dragWithRifle"] call EFUNC(common,doGesture); + }; + }, _unit] call CBA_fnc_execNextFrame; +}; + +// Move a bit closer and adjust direction when trying to pick up a person +if (_target isKindOf "CAManBase") then { + [QEGVAR(common,setDir), [_target, getDir _unit + 180], _target] call CBA_fnc_targetEvent; + _target setPosASL (getPosASL _unit vectorAdd (vectorDir _unit vectorMultiply 1.5)); + + [_target, "AinjPpneMrunSnonWnonDb_grab", 2] call EFUNC(common,doAnimation); +}; + +// Prevents dragging and carrying at the same time +_unit setVariable [QGVAR(isDragging), true, true]; + +[FUNC(startDragPFH), 0.2, [_unit, _target, CBA_missionTime + 5]] call CBA_fnc_addPerFrameHandler; + +// Disable collisions by setting the physx mass to almost zero +private _mass = getMass _target; + +if (_mass > 1) then { + _target setVariable [QGVAR(originalMass), _mass, true]; + [QEGVAR(common,setMass), [_target, 1e-12]] call CBA_fnc_globalEvent; // Force global sync +}; diff --git a/addons/dragging/initKeybinds.inc.sqf b/addons/dragging/initKeybinds.inc.sqf index 8ee36d0283..a8792f3576 100644 --- a/addons/dragging/initKeybinds.inc.sqf +++ b/addons/dragging/initKeybinds.inc.sqf @@ -5,7 +5,7 @@ if (!alive _player) exitWith {false}; if !([_player, objNull, ["isNotDragging", "isNotCarrying", "isNotSwimming"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // If we are drag/carrying something right now then just drop it: + // If we are dragging/carrying something right now then just drop it if (_player getVariable [QGVAR(isDragging), false]) exitWith { [_player, _player getVariable [QGVAR(draggedObject), objNull]] call FUNC(dropObject); @@ -34,7 +34,7 @@ if (!alive _player) exitWith {false}; if !([_player, objNull, ["isNotDragging", "isNotCarrying"]] call EFUNC(common,canInteractWith)) exitWith {false}; - // If we are drag/carrying something right now then just drop it: + // If we are dragging/carrying something right now then just drop it if (_player getVariable [QGVAR(isDragging), false]) exitWith { [_player, _player getVariable [QGVAR(draggedObject), objNull]] call FUNC(dropObject); diff --git a/addons/medical_gui/functions/fnc_collectActions.sqf b/addons/medical_gui/functions/fnc_collectActions.sqf index 818decb017..f9392897f3 100644 --- a/addons/medical_gui/functions/fnc_collectActions.sqf +++ b/addons/medical_gui/functions/fnc_collectActions.sqf @@ -32,7 +32,7 @@ GVAR(actions) = []; if ("ace_dragging" call EFUNC(common,isModLoaded)) then { GVAR(actions) pushBack [ - localize ELSTRING(dragging,Drag), "drag", + LELSTRING(dragging,Drag), "drag", {ACE_player != GVAR(target) && {[ACE_player, GVAR(target)] call EFUNC(dragging,canDrag)}}, { GVAR(pendingReopen) = false; @@ -41,7 +41,7 @@ if ("ace_dragging" call EFUNC(common,isModLoaded)) then { ]; GVAR(actions) pushBack [ - localize ELSTRING(dragging,Carry), "drag", + LELSTRING(dragging,Carry), "drag", {ACE_player != GVAR(target) && {[ACE_player, GVAR(target)] call EFUNC(dragging,canCarry)}}, { GVAR(pendingReopen) = false; diff --git a/docs/wiki/framework/medical-treatment-framework.md b/docs/wiki/framework/medical-treatment-framework.md index e42cb21e3b..c84d4382ea 100644 --- a/docs/wiki/framework/medical-treatment-framework.md +++ b/docs/wiki/framework/medical-treatment-framework.md @@ -57,9 +57,60 @@ class ACE_Medical_Treatment_Actions { }; ``` -## 2. Mission Variables +## 2. Medical Vehicles and Facilities -### 2.1 Grave Digging Object Configuration +### 2.1 Medical Vehicles + +To configure a vehicle as a Medical Vehicle by default, set the `attendant` property in the vehicle's config to `1`. +```cpp +class CfgVehicles { + class MyAmbulance { + attendant = 1; + }; +}; +``` +To set a vehicle as a Medical Vehicle mid-mission, set the `ace_medical_isMedicalVehicle` variable globally. +```sqf +// Sets the object behind your cursor to be a medical vehicle +cursorObject setVariable ["ace_medical_isMedicalVehicle", true, true]; + +// Create an interaction to turn a vehicle into a medical vehicle +private _statement = {_target setVariable ["ace_medical_isMedicalVehicle", true, true]}; +private _action = ["TAG_makeMedicalVehicle", "Set as Medical Vehicle", _statement, {!([_target] call ace_medical_treatment_fnc_isMedicalVehicle)}] call ace_interact_menu_fnc_createAction; +[cursorObject, 0, ["ACE_MainActions"], _action] call ace_interact_menu_fnc_createAction; + +// Set all vehicles of type "B_Truck_01_transport_F" as medical vehicles +private _classname = "B_Truck_01_transport_F"; +private _affectChildClasses = false; // Affect variants of this vehicle +["B_Truck_01_transport_F", "InitPost", { + params ["_vehicle"]; + if (!local _vehicle) exitWith {}; + _vehicle setVariable ["ace_medical_isMedicalVehicle", true, true]; +}, _affectChildClasses, [], true] call CBA_fnc_addClassEventHandler; +``` + +### 2.2 Medical Facilities + +To configure an object as a Medical Facility by default, add a new array containing its classname to the `ace_medical_facilities` class in config root. +```cpp +class CfgVehicles { + class ThingX; + class MyMedicalFacility: ThingX {}; + class MyMedicalFacility2_ElectricBoogaloo: MyMedicalFacility {}; +}; + +class ace_medical_facilities { + TAG_allOfMyFacilities[] = {"MyMedicalFacility", "MyMedicalFacility2_ElectricBoogaloo"}; +}; +``` +To set an object as a Medical Facility mid-mission, set the `ace_medical_isMedicalFacility` variable globally. See above. + + +Both Medical Facilities and Medical Vehicles can also be created via the Eden Editor's attributes menu. + +## 3. Mission Variables + +### 3.1 Grave Digging Object Configuration The object created when digging a grave can be modified by setting the `ace_medical_treatment_graveClassname` variable. ```sqf @@ -71,7 +122,7 @@ The object's rotation can also be modified, if necessary. ace_medical_treatment_graveRotation = 0; // rotation angle (will depend on model classname) ``` -### 2.2 Zeus Medical Menu Module +### 3.2 Zeus Medical Menu Module If a mission maker wishes to disable Zeus access to the medical menu, they can set the variable below: ace_medical_gui_enableZeusModule = false; // default is true