mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
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:
parent
94f3b301e0
commit
aee47c9bc6
@ -167,6 +167,13 @@ class ACE_Medical_Injuries {
|
|||||||
painMultiplier = 0.9;
|
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 {
|
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
|
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;
|
selectionSpecific = 0;
|
||||||
|
@ -9,3 +9,4 @@ PREP(woundReceived);
|
|||||||
PREP(woundsHandlerBase);
|
PREP(woundsHandlerBase);
|
||||||
PREP(woundsHandlerBurning);
|
PREP(woundsHandlerBurning);
|
||||||
PREP(woundsHandlerVehiclecrash);
|
PREP(woundsHandlerVehiclecrash);
|
||||||
|
PREP(woundsHandlerVehiclehit);
|
||||||
|
@ -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
|
@ -61,20 +61,6 @@
|
|||||||
};
|
};
|
||||||
}] call CBA_fnc_addClassEventHandler;
|
}] 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
|
// Fixes units being stuck in unconscious animation when being knocked over by a PhysX object
|
||||||
["CAManBase", "AnimDone", {
|
["CAManBase", "AnimDone", {
|
||||||
params ["_unit", "_anim"];
|
params ["_unit", "_anim"];
|
||||||
|
@ -57,14 +57,16 @@ if (
|
|||||||
0
|
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
|
// 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
|
// It does fire the EH multiple times, but this seems to scale with the intensity of the crash
|
||||||
private _vehicle = vehicle _unit;
|
|
||||||
if (
|
if (
|
||||||
EGVAR(medical,enableVehicleCrashes) &&
|
EGVAR(medical,enableVehicleCrashes) &&
|
||||||
{_hitPoint isEqualTo "#structural"} &&
|
{_hitPoint isEqualTo "#structural"} &&
|
||||||
{_ammo isEqualTo ""} &&
|
{_ammo isEqualTo ""} &&
|
||||||
{_vehicle != _unit} &&
|
{!isNull _vehicle} &&
|
||||||
{vectorMagnitude (velocity _vehicle) > 5}
|
{vectorMagnitude (velocity _vehicle) > 5}
|
||||||
// todo: no way to detect if stationary and another vehicle hits you
|
// todo: no way to detect if stationary and another vehicle hits you
|
||||||
) exitWith {
|
) exitWith {
|
||||||
@ -74,6 +76,29 @@ if (
|
|||||||
0
|
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
|
// This hitpoint is set to trigger last, evaluate all the stored damage values
|
||||||
// to determine where wounds are applied
|
// to determine where wounds are applied
|
||||||
if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
|
if (_hitPoint isEqualTo "ace_hdbracket") exitWith {
|
||||||
|
@ -5,7 +5,6 @@ PREP(handleVehicleDamage);
|
|||||||
PREP(handleCookoff);
|
PREP(handleCookoff);
|
||||||
PREP(detonate);
|
PREP(detonate);
|
||||||
PREP(processHit);
|
PREP(processHit);
|
||||||
PREP(injureOccupants);
|
|
||||||
PREP(handleDetonation);
|
PREP(handleDetonation);
|
||||||
PREP(handleDamage);
|
PREP(handleDamage);
|
||||||
PREP(knockOut);
|
PREP(knockOut);
|
||||||
|
@ -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;
|
|
@ -119,28 +119,6 @@ if (_isCar) then {
|
|||||||
_ammoEffectiveness = (_ammoEffectiveness + (_ammoEffectiveness * 0.5)) min 1;
|
_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 _currentVehicleAmmo = [_vehicle] call EFUNC(cookoff,getVehicleAmmo);
|
||||||
private _chanceOfDetonation = 0;
|
private _chanceOfDetonation = 0;
|
||||||
private _explosiveAmmoCount = 0;
|
private _explosiveAmmoCount = 0;
|
||||||
@ -200,8 +178,6 @@ switch (_hitArea) do {
|
|||||||
[_vehicle, _hitIndex, _hitpointName, _nextPartDamage * _penChance] call FUNC(addDamage);
|
[_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);
|
[_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, _hitArea, false] call FUNC(handleCookoff);
|
||||||
};
|
};
|
||||||
case "hull": {
|
case "hull": {
|
||||||
@ -220,8 +196,6 @@ switch (_hitArea) do {
|
|||||||
[_vehicle] call FUNC(knockOut);
|
[_vehicle] call FUNC(knockOut);
|
||||||
};
|
};
|
||||||
|
|
||||||
[_vehicle, _injuryChance, _injuryCount, _injurer, [1, 0.4, 0.4, 1]] call FUNC(injureOccupants);
|
|
||||||
|
|
||||||
private _hash = _vehicle getVariable [QGVAR(hitpointHash), []];
|
private _hash = _vehicle getVariable [QGVAR(hitpointHash), []];
|
||||||
private _hashKeys = [_hash] call CBA_fnc_hashKeys;
|
private _hashKeys = [_hash] call CBA_fnc_hashKeys;
|
||||||
|
|
||||||
@ -301,7 +275,6 @@ switch (_hitArea) do {
|
|||||||
_vehicle setVariable [QGVAR(canShoot), false];
|
_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);
|
[_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, "", true] call FUNC(handleCookoff);
|
||||||
};
|
};
|
||||||
case "gun": {
|
case "gun": {
|
||||||
|
Loading…
Reference in New Issue
Block a user