Fast medical item replacement (#7224)

* Add item replacement framework

* Correctance of English

Co-Authored-By: Dedmen Miller <dedmen@users.noreply.github.com>

* Remove unecessary code

* Use new item replacement framework for medical items

* minor fixes, support GVAR(convertItems) setting

* use forEach, convert atropine to epi

* replace with adenosine
This commit is contained in:
BaerMitUmlaut 2019-10-11 22:00:25 +02:00 committed by PabstMirror
parent 6ca4b2075d
commit bb0461be16
7 changed files with 150 additions and 60 deletions

View File

@ -138,6 +138,7 @@ PREP(positionToASL);
PREP(progressBar);
PREP(readSettingFromModule);
PREP(receiveRequest);
PREP(registerItemReplacement);
PREP(removeCanInteractWithCondition);
PREP(removeSpecificMagazine);
PREP(requestCallback);

View File

@ -0,0 +1,112 @@
#include "script_component.hpp"
/*
* Author: BaerMitUmlaut
* Registers an event handler that replaces an item or item type with one or
* more other items.
*
* Arguments:
* 0: Item or item type ID to replace <STRING or NUMBER>
* 1: Item or list of items <STRING or ARRAY>
* 2: Replace items that inherit from original item (only if 0 is STRING) (Optional)<BOOL>
*
* Return Value:
* None
*
* Example:
* ["FirstAidKit", "ACE_fieldDressing"] call ace_common_fnc_registerItemReplacement
*
* Public: Yes
*/
params [["_oldItem", "", [0,""]], ["_newItems", "", ["", []]], ["_replaceInherited", false, [false]]];
TRACE_3("registerItemReplacement",_oldItem,_newItems,_replaceInherited);
// CBA player event handler function
private _fnc_replaceItems = {
params ["_unit"];
private _items = items _unit;
if (_items isEqualTo GVAR(oldItems)) exitWith {};
private _newItems = _items - GVAR(oldItems);
if (_newItems isEqualTo []) exitWith {
GVAR(oldItems) = _items;
};
_newItems sort true; // Sort so all items of current class can be replaced at once
private _cfgWeapons = configFile >> "CfgWeapons"; // Microoptimization
for "_i" from 0 to count _newItems - 1 do {
private _item = _newItems#_i;
// Determine replacement items: direct replacements, ...
private _replacements = GVAR(itemReplacements) getVariable [_item, []];
// ... item type replacements ...
private _type = getNumber (_cfgWeapons >> _item >> "ItemInfo" >> "type");
private _typeReplacements = GVAR(itemReplacements) getVariable ["$" + str _type, []];
_replacements append _typeReplacements;
// ... and inherited replacements
{
if (_item isKindOf [_x, _cfgWeapons]) then {
private _inheritedReplacements = GVAR(itemReplacements) getVariable [_x, []];
_replacements append _inheritedReplacements;
};
} forEach GVAR(inheritedReplacements);
// Skip lookup for all following items of this class
private _count = 1;
while {_newItems#(_i + 1) == _item} do { // (i+1) can be out of bounds, but should fail safely
_count = _count + 1;
_i = _i + 1;
};
// Replace all items of current class in list
if !(_replacements isEqualTo []) then {
TRACE_3("replace",_item,_count,_replacements);
_unit removeItems _item;
for "_j" from 1 to _count do {
{ [_unit, _x] call FUNC(addToInventory) } forEach _replacements;
};
};
};
GVAR(oldItems) = items _unit;
};
// Setup on first run
if (isNil QGVAR(itemReplacements)) then {
GVAR(itemReplacements) = [] call CBA_fnc_createNamespace;
GVAR(inheritedReplacements) = [];
GVAR(oldItems) = [];
["loadout", _fnc_replaceItems] call CBA_fnc_addPlayerEventHandler;
};
// Save item replacement
// $ prefix is used for types (numbers) and replacements with inheritance
if (_replaceInherited) then {
_oldItem = "$" + _oldItem;
GVAR(inheritedReplacements) pushBack _oldItem;
};
if (_oldItem isEqualType 0) then {
_oldItem = "$" + str _oldItem;
};
if (_newItems isEqualType "") then {
_newItems = [_newItems];
};
private _oldReplacements = GVAR(itemReplacements) getVariable [_oldItem, []];
_oldReplacements append _newItems;
GVAR(itemReplacements) setVariable [_oldItem, _newItems];
// Force item scan when new replacement was registered in PostInit
if (!isNull ACE_player) then {
GVAR(oldItems) = [];
// Exec next frame to ensure full scan only runs once per frame
// For example, if item replacements are registred in PostInit (due to CBA
// settings) by different addons, the inventory is only scanned once in the
// next frame, not once per addon.
[_fnc_replaceItems, [ACE_player]] call CBA_fnc_execNextFrame;
};

View File

@ -1,11 +1,14 @@
// This config accepts both item type numbers and item class names
// Item type numbers need the prefix ItemType_, so for example ItemType_401
// Class names need no special prefix
class EGVAR(medical,replacementItems) {
FirstAidKit[] = {
DOUBLES(ItemType,TYPE_FIRST_AID_KIT)[] = {
{"ACE_fieldDressing", 1},
{"ACE_packingBandage", 1},
{"ACE_morphine", 1},
{"ACE_tourniquet", 1}
};
Medikit[] = {
DOUBLES(ItemType,TYPE_MEDIKIT)[] = {
{"ACE_fieldDressing", 1},
{"ACE_packingBandage", 2},
{"ACE_epinephrine", 1},
@ -14,5 +17,7 @@ class EGVAR(medical,replacementItems) {
{"ACE_tourniquet", 1},
{"ACE_splint", 2}
};
// todo: add GM medical items
ACE_atropine[] = {
{"ACE_adenosine", 1}
};
};

View File

@ -13,7 +13,6 @@ PREP(canTreatCached);
PREP(canTreat_holsterCheck);
PREP(checkBloodPressure);
PREP(checkBloodPressureLocal);
PREP(checkItems);
PREP(checkPulse);
PREP(checkPulseLocal);
PREP(checkResponse);

View File

@ -9,12 +9,8 @@
} forEach (_unit getVariable [QEGVAR(medical,allLogs), []]);
_unit setVariable [QEGVAR(medical,allLogs), [], true];
[_unit] call FUNC(checkItems);
}] call CBA_fnc_addEventHandler;
["loadout", LINKFUNC(checkItems)] call CBA_fnc_addPlayerEventHandler;
// Handle body removal and litter on server
if (isServer) then {
[QGVAR(createLitterServer), LINKFUNC(createLitterServer)] call CBA_fnc_addEventHandler;
@ -36,3 +32,32 @@ if (isServer) then {
// Logging events
[QGVAR(addToLog), LINKFUNC(addToLog)] call CBA_fnc_addEventHandler;
[QGVAR(addToTriageCard), LINKFUNC(addToTriageCard)] call CBA_fnc_addEventHandler;
// replace medical items with their ACE equivalents
["ace_settingsInitialized", {
TRACE_1("ace_settingsInitialized EH",GVAR(convertItems)); // 0: Enabled 1: RemoveOnly 2:Disabled
if (GVAR(convertItems) == 2) exitWith {};
{
// turn [["stuff", 2], ...] into ["stuff", "stuff", ...]
private _replacements = [];
if (GVAR(convertItems) == 0) then {
{
_x params ["_item", "_count"];
for "_i" from 1 to _count do {
_replacements pushBack _item;
};
} forEach getArray _x;
};
// check if replacement is for item type or class name
private _configName = configName _x;
private _toReplace = if ((_configName select [0,9]) == "ItemType_") then {
parseNumber (_configName select [9])
} else {
_configName
};
// register replacement
[_toReplace, _replacements] call EFUNC(common,registerItemReplacement);
} forEach (configProperties [configFile >> QEGVAR(medical,replacementItems), "isArray _x"]);
}] call CBA_fnc_addEventHandler;

View File

@ -44,9 +44,4 @@ GVAR(facilityClasses) = [];
} forEach getArray _x;
} forEach configProperties [configFile >> QEGVAR(medical,facilities), "isArray _x"];
// array of medical items to replace and their ACE equivalents
GVAR(replacementItems) = configProperties [configFile >> QEGVAR(medical,replacementItems), "isArray _x"] apply {
[configName _x, getArray _x]
};
ADDON = true;

View File

@ -1,47 +0,0 @@
#include "script_component.hpp"
/*
* Author: KoffeinFlummi, commy2, mharis001
* Handles converting vanilla medical items with ACE equivalents.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* [player] call ace_medical_treatment_fnc_checkItems
*
* Public: No
*/
if (GVAR(convertItems) == 2) exitWith {};
params ["_unit"];
private _fnc_loop = if (GVAR(convertItems) == 0) then {
{
_x params ["_itemToRemove", "_replacementItems"];
private _count = [_unit, _itemToRemove] call EFUNC(common,getCountOfItem);
if (_count > 0) then {
_unit removeItems _itemToRemove;
{
_x params ["_item", "_amount"];
for "_i" from 1 to (_amount * _count) do {
_unit addItem _item;
};
} forEach _replacementItems;
};
}
} else {
{
_x params ["_itemToRemove"];
_unit removeItems _itemToRemove;
}
};
_fnc_loop forEach GVAR(replacementItems);