Rework pain simulation

This commit is contained in:
BaerMitUmlaut 2019-10-07 01:36:55 +02:00
parent 1128ff0f3f
commit f11a8848e3
16 changed files with 261 additions and 124 deletions

View File

@ -1,3 +1,5 @@
PREP(addCustomPain);
PREP(addDamageToUnit);
PREP(adjustPainLevel);
PREP(getCustomPain);
PREP(setCustomPain);
PREP(setUnconscious);

View File

@ -0,0 +1,35 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Adds pain from external components or mods on a unit.
*
* Custom pain will never decrease when calling this function, the maximum of
* the current and the parameter value will be used. Use setCustomPain in
* combination with getCustomPain to decrease custom pain instead. This
* function is intended for pain events, like pain from bumping your head.
*
* Arguments:
* 0: Unit (needs to be local) <OBJECT>
* 1: Pain amount (range: 0..1) <NUMBER>
* 2: Pain index, -1 to assign new index (default: 0) <NUMBER>
* 3: Enable pain decay (default: true) <BOOL>
*
* Return Value:
* Pain index <NUMBER>
*
* Example:
* // One time light pain event (without an index, can be changed by other mods), e.g. bumping your head
* [player, 0.3] call ace_medical_fnc_addCustomPain;
* // Pain source that can be manually decreased later, e.g. an open wound
* mod_painIdx = [player, 0.5, [mod_painIdx] param [0, -1]] call ace_medical_fnc_addCustomPain;
* // Permanent pain source that does not decay, e.g. a broken heart
* mod_painIdx = [player, 1, [mod_painIdx] param [0, -1], false] call ace_medical_fnc_addCustomPain;
*
* Public: Yes
*/
params ["_unit", "_addedPain", "_index", "_enableDecay"];
private _oldPain = [_unit, _index] call FUNC(getCustomPain);
private _newPain = 0 max (_oldPain max _addedPain) min 1;
[_unit, _newPain, _index, _enableDecay] call FUNC(setCustomPain);

View File

@ -1,28 +0,0 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Public interface to allow external modules to safely adjust pain levels.
* Added pain can be positive or negative (Note: ignores painCoefficient setting)
*
* Arguments:
* 0: The patient <OBJECT>
* 1: Added ammount of pain (can be negative) <NUMBER>
*
* Return Value:
* The new pain level <NUMBER>
*
* Example:
* [guy, 0.5] call ace_medical_fnc_adjustPainLevel
*
* Public: Yes
*/
params ["_unit", "_addedPain"];
if (!local _unit) exitWith { ERROR_1("unit [%1] is not local",_unit); };
private _pain = GET_PAIN(_unit);
_pain = 0 max (_pain + _addedPain) min 1;
_unit setVariable [VAR_PAIN, _pain];

View File

@ -0,0 +1,27 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Gets pain from external components or mods on a unit.
*
* Arguments:
* 0: Unit (needs to be local) <OBJECT>
* 1: Pain index (default: 0) <NUMBER>
*
* Return Value:
* Pain amount <NUMBER>
*
* Example:
* private _pain = [player, mod_painIdx] call ace_medical_fnc_getCustomPain;
*
* Public: Yes
*/
params [
["_unit", objNull, [objNull]],
["_index", 0, [0]]
];
if (!local _unit) exitWith {
ERROR_1("Unit [%1] is not local",_unit);
};
[_unit, _index] call EFUNC(medical_vitals,getCustomPain);

View File

@ -0,0 +1,41 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Sets pain from external components or mods on a unit.
*
* This function allows you to define your own mod's pain source, which you can
* manually increase and decrease later. If you want to be Zeus compatible,
* make sure to save the returned index on the unit itself, as it might not be
* the same for every unit.
*
* Arguments:
* 0: Unit (needs to be local) <OBJECT>
* 1: Pain amount (range: 0..1) <NUMBER>
* 2: Pain index, -1 to assign new index (default: 0) <NUMBER>
* 3: Enable pain decay (default: true) <BOOL>
*
* Return Value:
* Pain index <NUMBER>
*
* Example:
* // Pain source that can be manually decreased later, e.g. an open wound
* mod_painIdx = [player, 0.5, [mod_painIdx] param [0, -1]] call ace_medical_fnc_setCustomPain;
* // Heal custom pain source, e.g. treat an open wound
* mod_painIdx = [player, 0, [mod_painIdx] param [0, -1]] call ace_medical_fnc_setCustomPain;
* // Permanent pain source that does not decay, e.g. a broken heart
* mod_painIdx = [player, 1, [mod_painIdx] param [0, -1], false] call ace_medical_fnc_addCustomPain;
*
* Public: Yes
*/
params [
["_unit", objNull, [objNull]],
["_pain", 0, [0]],
["_index", 0, [0]],
["_enableDecay", true, [false]]
];
if (!local _unit) exitWith {
ERROR_1("Unit [%1] is not local",_unit);
};
[_unit, _pain, _index, _enableDecay] call EFUNC(medical_vitals,setCustomPain);

View File

@ -114,8 +114,8 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra
private _classComplex = 10 * _woundClassIDToAdd + _category;
// Create a new injury. Format [0:classComplex, 1:bodypart, 2:amountOf, 3:bleedingRate, 4:woundDamage]
private _injury = [_classComplex, _bodyPartNToAdd, 1, _bleeding, _woundDamage];
// Create a new injury. Format [0:classComplex, 1:bodypart, 2:amountOf, 3:bleedingRate, 4:woundDamage, 5:pain]
private _injury = [_classComplex, _bodyPartNToAdd, 1, _bleeding, _woundDamage, _painLevel];
if (_bodyPartNToAdd == 0 || {_bodyPartNToAdd == 1 && {_woundDamage > PENETRATION_THRESHOLD}}) then {
_critialDamage = true;
@ -156,7 +156,7 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra
// if possible merge into existing wounds
private _createNewWound = true;
{
_x params ["_classID", "_bodyPartN", "_oldAmountOf", "_oldBleeding", "_oldDamage"];
_x params ["_classID", "_bodyPartN", "_oldAmountOf", "_oldBleeding", "_oldDamage", "_oldPainLevel"];
if (
(_classComplex == _classID) &&
{_bodyPartNToAdd == _bodyPartN} &&
@ -170,6 +170,8 @@ private _bodyPartVisParams = [_unit, false, false, false, false]; // params arra
_x set [3, _newBleeding];
private _newDamage = (_oldAmountOf * _oldDamage + _woundDamage) / _newAmountOf;
_x set [4, _newDamage];
private _newPainLevel = _painLevel max _oldPainLevel;
_x set [5, _newPainLevel];
_createNewWound = false;
};
} forEach _openWounds;
@ -193,8 +195,6 @@ _unit setVariable [QEGVAR(medical,bodyPartDamage), _bodyPartDamage, true];
_bodyPartVisParams call EFUNC(medical_engine,updateBodyPartVisuals);
[QEGVAR(medical,injured), [_unit, _painLevel]] call CBA_fnc_localEvent;
if (_critialDamage || {_painLevel > PAIN_UNCONSCIOUS}) then {
[_unit] call FUNC(handleIncapacitation);
};

View File

@ -10,12 +10,6 @@ class Extended_PreInit_EventHandlers {
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_FILE(XEH_postInit));
};
};
class Extended_Init_EventHandlers {
class CAManBase {
class ADDON {

View File

@ -1,5 +1,4 @@
PREP(addMedicationAdjustment);
PREP(adjustPainLevel);
PREP(getBloodLoss);
PREP(getBloodPressure);
PREP(getBloodVolumeChange);

View File

@ -1,4 +0,0 @@
#include "script_component.hpp"
// Handle pain changes on injury
[QEGVAR(medical,injured), LINKFUNC(adjustPainLevel)] call CBA_fnc_addEventHandler;

View File

@ -1,31 +0,0 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Interface to allow external modules to affect the pain level
* Sets the new pain level to the max between the input and current level
*
* Arguments:
* 0: The patient <OBJECT>
* 1: Desired pain level (0 .. 1) <NUMBER>
*
* Return Value:
* None
*
* Example:
* [guy, 0.5] call ace_medical_status_fnc_adjustPainLevel
*
* Public: No
*/
params ["_unit", "_desiredPainLevel"];
if (!local _unit) exitWith { ERROR("unit is not local"); };
TRACE_2("adjustPainLevel",_unit,_desiredPainLevel);
_desiredPainLevel = _desiredPainLevel * EGVAR(medical,painCoefficient);
private _pain = GET_PAIN(_unit);
_pain = 0 max (_pain max _desiredPainLevel) min 1;
_unit setVariable [VAR_PAIN, _pain];

View File

@ -1,4 +1,6 @@
PREP(getCustomPain);
PREP(handleUnitVitals);
PREP(setCustomPain);
PREP(updateHeartRate);
PREP(updatePainSuppress);
PREP(updatePain);
PREP(updatePeripheralResistance);

View File

@ -0,0 +1,23 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Gets pain from external components or mods on a unit.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Pain index (default: 0) <NUMBER>
*
* Return Value:
* Pain amount <NUMBER>
*
* Example:
* private _pain = [player, mod_painIdx] call ace_medical_vitals_fnc_getCustomPain;
*
* Public: No
*/
params ["_unit", ["_index", 0]];
private _customPain = _unit getVariable [QGVAR(customPain), []];
// Absolute value for non decaying pain, which is saved as a negative value
abs (_customPain param [_index, 0])

View File

@ -58,18 +58,6 @@ if !(_inPain isEqualTo IS_IN_PAIN(_unit)) then {
_unit setVariable [VAR_IN_PAIN, _inPain, true];
};
// Handle pain due tourniquets, that have been applied more than 120 s ago
private _tourniquetPain = 0;
private _tourniquets = GET_TOURNIQUETS(_unit);
{
if (_x > 0 && {CBA_missionTime - _x > 120}) then {
_tourniquetPain = _tourniquetPain max (CBA_missionTime - _x - 120) * 0.001;
};
} forEach _tourniquets;
if (_tourniquetPain > 0) then {
[_unit, _tourniquetPain] call EFUNC(medical_status,adjustPainLevel);
};
// Get Medication Adjustments:
private _hrTargetAdjustment = 0;
private _painSupressAdjustment = 0;
@ -99,7 +87,7 @@ if !(_adjustments isEqualTo []) then {
};
private _heartRate = [_unit, _hrTargetAdjustment, _deltaT, _syncValues] call FUNC(updateHeartRate);
[_unit, _painSupressAdjustment, _deltaT, _syncValues] call FUNC(updatePainSuppress);
[_unit, _painSupressAdjustment, _deltaT, _syncValues] call FUNC(updatePain);
[_unit, _peripheralResistanceAdjustment, _deltaT, _syncValues] call FUNC(updatePeripheralResistance);
private _bloodPressure = GET_BLOOD_PRESSURE(_unit);

View File

@ -0,0 +1,37 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Sets pain from external components or mods on a unit.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Pain amount (range: 0..1) <NUMBER>
* 2: Pain index, -1 to assign new index (default: 0) <NUMBER>
* 3: Enable pain decay (default: true) <BOOL>
*
* Return Value:
* Pain index <NUMBER>
*
* Example:
* mod_painIdx = [player, 0.5, [mod_painIdx] param [0, -1]] call ace_medical_vitals_fnc_setCustomPain;
*
* Public: No
*/
params ["_unit", "_pain", ["_index", 0], ["_enableDecay", true]];
private _customPain = _unit getVariable [QGVAR(customPain), [0]];
_pain = 0 max _pain min 1;
if (_index == -1) then {
_index = count _customPain;
};
if (!_enableDecay) then {
_pain = -_pain;
};
_customPain set [_index, _pain];
_unit setVariable [QGVAR(customPain), _customPain];
_index

View File

@ -0,0 +1,86 @@
#include "script_component.hpp"
/*
* Author: Glowbal
* Update the pain suppression
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Pain Suppress Adjustments <NUMBER>
* 2: Time since last update <NUMBER>
* 3: Sync value? <BOOL>
*
* Return Value:
* None
*
* Example:
* [player, 0, 1, false] call ace_medical_vitals_fnc_updatePainSuppress
*
* Public: No
*/
params ["_unit", "_painSupressAdjustment", "_deltaT", "_syncValue"];
_unit setVariable [VAR_PAIN_SUPP, 0 max _painSupressAdjustment, _syncValue];
// Pain value formula: maximum of
// - most painful open wound * (1 + 0.1 * count of open wounds)
// - most painful bandaged wound * (1 + 0.1 * count of bandaged wounds)
// - most painful stitched wound * (1 + 0.1 * count of stitched wounds)
// - most painful tourniquet
// Pain from wounds
private _woundsPain = selectMax ([
GET_OPEN_WOUNDS(_unit),
GET_BANDAGED_WOUNDS(_unit),
GET_STITCHED_WOUNDS(_unit)
] apply {
selectMax (_x apply { _x#5 })
});
// Pain from tourniquets
private _tourniquetPain = selectMax (GET_TOURNIQUETS(_unit) apply {
if (_x > 0 && {CBA_missionTime - _x > 120}) then {
(CBA_missionTime - _x - 120) * 0.001
} else {
0
};
});
// Pain from other components or mods
private _customPain = selectMax (_unit getVariable [QGVAR(customPain), []] apply { abs _x });
// Update total pain
private _totalPain = selectMax [_woundsPain, _tourniquetPain, _customPain];
_unit setVariable [VAR_PAIN, 0 max _totalPain min 1, _syncValue];
// Pain decay
// Open wounds do not have pain decay
// Closed and bandaged wound pain decays at the same rate (because stitching hurts, too)
// Decaying custom pain sources are positive, non-decaying custom pain is negative
// Bandaged and stitched wounds
{
{
_x set [5, 0 max (_x#5 - _deltaT / PAIN_FADE_TIME)];
} forEach _x;
} forEach [
GET_BANDAGED_WOUNDS(_unit),
GET_STITCHED_WOUNDS(_unit)
];
// Custom pain sources
private _customPain = _unit getVariable [QGVAR(customPain), []];
{
if (_x > 0) then {
_customPain set [_forEachIndex, 0 max (_x - _deltaT / PAIN_FADE_TIME)];
};
} forEach _customPain;
// No need to setVariable because array reference
// Handles simple medication pain supppression
if (isNil QEGVAR(medical_treatment,advancedMedication) || {!EGVAR(medical_treatment,advancedMedication)}) then {
private _painSupress = _unit getVariable [VAR_PAIN_SUPP, 0];
_painSupress = _painSupress - _deltaT / PAIN_SUPPRESSION_FADE_TIME;
_unit setVariable [VAR_PAIN_SUPP, 0 max _painSupress, _syncValue];
};

View File

@ -1,34 +0,0 @@
#include "script_component.hpp"
/*
* Author: Glowbal
* Update the pain suppression
*
* Arguments:
* 0: The Unit <OBJECT>
* 1: Pain Suppress Adjustments <NUMBER>
* 2: Time since last update <NUMBER>
* 3: Sync value? <BOOL>
*
* Return Value:
* None
*
* Example:
* [player, 0, 1, false] call ace_medical_vitals_fnc_updatePainSuppress
*
* Public: No
*/
params ["_unit", "_painSupressAdjustment", "_deltaT", "_syncValue"];
_unit setVariable [VAR_PAIN_SUPP, 0 max _painSupressAdjustment, _syncValue];
// Handle continuous pain reduction
private _pain = GET_PAIN(_unit);
_unit setVariable [VAR_PAIN, 0 max (_pain - _deltaT / PAIN_FADE_TIME), _syncValue];
// Handles simple medication
if (isNil QEGVAR(medical_treatment,advancedMedication) || {!EGVAR(medical_treatment,advancedMedication)}) then {
private _painSupress = _unit getVariable [VAR_PAIN_SUPP, 0];
_painSupress = _painSupress - _deltaT / PAIN_SUPPRESSION_FADE_TIME;
_unit setVariable [VAR_PAIN_SUPP, 0 max _painSupress, _syncValue];
};