diff --git a/addons/medical_damage/ACE_Medical_Injuries.hpp b/addons/medical_damage/ACE_Medical_Injuries.hpp index f09008880ba..8117a2c56ff 100644 --- a/addons/medical_damage/ACE_Medical_Injuries.hpp +++ b/addons/medical_damage/ACE_Medical_Injuries.hpp @@ -167,6 +167,13 @@ class ACE_Medical_Injuries { painMultiplier = 0.9; }; }; + class vehiclehit: explosive { + // vehicle explosions are usually caused by explosive damage and should behave similarly + thresholds[] = {{6, 3}, {4.5, 2}, {2, 2}, {0.8, 1}, {0.2, 1}, {0, 0}}; + class woundHandlers: woundHandlers { + GVAR(vehiclehit) = QFUNC(woundsHandlerVehiclehit); + }; + }; class vehiclecrash { thresholds[] = {{1.5, 3}, {1.5, 2}, {1, 2}, {1, 1}, {0.05, 1}}; // prevent subdividing wounds past FRACTURE_DAMAGE_THRESHOLD to ensure limp/fractue is triggered selectionSpecific = 0; diff --git a/addons/medical_damage/XEH_PREP.hpp b/addons/medical_damage/XEH_PREP.hpp index 6df53fb3091..a17e7d739c5 100644 --- a/addons/medical_damage/XEH_PREP.hpp +++ b/addons/medical_damage/XEH_PREP.hpp @@ -9,3 +9,4 @@ PREP(woundReceived); PREP(woundsHandlerBase); PREP(woundsHandlerBurning); PREP(woundsHandlerVehiclecrash); +PREP(woundsHandlerVehiclehit); diff --git a/addons/medical_damage/functions/fnc_woundsHandlerVehiclehit.sqf b/addons/medical_damage/functions/fnc_woundsHandlerVehiclehit.sqf new file mode 100644 index 00000000000..9c4f864f97c --- /dev/null +++ b/addons/medical_damage/functions/fnc_woundsHandlerVehiclehit.sqf @@ -0,0 +1,37 @@ +#include "..\script_component.hpp" +/* + * Author: Pterolatypus, LinkIsGrim + * Custom wound handler for vehicle hits and explosions, sends damage to a random hitpoint + * + * Arguments: + * 0: Unit That Was Hit + * 1: Damage done to each body part + * 2: Type of the damage done + * + * Return Value: + * None + * + * Example: + * [player, [[0.5, "#structural", 1.5]], "vehiclehit"] call ace_medical_damage_fnc_woundsHandlerVehiclehit + * + * Public: No + */ +params ["_unit", "_allDamages", "_typeOfDamage"]; +TRACE_3("woundsHandlerVehiclehit",_unit,_allDamages,_typeOfDamage); + +// this should only trigger for hits to just structural +if (count _allDamages > 1) exitWith {_this}; + +// damage can sometimes be negative (why?) +// damage to structural is low unless it's a very large explosion, in which case it is typically >= 1 +private _damageToApply = (abs (_allDamages select 0 select 0)); + +private _newDamages = []; + +// hitpoints are randomized, more damage means more wounds in different body parts +for "_i" from 1 to (_damageToApply * 6) do { + _newDamages pushBack [_damageToApply, selectRandom ALL_BODY_PARTS, _damageToApply] +}; + +TRACE_1("Vehicle explosion handled, passing damage", _newDamages); +[_unit, _newDamages, _typeOfDamage] //return diff --git a/addons/medical_engine/XEH_postInit.sqf b/addons/medical_engine/XEH_postInit.sqf index 64f8bab83b7..6455904f95e 100644 --- a/addons/medical_engine/XEH_postInit.sqf +++ b/addons/medical_engine/XEH_postInit.sqf @@ -61,20 +61,6 @@ }; }] call CBA_fnc_addClassEventHandler; -// Guarantee aircraft crashes are more lethal -["Air", "Killed", { - params ["_vehicle", "_killer"]; - TRACE_3("air killed",_vehicle,typeOf _vehicle,velocity _vehicle); - if ((getText (configOf _vehicle >> "destrType")) == "") exitWith {}; - if (unitIsUAV _vehicle) exitWith {}; - - private _lethality = linearConversion [0, 25, (vectorMagnitude velocity _vehicle), 0.5, 1]; - TRACE_2("air crash",_lethality,crew _vehicle); - { - [QEGVAR(medical,woundReceived), [_x, [[_lethality, "Head", _lethality]], _killer, "#vehiclecrash"], _x] call CBA_fnc_targetEvent; - } forEach (crew _vehicle); -}, true, ["ParachuteBase"]] call CBA_fnc_addClassEventHandler; - // Fixes units being stuck in unconscious animation when being knocked over by a PhysX object ["CAManBase", "AnimDone", { params ["_unit", "_anim"]; diff --git a/addons/medical_engine/functions/fnc_handleDamage.sqf b/addons/medical_engine/functions/fnc_handleDamage.sqf index b38b3426cf0..6483f6de648 100644 --- a/addons/medical_engine/functions/fnc_handleDamage.sqf +++ b/addons/medical_engine/functions/fnc_handleDamage.sqf @@ -57,14 +57,16 @@ if ( 0 }; +// Faster than (vehicle _unit), also handles dead units +private _vehicle = objectParent _unit; + // Crashing a vehicle doesn't fire the EH for each hitpoint so the "ace_hdbracket" code never runs // It does fire the EH multiple times, but this seems to scale with the intensity of the crash -private _vehicle = vehicle _unit; if ( EGVAR(medical,enableVehicleCrashes) && {_hitPoint isEqualTo "#structural"} && {_ammo isEqualTo ""} && - {_vehicle != _unit} && + {!isNull _vehicle} && {vectorMagnitude (velocity _vehicle) > 5} // todo: no way to detect if stationary and another vehicle hits you ) exitWith { @@ -74,6 +76,29 @@ if ( 0 }; +// Receiving explosive damage inside a vehicle doesn't trigger for each hitpoint +// This is the case for mines, explosives, artillery, and catasthrophic vehicle explosions +// Triggers twice, but that doesn't matter as damage is low +if ( + _hitPoint isEqualTo "#structural" && + {!isNull _vehicle} && + {_ammo isNotEqualTo ""} && + { + private _ammoCfg = configFile >> "CfgAmmo" >> _ammo; + GET_NUMBER(_ammoCfg >> "explosive", 0) > 0 || + {GET_NUMBER(_ammoCfg >> "indirectHit", 0) > 0} + } +) exitwith { + TRACE_6("Vehicle hit",_unit,_shooter,_instigator,_damage,_newDamage,_damages); + + _unit setVariable [QEGVAR(medical,lastDamageSource), _shooter]; + _unit setVariable [QEGVAR(medical,lastInstigator), _instigator]; + + [QEGVAR(medical,woundReceived), [_unit, [[_newDamage, _hitPoint, _newDamage]], _shooter, "vehiclehit"]] call CBA_fnc_localEvent; + + 0 +}; + // This hitpoint is set to trigger last, evaluate all the stored damage values // to determine where wounds are applied if (_hitPoint isEqualTo "ace_hdbracket") exitWith { diff --git a/addons/vehicle_damage/XEH_PREP.hpp b/addons/vehicle_damage/XEH_PREP.hpp index 0f379e241fa..524fe6ea9dd 100644 --- a/addons/vehicle_damage/XEH_PREP.hpp +++ b/addons/vehicle_damage/XEH_PREP.hpp @@ -5,7 +5,6 @@ PREP(handleVehicleDamage); PREP(handleCookoff); PREP(detonate); PREP(processHit); -PREP(injureOccupants); PREP(handleDetonation); PREP(handleDamage); PREP(knockOut); diff --git a/addons/vehicle_damage/functions/fnc_injureOccupants.sqf b/addons/vehicle_damage/functions/fnc_injureOccupants.sqf deleted file mode 100644 index 172d00e77a5..00000000000 --- a/addons/vehicle_damage/functions/fnc_injureOccupants.sqf +++ /dev/null @@ -1,76 +0,0 @@ -#include "..\script_component.hpp" -/* - * Author: tcvm - * Injures occupants in a vehicle based on percent chance of injury. - * - * Arguments: - * 0: The vehicle - * 1: Injury Chance - * 2: Maximum people to injure - * 3: Projectile source (default: objNull) - * 4: Modifiers for probability for each crew type to be injured. (In order of: driver, gunner, commander, cargo) - * - * Return Value: - * None - * - * Example: - * [myVehicle, 0.6, 10] call ace_vehicle_damage_fnc_injureOccupants; - * - * Public: No - */ - -params ["_vehicle", "_chance", "_count", ["_source", objNull], ["_probabilityModifier", [1, 1, 1, 1]]]; -TRACE_4("adding damage to units", _vehicle, _chance, _count, _source); - -private _vehicleCrew = crew _vehicle; -private _crewCount = count _vehicleCrew; -if (_crewCount <= 0) exitWith {}; - -private _crewInjuryIndices = []; -{ - _crewInjuryIndices pushBack _forEachIndex; -} forEach _vehicleCrew; - -_crewInjuryIndices = _crewInjuryIndices call BIS_fnc_arrayShuffle; - -private _injuryCount = 0; -// Not actually doing anything to any initial vehicle crew in this forEach - just a way to loop through all crew at least once -{ - private _indexToInjure = -1; - { - private _modifier = _probabilityModifier select 3; - if ((_vehicleCrew select _x) isEqualTo driver _vehicle) then { - _modifier = _probabilityModifier select 0; - }; - if ((_vehicleCrew select _x) isEqualTo gunner _vehicle) then { - _modifier = _probabilityModifier select 1; - }; - if ((_vehicleCrew select _x) isEqualTo commander _vehicle) then { - _modifier = _probabilityModifier select 2; - }; - - if ((_chance * _modifier) > random 1) exitWith { - _indexToInjure = _forEachIndex; - }; - } forEach _crewInjuryIndices; - - if (_indexToInjure >= 0) then { - private _casualty = _vehicleCrew select (_crewInjuryIndices select _indexToInjure); - if (alive _casualty) then { - _injuryCount = _injuryCount + 1; - private _indexCount = count _crewInjuryIndices; - if (_indexCount >= 0) then { - _crewInjuryIndices deleteAt _indexToInjure; - - // arbitrary percentages - private _injuredBodyPart = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.3, 0.8, 0.5, 0.5, 0.3, 0.3]; - private _currentUnitDamage = _casualty getHitpointDamage _injuredBodyPart; - private _damageAmount = (_currentUnitDamage + random 1.8) max (_currentUnitDamage + 0.1); - - [_casualty, _damageAmount, _injuredBodyPart, "shell", _source] call EFUNC(medical,addDamageToUnit); - }; - }; - }; - - if (_injuryCount >= _count) exitWith {}; -} forEach _vehicleCrew; diff --git a/addons/vehicle_damage/functions/fnc_processHit.sqf b/addons/vehicle_damage/functions/fnc_processHit.sqf index 3699fc1f5db..48d6ec00557 100644 --- a/addons/vehicle_damage/functions/fnc_processHit.sqf +++ b/addons/vehicle_damage/functions/fnc_processHit.sqf @@ -119,28 +119,6 @@ if (_isCar) then { _ammoEffectiveness = (_ammoEffectiveness + (_ammoEffectiveness * 0.5)) min 1; }; -private _injuryChance = 0; -private _injuryCount = 0; -switch (_warheadType) do { - case WARHEAD_TYPE_AP: { - _injuryChance = (_ammoEffectiveness * 2) min 1; - _injuryCount = 1 + (_ammoEffectiveness * round random 9); - }; - case WARHEAD_TYPE_HE: { - _injuryChance = 0.03 * (1 + _ammoEffectiveness); // spalling injury chance alongside direct hit potential - _injuryCount = 2 + (ceil random 3); - if (_isCar) then { - _injuryChance = 0.8; - _injuryCount = 3 max random count crew _vehicle; - }; - }; - default { - _injuryChance = (4 * _ammoEffectiveness) min 1; - _injuryCount = 2 + round random 3; - }; -}; -_injuryChance = _injuryChance * _penChance; - private _currentVehicleAmmo = [_vehicle] call EFUNC(cookoff,getVehicleAmmo); private _chanceOfDetonation = 0; private _explosiveAmmoCount = 0; @@ -200,8 +178,6 @@ switch (_hitArea) do { [_vehicle, _hitIndex, _hitpointName, _nextPartDamage * _penChance] call FUNC(addDamage); }; - // slightly lower injury chance since this hit the engine block - [_vehicle, _injuryChance, _injuryCount, _injurer, [0.2, 0.2, 0.2, 0.4]] call FUNC(injureOccupants); [_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, _hitArea, false] call FUNC(handleCookoff); }; case "hull": { @@ -220,8 +196,6 @@ switch (_hitArea) do { [_vehicle] call FUNC(knockOut); }; - [_vehicle, _injuryChance, _injuryCount, _injurer, [1, 0.4, 0.4, 1]] call FUNC(injureOccupants); - private _hash = _vehicle getVariable [QGVAR(hitpointHash), []]; private _hashKeys = [_hash] call CBA_fnc_hashKeys; @@ -301,7 +275,6 @@ switch (_hitArea) do { _vehicle setVariable [QGVAR(canShoot), false]; }; - [_vehicle, _injuryChance, _injuryCount, _injurer, [0.5, 1.5, 1.5, 0.8]] call FUNC(injureOccupants); [_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, "", true] call FUNC(handleCookoff); }; case "gun": {