Medical - Add damage handling for explosive damage while inside vehicles (#9246)

* Add vehicle explosion handling

* Missing semicolon

* scale armor damage using passthrough

* add - to comment

Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>

* improve condition

Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>

* remove extra brackets

Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>

* remove extra brackets

* fix damage sorting

* whitespace

* comment

* fix function header

* fix infinite armor when no item equipped

* modify condition & handling for vehicle explosion

* add vehiclehit woundHandler

* finalize

* add vehiclehit woundHandler

* finalize

* cleanup

* more cleanup

* name

* randomize hitpoints

* finalize

* don't scale structural damage

* fix undefined var

* remove _i

* fix script error, tone down scaling

* add AVD checks

* Update addons/medical_damage/functions/fnc_woundsHandlerVehiclehit.sqf

Co-authored-by: PabstMirror <pabstmirror@gmail.com>

* nuke AVD crew damage handling

* get rid of aircraft crash lethality compensation

---------

Co-authored-by: James Woods <pterolatypus@gmail.com>
Co-authored-by: GhostIsSpooky <69561145+Salluci@users.noreply.github.com>
Co-authored-by: Jouni Järvinen <rautamiekka@users.noreply.github.com>
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
This commit is contained in:
Grim 2023-09-24 15:58:59 -04:00 committed by GitHub
parent 94f3b301e0
commit aee47c9bc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 72 additions and 120 deletions

View File

@ -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;

View File

@ -9,3 +9,4 @@ PREP(woundReceived);
PREP(woundsHandlerBase);
PREP(woundsHandlerBurning);
PREP(woundsHandlerVehiclecrash);
PREP(woundsHandlerVehiclehit);

View File

@ -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 <OBJECT>
* 1: Damage done to each body part <ARRAY>
* 2: Type of the damage done <STRING>
*
* 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

View File

@ -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"];

View File

@ -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 {

View File

@ -5,7 +5,6 @@ PREP(handleVehicleDamage);
PREP(handleCookoff);
PREP(detonate);
PREP(processHit);
PREP(injureOccupants);
PREP(handleDetonation);
PREP(handleDamage);
PREP(knockOut);

View File

@ -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 <OBJECT>
* 1: Injury Chance <NUMBER>
* 2: Maximum people to injure <NUMBER>
* 3: Projectile source <OBJECT> (default: objNull)
* 4: Modifiers for probability for each crew type to be injured. <ARRAY> (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;

View File

@ -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": {