Vary time taken to bandage based on circumstances (#6467)

This commit is contained in:
SilentSpike 2018-07-25 09:35:04 +01:00 committed by GitHub
parent 78ee7d4677
commit 39b1d144e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 150 additions and 77 deletions

View File

@ -61,6 +61,16 @@
// Minimum body part damage required for blood effect on uniform
#define VISUAL_BODY_DAMAGE_THRESHOLD 0.35
// Empty wound data, used for some default return values
// [ID, classID, bodypartIndex, amountOf, bloodloss, damage, category]
#define EMPTY_WOUND [-1, -1, -1, 0, 0, 0, 0]
// Base time to bandage each wound category
#define BANDAGE_TIME_S 4
#define BANDAGE_TIME_M 6
#define BANDAGE_TIME_L 8
#define BANDAGE_TIME_MOD_MEDIC -2
#define BANDAGE_TIME_MOD_SELF 4
// - Unit Variables ----------------------------------------------------

View File

@ -9,7 +9,7 @@ class GVAR(Actions) {
allowedSelections[] = {"All"};
allowSelfTreatment = 1;
requiredMedic = 0;
treatmentTime = 8;
treatmentTime = QFUNC(getBandageTime);
treatmentTimeSelfCoef = 1;
items[] = {{"ACE_fieldDressing", "ACE_packingBandage", "ACE_elasticBandage", "ACE_quikclot"}};
condition = QUOTE(!EGVAR(medical,advancedBandages));

View File

@ -45,6 +45,8 @@ PREP(bodyCleanupLoop);
PREP(calculateBlood);
PREP(canAccessMedicalEquipment);
PREP(dropDownTriageCard);
PREP(findMostEffectiveWound);
PREP(getBandageTime);
PREP(getTriageStatus);
PREP(handleBandageOpening);
PREP(hasTourniquetAppliedTo);

View File

@ -0,0 +1,73 @@
#include "script_component.hpp"
/*
* Author: SilentSpike
* Finds the wound most effective to bandage on the given bodypart of the patient for the given bandage type.
*
* Arguments:
* 0: The patient <OBJECT>
* 1: Treatment class name <STRING>
* 2: Body part index <NUMBER>
*
* Return Value:
* [Wound, Index, Effectiveness] <ARRAY, NUMBER, NUMBER>
*
* Public: No
*/
params ["_patient", "_bandage", "_partIndex"];
// Get the default effectiveness for the used bandage
private _config = configFile >> QUOTE(ADDON) >> "Bandaging";
private _effectiveness = getNumber (_config >> "effectiveness");
if (isClass (_config >> _bandage)) then {
_config = (_config >> _bandage);
if (isNumber (_config >> "effectiveness")) then {
_effectiveness = getNumber (_config >> "effectiveness");
};
};
// Iterate over open wounds to find the most effective target
private _openWounds = _patient getVariable [QEGVAR(medical,openWounds), []];
if (_openWounds isEqualTo []) exitWith { [EMPTY_WOUND, -1, -1] };
private _wound = EMPTY_WOUND;
private _woundIndex = -1;
private _effectivenessFound = -1;
{
_x params ["", "_classID", "_partIndexN", "_amountOf", "_bleeding", "_damage", "_category"];
// Ignore wounds on other bodyparts
if (_partIndexN == _partIndex) then {
private _woundEffectiveness = _effectiveness;
// Select the classname from the wound classname storage
private _suffix = ["Minor", "Medium", "Large"] select _category;
private _className = format ["%1%2", EGVAR(medical_damage,woundClassNames) select _classID, _suffix];
// Get the effectiveness of the bandage on this wound type
if (isClass (_config >> _className)) then {
private _woundTreatmentConfig = _config >> _className;
if (isNumber (_woundTreatmentConfig >> "effectiveness")) then {
_woundEffectiveness = getNumber (_woundTreatmentConfig >> "effectiveness");
};
} else {
// Basic medical bandage just has a base level config (same effectivenes for all wound types)
if (_bandage != "BasicBandage") then {
WARNING_2("No config for wound type [%1] config base [%2]",_className,_config);
};
};
// Track most effective found so far
if (_woundEffectiveness * _amountOf * _bleeding > _effectivenessFound * (_wound select 3) * (_wound select 4)) then {
_effectivenessFound = _woundEffectiveness;
_woundIndex = _forEachIndex;
_wound = _x;
};
};
} forEach _openWounds;
[_wound, _woundIndex, _effectivenessFound]

View File

@ -0,0 +1,49 @@
#include "script_component.hpp"
/*
* Author: SilentSpike
* Calculates the time to bandage a wound based on it's size, the patient and the medic.
*
* Arguments:
* 0: The medic <OBJECT>
* 1: The patient <OBJECT>
* 2: Body part <STRING>
* 3: Treatment class name <STRING>
*
* Return Value:
* Time in seconds <NUMBER>
*
* Public: No
*/
params ["_medic", "_patient", "_bodypart", "_bandage"];
private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
if (_partIndex < 0) exitWith { 0 };
private _targetWound = [_patient, _bandage, _partIndex] call FUNC(findMostEffectiveWound);
_targetWound params ["_wound", "_woundIndex", "_effectiveness"];
// Everything is patched up on this body part already
if (_wound isEqualTo EMPTY_WOUND) exitWith { 0 };
_wound params ["", "", "", "_amountOf", "_bloodloss", "_damage", "_category"];
// Base bandage time is based on wound size and remaining percentage
private _bandageTime = ([
BANDAGE_TIME_S,
BANDAGE_TIME_M,
BANDAGE_TIME_L
] select _category) * _amountOf;
// Medics are more practised at applying bandages
if ([_medic] call FUNC(isMedic)) then {
_bandageTime = _bandageTime + BANDAGE_TIME_MOD_MEDIC;
};
// Bandaging yourself requires more work
if (_medic == _patient) then {
_bandageTime = _bandageTime + BANDAGE_TIME_MOD_SELF;
};
// Nobody can bandage instantly
_bandageTime max 1

View File

@ -11,7 +11,7 @@
* Return Value:
* Succesful treatment started <BOOL>
*
* Public: Yes
* Public: No
*/
#include "script_component.hpp"
@ -133,10 +133,9 @@ if (vehicle _caller == _caller && {_callerAnim != ""}) then {
_caller setVariable [QGVAR(endInAnim), _endInAnim];
};
// get treatment time
// get treatment time from config - also supports variables and code expressions
private _treatmentTime = 0;
// reads number from config. supports variables and code expressions
if (isNumber (_config >> "treatmentTime")) then {
_treatmentTime = getNumber (_config >> "treatmentTime");
} else {

View File

@ -8,21 +8,20 @@
* 2: Body part <STRING>
* 3: Treatment class name <STRING>
* 4: Item <STRING>
* 5: specific Spot <NUMBER> (default: -1)
*
* Return Value:
* Succesful treatment started <BOOL>
*
* Public: Yes
* Public: No
*/
#include "script_component.hpp"
params ["_caller", "_target", "_bodyPart", "_className", "_items", "", ["_specificSpot", -1]];
params ["_caller", "_target", "_bodyPart", "_className", "_items"];
[_target, "activity", ELSTRING(medical_treatment,Activity_bandagedPatient), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog);
[_target, "activity_view", ELSTRING(medical_treatment,Activity_bandagedPatient), [[_caller, false, true] call EFUNC(common,getName)]] call FUNC(addToLog); // TODO expand message
[QGVAR(treatmentBandageLocal), [_target, _className, _bodyPart, _specificSpot], _target] call CBA_fnc_targetEvent;
[QGVAR(treatmentBandageLocal), [_target, _className, _bodyPart], _target] call CBA_fnc_targetEvent;
/*{
if (_x != "") then {

View File

@ -14,7 +14,7 @@
*/
#include "script_component.hpp"
params ["_target", "_bandage", "_bodyPart", ["_specificClass", -1]];
params ["_target", "_bandage", "_bodyPart"];
private _partIndex = ALL_BODY_PARTS find toLower _bodyPart;
if (_partIndex < 0) exitWith { false };
@ -22,84 +22,25 @@ if (_partIndex < 0) exitWith { false };
private _openWounds = _target getVariable [QEGVAR(medical,openWounds), []];
if (_openWounds isEqualTo []) exitWith { false };
// Get the default effectiveness for the used bandage
private _config = configFile >> QUOTE(ADDON) >> "Bandaging";
private _effectiveness = getNumber (_config >> "effectiveness");
if (isClass (_config >> _bandage)) then {
_config = (_config >> _bandage);
if (isNumber (_config >> "effectiveness")) then {
_effectiveness = getNumber (_config >> "effectiveness");
};
};
// Figure out which injury for this bodypart is the best choice to bandage
// TODO also use up the remainder on left over injuries
private _mostEffectiveSpot = 0;
private _effectivenessFound = -1;
private _mostEffectiveInjury = _openWounds select 0;
private _exit = false;
private _targetWound = [_target, _bandage, _partIndex] call FUNC(findMostEffectiveWound);
_targetWound params ["_wound", "_woundIndex", "_effectiveness"];
{
_x params ["", "_classID", "_partIndexN", "_amountOf", "_bleeding", "_damage", "_category"];
TRACE_2("OPENWOUND: ", _target, _x);
// Only parse injuries that are for the selected bodypart.
if (_partIndexN == _partIndex) then {
private _woundEffectiveness = _effectiveness;
// Select the classname from the wound classname storage
private _postfix = ["Minor", "Medium", "Large"] select _category;
private _className = format ["%1%2", EGVAR(medical_damage,woundClassNames) select _classID, _postfix];
// Check if this wound type has attributes specified for the used bandage
if (isClass (_config >> _className)) then {
// Collect the effectiveness from the used bandage for this wound type
private _woundTreatmentConfig = _config >> _className;
if (isNumber (_woundTreatmentConfig >> "effectiveness")) then {
_woundEffectiveness = getNumber (_woundTreatmentConfig >> "effectiveness");
};
} else {
//Basic medical bandage just has a base level config (same effectivenes for all wound types)
if (_bandage != "BasicBandage") then {
WARNING_2("No config for wound type [%1] config base [%2]", _className, _config);
};
};
TRACE_2("Wound classes: ", _specificClass, _classID);
if (_specificClass == _classID) exitWith {
_effectivenessFound = _woundEffectiveness;
_mostEffectiveSpot = _forEachIndex;
_mostEffectiveInjury = _x;
_exit = true;
};
// Check if this is the currently most effective found.
if (_woundEffectiveness * _amountOf * _bleeding > _effectivenessFound * (_mostEffectiveInjury select 3) * (_mostEffectiveInjury select 4)) then {
_effectivenessFound = _woundEffectiveness;
_mostEffectiveSpot = _forEachIndex;
_mostEffectiveInjury = _x;
};
};
if (_exit) exitWith {};
} forEach _openWounds;
if (_effectivenessFound == -1) exitWith {}; // Seems everything is patched up on this body part already..
// Everything is patched up on this body part already
if (_effectiveness == -1) exitWith {};
// Find the impact this bandage has and reduce the amount this injury is present
private _amountOf = _mostEffectiveInjury select 3;
private _impact = _effectivenessFound min _amountOf;
_mostEffectiveInjury set [3, _amountOf - _impact];
_openWounds set [_mostEffectiveSpot, _mostEffectiveInjury];
private _amountOf = _wound select 3;
private _impact = _effectiveness min _amountOf;
_wound set [3, _amountOf - _impact];
_openWounds set [_woundIndex, _wound];
_target setVariable [QEGVAR(medical,openWounds), _openWounds, true];
// Handle the reopening of bandaged wounds
if (_impact > 0 && {EGVAR(medical,advancedBandages) && {EGVAR(medical,woundReopening)}}) then {
[_target, _impact, _partIndex, _mostEffectiveSpot, _mostEffectiveInjury, _bandage] call FUNC(handleBandageOpening);
[_target, _impact, _partIndex, _woundIndex, _wound, _bandage] call FUNC(handleBandageOpening);
};
true