diff --git a/addons/repair/ACE_Repair.hpp b/addons/repair/ACE_Repair.hpp index ae436791ad..344c509b2f 100644 --- a/addons/repair/ACE_Repair.hpp +++ b/addons/repair/ACE_Repair.hpp @@ -3,10 +3,11 @@ class ACE_Repair { class ReplaceWheel { displayName = CSTRING(ReplaceWheel); displayNameProgress = CSTRING(ReplacingWheel); + forceDisplayName = 0; repairLocations[] = {"All"}; requiredEngineer = QGVAR(engineerSetting_Wheel); - repairingTime = 10; + repairingTime = QGVAR(wheelChangeTime); repairingTimeSelfCoef = 1; items = QGVAR(wheelRepairRequiredItems); condition = QFUNC(canReplaceWheel); @@ -21,6 +22,7 @@ class ACE_Repair { animationCallerProne = "Acts_carFixingWheel"; animationCallerSelf = "Acts_carFixingWheel"; animationCallerSelfProne = "Acts_carFixingWheel"; + loopAnimation = 0; litter[] = {}; }; class RemoveWheel: ReplaceWheel { @@ -46,7 +48,7 @@ class ACE_Repair { displayNameProgress = CSTRING(RepairingHitPoint); condition = QFUNC(canMiscRepair); requiredEngineer = QGVAR(engineerSetting_Repair); - repairingTime = 15; + repairingTime = QGVAR(miscRepairTime); callbackSuccess = QFUNC(doRepair); items = QGVAR(miscRepairRequiredItems); itemConsumed = QGVAR(consumeItem_ToolKit); @@ -80,11 +82,14 @@ class ACE_Repair { class FullRepair: MiscRepair { displayName = CSTRING(fullRepair); displayNameProgress = CSTRING(fullyRepairing); + forceDisplayName = 1; + loopAnimation = 1; requiredEngineer = QGVAR(engineerSetting_fullRepair); repairLocations[] = {QGVAR(fullRepairLocation)}; - repairingTime = 30; - condition = "-1 != ((getAllHitPointsDamage _target param [2,[]]) findIf {_x > 0})"; + repairingTime = QFUNC(getFullRepairTime); + condition = "((getAllHitPointsDamage _target) select 2) findIf {_x > 0} != -1"; callbackSuccess = QFUNC(doFullRepair); + callbackProgress = QFUNC(fullRepairProgress); items = QGVAR(fullRepairRequiredItems); itemConsumed = QGVAR(consumeItem_ToolKit); }; diff --git a/addons/repair/XEH_PREP.hpp b/addons/repair/XEH_PREP.hpp index 7c82632f87..ea9e40a4e7 100644 --- a/addons/repair/XEH_PREP.hpp +++ b/addons/repair/XEH_PREP.hpp @@ -17,8 +17,11 @@ PREP(doRepair); PREP(doRepairTrack); PREP(doReplaceTrack); PREP(doReplaceWheel); +PREP(fullRepairProgress); PREP(getClaimObjects); +PREP(getFullRepairTime); PREP(getHitPointString); +PREP(getHitPointsToIgnore); PREP(getPatchWheelTime); PREP(getPostRepairDamage); PREP(getRepairItems); diff --git a/addons/repair/functions/fnc_addRepairActions.sqf b/addons/repair/functions/fnc_addRepairActions.sqf index f78863985d..20607ca940 100644 --- a/addons/repair/functions/fnc_addRepairActions.sqf +++ b/addons/repair/functions/fnc_addRepairActions.sqf @@ -25,6 +25,9 @@ TRACE_2("addRepairActions", _vehicle,_type); private _initializedClasses = GETMVAR(GVAR(initializedClasses),[]); if (_type in _initializedClasses) exitWith {}; +// get hitPoints to ignore +private _hitPointsToIgnore = [_vehicle] call FUNC(getHitPointsToIgnore); + // get all hitpoints and selections (getAllHitPointsDamage _vehicle) params [["_hitPoints", []], ["_hitSelections", []]]; // Since 1.82 these are all lower case @@ -40,8 +43,6 @@ private _icon = ["a3\ui_f\data\igui\cfg\actions\repair_ca.paa", "#FFFFFF"]; private _vehCfg = configOf _vehicle; // Custom position can be defined via config for associated hitpoint private _hitpointPositions = getArray (_vehCfg >> QGVAR(hitpointPositions)); -// Associated hitpoints can be grouped via config to produce a single repair action -private _hitpointGroups = getArray (_vehCfg >> QGVAR(hitpointGroups)); // Get turret paths private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehicle, "commander", true])) apply {_x # 3}; @@ -88,59 +89,32 @@ private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehi _processedSelections pushBack _selection; } else { - // Empty hitpoints don't contain enough information - if (_hitpoint isEqualTo "") exitWith { TRACE_3("Skipping Empty Hit",_hitpoint,_forEachIndex,_selection); }; - // Ignore glass hitpoints - if ((_hitpoint find "glass") != -1) exitWith { TRACE_3("Skipping Glass",_hitpoint,_forEachIndex,_selection); }; - // Ignore hitpoints starting with # (seems to be lights) - if ((_hitpoint select [0,1]) == "#") exitWith { TRACE_3("Skipping # hit",_hitpoint,_forEachIndex,_selection); }; - // Ignore ERA/Slat armor (vanilla uses hitera_/hitslat_, pre-1.82 RHS uses era_) - // ToDo: see how community utilizes new armor system, could also check getText (_hitpointConfig >> "simulation") - if (((_hitpoint select [0,7]) == "hitera_") || {(_hitpoint select [0,8]) == "hitslat_"} || {(_hitpoint select [0,4]) == "era_"}) exitWith { TRACE_3("Skipping ERA/SLAT",_hitpoint,_forEachIndex,_selection); }; + // Skip ignored hitpoints + if (_hitpoint in _hitPointsToIgnore) exitWith { + TRACE_3("Skipping ignored hitpoint",_hitpoint,_forEachIndex,_selection); + }; // Some hitpoints do not have a selection but do have an armorComponent value (seems to mainly be RHS) // Ref https://community.bistudio.com/wiki/Arma_3_Damage_Enhancement // this code won't support identically named hitpoints (e.g. commander turret: Duplicate HitPoint name 'HitTurret') private _armorComponent = ""; if (_selection == "") then { - { - private _turretHitpointCfg = ([_vehCfg, _x] call CBA_fnc_getTurret) >> "HitPoints"; - private _hitpointsCfg = "configName _x == _hitpoint" configClasses _turretHitpointCfg; - if (_hitpointsCfg isNotEqualTo []) exitWith { - TRACE_2("turret hitpoint configFound",_hitpoint,_x); - // only do turret hitpoints or stuff linked to visuals for now or we apparently get some weird stuff - if ((_hitpoint in ["hitturret", "hitgun"]) || {(getNumber (_hitpointsCfg # 0 >> "isGun")) == 1} || {(getNumber (_hitpointsCfg # 0 >> "isTurret")) == 1} || {(getText (_hitpointsCfg # 0 >> "visual")) != ""}) then { + private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints"); + if (_hitpointsCfg isNotEqualTo []) then { + _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); + }; + if (_armorComponent == "") then { + { + private _turretHitpointCfg = ([_vehCfg, _x] call CBA_fnc_getTurret) >> "HitPoints"; + private _hitpointsCfg = "configName _x == _hitpoint" configClasses _turretHitpointCfg; + if (_hitpointsCfg isNotEqualTo []) exitWith { + TRACE_2("turret hitpoint configFound",_hitpoint,_x); _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); }; - }; - } forEach _turretPaths; - if (_armorComponent == "") then { - private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints"); - if ((getText (_hitpointsCfg # 0 >> "visual")) != "") then { - _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); - }; + } forEach _turretPaths; }; if (_armorComponent != "") then { INFO_3("%1: %2 no selection: using armorComponent %3",_type,_hitpoint,_armorComponent); }; }; - if ((_selection == "") && {_armorComponent == ""}) exitWith { TRACE_3("Skipping no selection OR armor component",_hitpoint,_forEachIndex,_selection); }; - - - //Depends hitpoints shouldn't be modified directly (will be normalized) - // Biki: Clearing 'depends' in case of inheritance cannot be an empty string (rpt warnings), but rather a "0" value. - if (!((getText (_vehCfg >> "HitPoints" >> _hitpoint >> "depends")) in ["", "0"])) exitWith { - TRACE_3("Skip Depends",_hitpoint,_forEachIndex,_selection); - }; - - private _childHitPoint = false; - { - { - if (_hitpoint == _x) exitWith { - _childHitPoint = true; - }; - } forEach (_x select 1); - } forEach _hitpointGroups; - // If the current selection is associated with a child hitpoint, then skip - if (_childHitPoint) exitWith { TRACE_3("childHitpoint",_hitpoint,_forEachIndex,_selection); }; // Find the action position private _position = compile format ["_target selectionPosition ['%1', 'HitPoints'];", _selection]; diff --git a/addons/repair/functions/fnc_doRepair.sqf b/addons/repair/functions/fnc_doRepair.sqf index 1b6f497d8e..2874eaf2f8 100644 --- a/addons/repair/functions/fnc_doRepair.sqf +++ b/addons/repair/functions/fnc_doRepair.sqf @@ -7,6 +7,7 @@ * 0: Unit that does the repairing * 1: Vehicle to repair * 2: Selected hitpointIndex + * 3: Repair action classname * * Return Value: * None @@ -17,10 +18,11 @@ * Public: No */ -params ["_unit", "_vehicle", "_hitPointIndex"]; -TRACE_3("params",_unit,_vehicle,_hitPointIndex); +params ["_unit", "_vehicle", "_hitPointIndex", "_action"]; +TRACE_4("params",_unit,_vehicle,_hitPointIndex,_action); -private _postRepairDamageMin = [_unit] call FUNC(getPostRepairDamage); +// override minimum damage if doing full repair +private _postRepairDamageMin = [_unit, _action isEqualTo "fullRepair"] call FUNC(getPostRepairDamage); (getAllHitPointsDamage _vehicle) params ["_allHitPoints"]; private _hitPointClassname = _allHitPoints select _hitPointIndex; diff --git a/addons/repair/functions/fnc_fullRepairProgress.sqf b/addons/repair/functions/fnc_fullRepairProgress.sqf new file mode 100644 index 0000000000..444bb750b3 --- /dev/null +++ b/addons/repair/functions/fnc_fullRepairProgress.sqf @@ -0,0 +1,50 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Handles full repair by periodically repairing damaged hitpoints. + * + * Arguments: + * 0: Arguments + * 0: Engineer + * 1: Vehicle + * 2: Hitpoint (unused) + * 3: Repair action classname + * 1: Elapsed Time + * 2: Total Time + * + * Return Value: + * Continue Repair + * + * Example: + * [[objNull, player], 5, 10] call ace_repair_fnc_fullRepairProgress + * + * Public: No + */ + +params ["_args", "_elapsedTime", "_totalTime"]; +_args params ["_engineer", "_vehicle", "", "_action"]; + +if !((alive _vehicle) && {(abs speed _vehicle) < 1}) exitWith {false}; // make sure vehicle doesn't drive off + +// Not enough time has elapsed to repair a hitpoint +if (_totalTime - _elapsedTime > ([_engineer, _vehicle] call FUNC(getFullRepairTime)) - (GVAR(miscRepairTime) * GVAR(timeCoefficientFullRepair))) exitWith {true}; + +private _allHitPointsDamage = getAllHitPointsDamage _vehicle; +_allHitPointsDamage params ["_hitPoints", "", "_damageValues"]; + +private _hitPointsToIgnore = [_vehicle] call FUNC(getHitPointsToIgnore); + +private _firstDamagedIndex = { + private _hitPoint = _hitPoints select _forEachIndex; + if (_x > 0 && {!(_hitPoint in _hitPointsToIgnore)}) exitWith {_forEachIndex}; + -1 +} forEach _damageValues; + +// Stop repairing if there are no more damaged hitpoints +// callBackSuccess to FUNC(doFullRepair) for ignored hitpoints +if (_firstDamagedIndex == -1) exitWith {true}; + +// Repair the first damaged hitpoint +[_engineer, _vehicle, _firstDamagedIndex, _action] call FUNC(doRepair); + +true diff --git a/addons/repair/functions/fnc_getFullRepairTime.sqf b/addons/repair/functions/fnc_getFullRepairTime.sqf new file mode 100644 index 0000000000..78f46472a5 --- /dev/null +++ b/addons/repair/functions/fnc_getFullRepairTime.sqf @@ -0,0 +1,42 @@ +#include "script_component.hpp" +/* + * Author: LinkIsGrim + * Calculates the Full Repair time based on the amount of hitpoints to repair + * + * Arguments: + * 0: Engineer + * 1: Vehicle + * + * Return Value: + * Repair Time + * + * Example: + * [player, vehicle] call ace_repair_fnc_getFullRepairTime + * + * Public: No + */ + +params ["_engineer", "_vehicle"]; + +private _allHitPointsDamage = getAllHitPointsDamage _vehicle; +_allHitPointsDamage params ["_hitPoints", "", "_damageValues"]; + +private _hitPointsToIgnore = [_vehicle] call FUNC(getHitPointsToIgnore); + +private _repairsNeeded = 0; +private _doExtraRepair = false; +{ + if (_x <= 0) then {continue}; // skip hitpoints that don't need repairs + private _hitPoint = _hitPoints select _forEachIndex; + if (_hitPoint in _hitPointsToIgnore) then { // only add extra repair for ignore hitpoints if they're damaged + _doExtraRepair = true; + continue + }; + _repairsNeeded = _repairsNeeded + ceil (_x / 0.5); // repair is capped at 0.5 in FUNC(doRepair) +} forEach _damageValues; + +if (_doExtraRepair) then { + _repairsNeeded = _repairsNeeded + 1; +}; + +_repairsNeeded * GVAR(miscRepairTime) * GVAR(timeCoefficientFullRepair) // return diff --git a/addons/repair/functions/fnc_getHitPointsToIgnore.sqf b/addons/repair/functions/fnc_getHitPointsToIgnore.sqf new file mode 100644 index 0000000000..24f2d9a207 --- /dev/null +++ b/addons/repair/functions/fnc_getHitPointsToIgnore.sqf @@ -0,0 +1,142 @@ +#include "script_component.hpp" +/* + * Author: commy2, kymckay, LinkIsGrim + * Get list of vehicle hitpoints to ignore + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * HitPoints to ignore + * + * Example: + * [vehicle] call ace_repair_fnc_getHitpointsToIgnore + * + * Public: No + */ + +params ["_vehicle"]; + +private _type = typeOf _vehicle; +TRACE_2("getHitPointsToIgnore", _vehicle,_type); +private _initializedClasses = missionNamespace getVariable [QGVAR(hitPointsToIgnoreInitializedClasses), createHashMap]; +if (_type in _initializedClasses) exitWith {_initializedClasses get _type}; + +private _vehCfg = configOf _vehicle; +private _hitpointGroups = getArray (_vehCfg >> QGVAR(hitpointGroups)); +private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehicle, "commander", true])) apply {_x # 3}; + +(getAllHitPointsDamage _vehicle) params [["_hitPoints", []], ["_hitSelections", []]]; +// get hitpoints of wheels with their selections +([_vehicle] call FUNC(getWheelHitPointsWithSelections)) params ["_wheelHitPoints", "_wheelHitSelections"]; + +private _hitPointsToIgnore = [""]; // always ignore empty hitpoints +private _processedSelections = []; + +{ + private _selection = _x; + private _hitpoint = toLower (_hitPoints select _forEachIndex); + private _isWheelOrTrack = _selection in _wheelHitSelections || {_hitpoint in _wheelHitPoints} || {_hitpoint in TRACK_HITPOINTS}; + + if (_hitpoint isEqualTo "") then { // skip empty hitpoint + continue + }; + + if (_isWheelOrTrack && {_selection in _processedSelections || {_selection isEqualTo ""}}) then { // skip duplicate or empty selection wheel/track + TRACE_3("Skipping duplicate Wheel/Track or empty selection",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping duplicate wheel, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if ("glass" in _hitpoint) then { // skip glass + TRACE_3("Skipping glass",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping glass, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if (_hitpoint select [0,1] isEqualTo "#" || {_hitpoint select [0,9] isEqualTo "hit_light"}) then { // skip lights + TRACE_3("Skipping light",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping light, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if (_hitpoint select [0,7] isEqualTo "hitera_" || {_hitpoint select [0,8] isEqualTo "hitslat_"} || {_hitpoint select [0,4] isEqualTo "era_"}) then { // skip era/slat + TRACE_3("Skipping ERA/Slat HitPoint",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping ERA/SLAT, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + private _armorComponent = ""; + if (_selection == "") then { // some hitpoints have empty selection but defined armor component (mostly RHS) + { + private _turretHitpointCfg = ([_vehCfg, _x] call CBA_fnc_getTurret) >> "HitPoints"; + private _hitpointsCfg = "configName _x == _hitpoint" configClasses _turretHitpointCfg; + if (_hitpointsCfg isNotEqualTo []) exitWith { + TRACE_2("turret hitpoint configFound",_hitpoint,_x); + // only do turret hitpoints and stuff linked to visuals + if ((_hitpoint in ["hitturret", "hitgun"]) || {(getNumber (_hitpointsCfg # 0 >> "isGun")) == 1} || {(getNumber (_hitpointsCfg # 0 >> "isTurret")) == 1} || {(getText (_hitpointsCfg # 0 >> "visual")) != ""}) then { + _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); + }; + }; + } forEach _turretPaths; + if (_armorComponent == "") then { + private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints"); + if (_hitpointsCfg isNotEqualTo [] && {(getText (_hitpointsCfg # 0 >> "visual")) != ""}) then { + _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent"); + }; + }; + }; + + if ((_selection == "") && {_armorComponent == ""}) then { + TRACE_3("Skipping no selection OR armor component",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping no selection OR armor component, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if (!(getText (_vehCfg >> "HitPoints" >> _hitpoint >> "depends") in ["", "0"])) then { // skip depends hitpoints, should be normalized by engine + TRACE_3("Skipping depends hitpoint",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping depends hitpoint, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + if ((_hitpointGroups findIf {(_x select 1) == _hitpoint}) != -1) then { // skip child hitpoints + TRACE_3("Skipping child hitpoint",_hitpoint,_forEachIndex,_selection); + /*#ifdef DEBUG_MODE_FULL + systemChat format ["Skipping child hitpoint, hitpoint %1, index %2, selection %3", _hitpoint, _forEachIndex, _selection]; + #endif*/ + _hitPointsToIgnore pushBackUnique _hitpoint; + _processedSelections pushBack _selection; + continue + }; + + _processedSelections pushBack _selection; +} forEach _hitSelections; + +_initializedClasses set [_type, _hitPointsToIgnore]; +missionNamespace setVariable [QGVAR(hitPointsToIgnoreInitializedClasses), _initializedClasses]; + +_hitPointsToIgnore diff --git a/addons/repair/functions/fnc_getPostRepairDamage.sqf b/addons/repair/functions/fnc_getPostRepairDamage.sqf index 0eac151e45..141df15369 100644 --- a/addons/repair/functions/fnc_getPostRepairDamage.sqf +++ b/addons/repair/functions/fnc_getPostRepairDamage.sqf @@ -5,6 +5,7 @@ * * Arguments: * 0: Unit that does the repairing + * 1: Override for full repair (default: false) * * Return Value: * 0: Repair Damage Threshold @@ -15,11 +16,11 @@ * Public: No */ -params ["_unit"]; -TRACE_1("params",_unit); +params ["_unit", ["_override", false]]; +TRACE_2("params",_unit,_override); -//If in facility or near vehicle then complete repair of hitpoint: -if (([_unit] call FUNC(isInRepairFacility) || {[_unit] call FUNC(isNearRepairVehicle)})) exitWith {0}; +//If in facility, near vehicle, or doing full repair then complete repair of hitpoint: +if ((_override || {[_unit] call FUNC(isInRepairFacility)} || {[_unit] call FUNC(isNearRepairVehicle)})) exitWith {0}; private _class = _unit getVariable ["ACE_IsEngineer", getNumber (configOf _unit >> "engineer")]; //If advanced or more qualified than min, then use engineer threshold: diff --git a/addons/repair/functions/fnc_isInRepairFacility.sqf b/addons/repair/functions/fnc_isInRepairFacility.sqf index 1693297494..a0a1615cd9 100644 --- a/addons/repair/functions/fnc_isInRepairFacility.sqf +++ b/addons/repair/functions/fnc_isInRepairFacility.sqf @@ -15,28 +15,15 @@ * Public: Yes */ +#define CHECK_OBJECTS(var) ((var) findIf {(_x getVariable ["ACE_isRepairFacility", getNumber (configOf _x >> QGVAR(canRepair))] > 0) && {!(_x isKindOf "AllVehicles")} && {alive _x}} != -1) + params [["_object", objNull, [objNull]]]; TRACE_1("params",_object); -private _position = getPosASL _object; -private _isInBuilding = false; -private _checkObject = { - if ( - _x getVariable ["ACE_isRepairFacility", getNumber (configOf _x >> QGVAR(canRepair))] > 0 - && {!(_x isKindOf "AllVehicles")} // check if it's not repair vehicle - && {alive _x} - ) exitWith { - _isInBuilding = true; - }; +private _fnc_check = { + private _position = _object modelToWorldVisual [0, 0, eyePos _object select 2]; + CHECK_OBJECTS(lineIntersectsWith [ARR_3(_position, _position vectorAdd [ARR_3(0, 0, 10)], _object)]) || {CHECK_OBJECTS(_object nearObjects 7.5)} }; -private _objects = (lineIntersectsWith [_object modelToWorldVisual [0, 0, (_position select 2)], _object modelToWorldVisual [0, 0, (_position select 2) +10], _object]); -_checkObject forEach _objects; - -if (_isInBuilding) exitWith {true}; - -_objects = _object nearObjects 7.5; -_checkObject forEach _objects; - -_isInBuilding +[[], _fnc_check, _object, QGVAR(inRepairFacilityCache), IN_REPAIR_FACILITY_CACHE_EXPIRY] call EFUNC(common,cachedCall); diff --git a/addons/repair/functions/fnc_isNearRepairVehicle.sqf b/addons/repair/functions/fnc_isNearRepairVehicle.sqf index 1243c0f95b..3a894162ee 100644 --- a/addons/repair/functions/fnc_isNearRepairVehicle.sqf +++ b/addons/repair/functions/fnc_isNearRepairVehicle.sqf @@ -15,14 +15,14 @@ * Public: Yes */ +#define CHECK_OBJECTS(var) ((var) findIf {alive _x && {[_x] call FUNC(isRepairVehicle)}} != -1) + params ["_unit"]; TRACE_1("params",_unit); -private _nearObjects = nearestObjects [_unit, ["Air", "LandVehicle", "Slingload_base_F"], 20]; +private _fnc_check = { + private _nearObjects = nearestObjects [_unit, ["Air", "LandVehicle", "Slingload_base_F"], 20]; + CHECK_OBJECTS(_nearObjects) +}; -private _return = false; -{ - if (alive _x && {[_x] call FUNC(isRepairVehicle)}) exitWith {_return = true;}; -} forEach _nearObjects; - -_return; +[[], _fnc_check, _unit, QGVAR(nearRepairVehicleCache), NEAR_REPAIR_VEHICLE_CACHE_EXPIRY] call EFUNC(common,cachedCall); diff --git a/addons/repair/functions/fnc_repair.sqf b/addons/repair/functions/fnc_repair.sqf index 51fdea90fe..a0654d2555 100644 --- a/addons/repair/functions/fnc_repair.sqf +++ b/addons/repair/functions/fnc_repair.sqf @@ -148,6 +148,7 @@ if (_callbackProgress == "") then { // Player Animation private _callerAnim = [getText (_config >> "animationCaller"), getText (_config >> "animationCallerProne")] select (stance _caller == "PRONE"); +private _loopAnim = (getNumber (_config >> "loopAnimation")) isEqualTo 1; _caller setVariable [QGVAR(selectedWeaponOnrepair), currentWeapon _caller]; // Cannot use secondairy weapon for animation @@ -171,10 +172,27 @@ if (vehicle _caller == _caller && {_callerAnim != ""}) then { } else { _caller setVariable [QGVAR(repairPrevAnimCaller), animationState _caller]; }; + _caller setVariable [QGVAR(repairCurrentAnimCaller), toLower _callerAnim]; [_caller, _callerAnim] call EFUNC(common,doAnimation); }; }; +if (_loopAnim) then { + private _animDoneEh = _caller addEventHandler ["AnimDone", { + params ["_caller", "_anim"]; + if (_anim isEqualTo (_caller getVariable [QGVAR(repairCurrentAnimCaller), ""])) then { + [{ + params ["_caller", "_anim"]; + if !(isNil {_caller getVariable QGVAR(repairCurrentAnimCaller)}) then { + TRACE_2("loop",_caller,_anim); + _this call EFUNC(common,doAnimation) + }; + }, [_caller, _anim], 2.5] call CBA_fnc_waitAndExecute; + }; + }]; + _caller setVariable [QGVAR(repairLoopAnimEh), _animDoneEh]; +}; + private _soundPosition = _caller modelToWorldVisualWorld (_caller selectionPosition "RightHand"); ["Acts_carFixingWheel", _soundPosition, nil, 50] call EFUNC(common,playConfigSound3D); @@ -213,7 +231,10 @@ private _hitPointClassname = if (_hitPoint isEqualType "") then { }; private _processText = getText (_config >> "displayNameProgress"); private _backupText = format [localize LSTRING(RepairingHitPoint), _hitPointClassname]; -([_hitPointClassname, _processText, _backupText] call FUNC(getHitPointString)) params ["_text"]; +private _text = _processText; +if (getNumber (_config >> "forceDisplayName") isNotEqualTo 1) then { + _text = ([_hitPointClassname, _processText, _backupText] call FUNC(getHitPointString)) select 0; +}; TRACE_4("display",_hitPoint,_hitPointClassname,_processText,_text); diff --git a/addons/repair/functions/fnc_repair_failure.sqf b/addons/repair/functions/fnc_repair_failure.sqf index 83cce85e0d..5acd9564e7 100644 --- a/addons/repair/functions/fnc_repair_failure.sqf +++ b/addons/repair/functions/fnc_repair_failure.sqf @@ -29,9 +29,13 @@ TRACE_5("params",_caller,_target,_selectionName,_className,_usersOfItems); if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then { _caller removeWeapon "ACE_FakePrimaryWeapon"; }; + +_caller removeEventHandler ["AnimDone", _caller getVariable [QGVAR(repairLoopAnimEh), -1]]; +_caller setVariable [QGVAR(repairLoopAnimEh), nil]; if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) then { [_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation); }; +_caller setVariable [QGVAR(repairCurrentAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil]; private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); diff --git a/addons/repair/functions/fnc_repair_success.sqf b/addons/repair/functions/fnc_repair_success.sqf index a86be84244..99778c37dd 100644 --- a/addons/repair/functions/fnc_repair_success.sqf +++ b/addons/repair/functions/fnc_repair_success.sqf @@ -29,9 +29,13 @@ TRACE_4("params",_caller,_target,_selectionName,_className); if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then { _caller removeWeapon "ACE_FakePrimaryWeapon"; }; + +_caller removeEventHandler ["AnimDone", _caller getVariable [QGVAR(repairLoopAnimEh), -1]]; +_caller setVariable [QGVAR(repairLoopAnimEh), nil]; if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) then { [_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation); }; +_caller setVariable [QGVAR(repairCurrentAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil]; private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); diff --git a/addons/repair/initSettings.sqf b/addons/repair/initSettings.sqf index 040e44c2eb..066e944a50 100644 --- a/addons/repair/initSettings.sqf +++ b/addons/repair/initSettings.sqf @@ -107,6 +107,14 @@ private _category = format ["ACE %1", LLSTRING(Repair)]; {[QGVAR(engineerSetting_fullRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; +[ + QGVAR(timeCoefficientFullRepair), "SLIDER", + [LSTRING(timeCoefficientFullRepair_name), LSTRING(timeCoefficientFullRepair_description)], + _category, + [0,3,1.5,2], + true +] call CBA_fnc_addSetting; + [ QGVAR(addSpareParts), "CHECKBOX", [LSTRING(addSpareParts_name), LSTRING(addSpareParts_description)], @@ -153,6 +161,21 @@ private _category = format ["ACE %1", LLSTRING(Repair)]; {[QGVAR(autoShutOffEngineWhenStartingRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} ] call CBA_fnc_addSetting; +[ + QGVAR(miscRepairTime), "SLIDER", + [LSTRING(miscRepairTime_name), LSTRING(miscRepairTime_description)], + _category, + [0,60,15,-1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] + true +] call CBA_fnc_addSetting; + +[ + QGVAR(wheelChangeTime), "SLIDER", + [LSTRING(wheelChangeTime_name), LSTRING(wheelChangeTime_description)], + _category, + [0,60,10,-1], // [min, max, default value, trailing decimals (-1 for whole numbers only)] + true +] call CBA_fnc_addSetting; [ QGVAR(patchWheelTime), diff --git a/addons/repair/script_component.hpp b/addons/repair/script_component.hpp index 2a6196c6fc..9fab647079 100644 --- a/addons/repair/script_component.hpp +++ b/addons/repair/script_component.hpp @@ -20,6 +20,10 @@ #define DAMAGE_COLOR_SCALE ["#FFFFFF", "#FFFF7E", "#FFEC4D", "#FFD52C", "#FCB121", "#FF9916", "#FF7D16", "#FF4400", "#FF0000"] +#define IN_REPAIR_FACILITY_CACHE_EXPIRY 1 + +#define NEAR_REPAIR_VEHICLE_CACHE_EXPIRY 1 + #define ANY_TOOLKIT_FAKECLASS QGVAR(anyToolKit) #define PATCH_WHEEL_STEP_TIME 0.05 diff --git a/addons/repair/stringtable.xml b/addons/repair/stringtable.xml index 92bee905bb..4929e0f31a 100644 --- a/addons/repair/stringtable.xml +++ b/addons/repair/stringtable.xml @@ -266,6 +266,12 @@ 維修載具中... Tamir Ediliyor... + + Full Repair Time Coefficient + + + Modifies how long it takes to perform a Full Repair.\nThe repair time is based on based on the amount of repairs needed for each part, including those normally inaccessible. + Boost engineer training when in repair vehicles or facilities. Untrained becomes engineer, engineer becomes advanced engineer. Améliore les compétences en ingénierie des unités en fonction du lieu où elles se trouvent ; notamment dans les véhicules de réparation ou les ateliers.\nUn soldat non formé devient ingénieur, un ingénieur devient ingénieur avancé. @@ -1860,7 +1866,7 @@ 選擇的備件數量 - Wheel Repair Requirements + Wheel Change Requirements Bedingungen für die Reifenreperatur Wym. naprawy kół Requisitos de reparación de ruedas @@ -2062,6 +2068,18 @@ Apagar el motor automáticamente al efectuar una reparación 수리 시 엔진을 자동으로 끕니다. + + Part Repair Time + + + Time in seconds to complete a repair. + + + Wheel Change Time + + + Time in seconds to remove or change a wheel. + Patch Wheel Radflicken @@ -2071,16 +2089,16 @@ Radflicken... - Patch wheel time + Wheel Patch Time Time it takes to patch a wheel by 5%. - Patch wheel maximum repair + Patch Wheel Threshold - Maximum level a wheel can be patched. + Maximum level to which a wheel can be patched. Wheel Patch Location