#include "..\script_component.hpp" /* * Author: tcvm, johnb43 * Simulates fire intensity over time on burning units. * Arbitrary values to ignite people. Assumed maximum is "10". * * Arguments: * 0: Unit * 1: Instigator * * Return Value: * None * * Example: * [player, player] call ace_fire_fnc_burnSimulation * * Public: No */ params ["_unit", "_instigator"]; [{ params ["_args", "_pfhID"]; _args params ["_unit", "_instigator"]; if (isNull _unit) exitWith { TRACE_1("unit is null",_unit); _pfhID call CBA_fnc_removePerFrameHandler; }; // Locality has changed if (!local _unit) exitWith { TRACE_1("unit is no longer local",_unit); _pfhID call CBA_fnc_removePerFrameHandler; [QGVAR(burnSimulation), [_unit, _instigator], _unit] call CBA_fnc_targetEvent; }; // If the unit is invulnerable, in water or if the fire has died out, stop burning the unit if ( !(_unit call FUNC(isBurning)) || {!(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]})} || {private _eyePos = eyePos _unit; surfaceIsWater _eyePos && {(_eyePos select 2) < 0.1}} ) exitWith { TRACE_3("unit is no longer burning, invulnerable or in water",_unit,_unit call FUNC(isBurning),isDamageAllowed _unit && {_unit getVariable [ARR_2(QEGVAR(medical,allowDamage),true)]}); // Remove global effects (_unit getVariable [QGVAR(jipID), ""]) call CBA_fnc_removeGlobalEventJIP; // Update globally that the unit isn't burning anymore _unit setVariable [QGVAR(intensity), nil, true]; _pfhID call CBA_fnc_removePerFrameHandler; if (!isNil {_unit getVariable QGVAR(stopDropRoll)} && {!isPlayer _unit}) then { _unit setUnitPos "AUTO"; _unit setVariable [QGVAR(stopDropRoll), nil, true]; }; }; if (isGamePaused) exitWith {}; private _intensity = _unit getVariable [QGVAR(intensity), 0]; // Propagate fire to other units (alive or dead) if it's intense if (_intensity >= BURN_THRESHOLD_INTENSE) then { TRACE_2("check for other units",_unit,_intensity); { private _distancePercent = 1 - ((_unit distance _x) / BURN_PROPAGATE_DISTANCE); private _adjustedIntensity = _intensity * _distancePercent; // Don't burn if intensity is too low or already burning with higher intensity if (BURN_MIN_INTENSITY > _adjustedIntensity || {(_x getVariable [QGVAR(intensity), 0]) > _adjustedIntensity}) then { continue; }; [QGVAR(burn), [_x, _adjustedIntensity, _instigator], _x] call CBA_fnc_targetEvent; TRACE_3("propagate fire",_x,_intensity,_adjustedIntensity); } forEach nearestObjects [_unit, ["CAManBase"], BURN_PROPAGATE_DISTANCE]; }; // Update intensity/fire reactions if (CBA_missionTime >= _unit getVariable [QGVAR(intensityUpdate), 0]) then { TRACE_2("update intensity",_unit,_intensity); _unit setVariable [QGVAR(intensityUpdate), CBA_missionTime + INTENSITY_UPDATE]; _intensity = _intensity - INTENSITY_LOSS - (rain / 10); if (_unit call EFUNC(common,isAwake)) then { if (_unit call EFUNC(common,isPlayer)) then { // Decrease intensity of burn if rolling around if ((animationState _unit) in PRONE_ROLLING_ANIMS) then { _intensity = _intensity * INTENSITY_DECREASE_MULT_ROLLING; }; } else { private _sdr = _unit getVariable [QGVAR(stopDropRoll), false]; private _vehicle = objectParent _unit; if (isNull _vehicle && {_sdr || {0.05 > random 1}}) then { _unit setVariable [QGVAR(stopDropRoll), true, true]; if (!_sdr) then { TRACE_1("stop, drop, roll!",_unit); _unit setUnitPos "DOWN"; doStop _unit; }; // Queue up a bunch of animations for "_i" from 0 to 2 do { [_unit, selectRandom ["amovppnemstpsnonwnondnon_amovppnemevasnonwnondl", "amovppnemstpsnonwnondnon_amovppnemevasnonwnondr"], 0] call EFUNC(common,doAnimation); }; _intensity = _intensity - (1 / _intensity); } else { // Make the unit leave the vehicle if (_vehicle != _unit) then { TRACE_1("Ejecting",_unit); _unit leaveVehicle _vehicle; unassignVehicle _unit; _unit action ["Eject", _vehicle]; }; _unit disableAI "TARGET"; _unit disableAI "AUTOTARGET"; // Run away, erraticly if (leader group _unit != _unit) then { [_unit] join grpNull; }; _unit doMove ((getPosATL _unit) getPos [20 + random 35, floor (random 360)]); _unit setSpeedMode "FULL"; _unit setSuppression 1; }; }; // Play screams and throw weapon (if enabled) _unit call FUNC(burnReaction); }; // Keep pain around unconsciousness limit to allow for more fun interactions private _painPercieved = (0 max ((_unit getVariable [QEGVAR(medical,pain), 0]) - (_unit getVariable [QEGVAR(medical,painSuppress), 0])) min 1); private _painUnconscious = missionNamespace getVariable [QEGVAR(medical,painUnconsciousThreshold), 0]; private _damageToAdd = [0.15, _intensity / BURN_MAX_INTENSITY] select (!alive _unit || {_painPercieved < _painUnconscious + random 0.2}); if (GETEGVAR(medical,enabled,false)) then { if (!isNull _instigator) then { _unit setVariable [QEGVAR(medical,lastDamageSource), _instigator]; _unit setVariable [QEGVAR(medical,lastInstigator), _instigator]; }; // Common burn areas are the hands and face https://www.ncbi.nlm.nih.gov/pubmed/16899341/ private _bodyPart = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.77, 0.5, 0.8, 0.8, 0.3, 0.3]; // Use event directly, as ace_medical_fnc_addDamageToUnit requires unit to be alive [QEGVAR(medical,woundReceived), [_unit, [[_damageToAdd, _bodyPart, _damageToAdd]], _instigator, "burn"]] call CBA_fnc_localEvent; } else { private _bodyParts = [["HitFace", "HitNeck", "HitHead"], ["HitPelvis", "HitAbdomen", "HitDiaphragm", "HitChest", "HitBody"], ["HitArms", "HitHands"], ["HitLegs"]] selectRandomWeighted [0.77, 0.5, 0.8, 0.3]; { _unit setHitPointDamage [_x, (_unit getHitPointDamage _x) + _damageToAdd, true, _instigator, _instigator]; } forEach _bodyParts; }; _unit setVariable [QGVAR(intensity), _intensity, true]; // Globally sync intensity across all clients to make sure simulation is deterministic }; }, BURN_PROPAGATE_UPDATE, [_unit, _instigator]] call CBA_fnc_addPerFrameHandler;