Repair - Make Full Repair Time dependent on vehicle damage (#8417)

* add variable full repair time

* enable compile cache

* Fix stupid

* whoops

* incremental full repair

* cleanup function header

* ignore hitpoints inFullRepairProgress

* fix getHitPointsToIgnore

* final cleanup

* don't show repair hint while doing full repair

* make this all work

* fix stupid

put this back in place

* Add setting for speedup when near repair facility/vehicle

enable compile cache

* refactor near repair facility/vehicle checks

* remove skipping hint from do_repair

better for feedback this way

* git diff stuff

* use functions directly in ACE_Repair.hpp

* add check for vehicle proximity

* add a new line

* switch to multiply by setting instead

* speed boost settings, remove exit addRepairActions

* stringtable

* remove speed boost settings

* fix things, add forceDisplayName

* name in function header

* fix TRACE

* add animation looping

* remove systemChat

Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>

* add time coefficient setting

* move to repair category

* time coefficient max and default values

---------

Co-authored-by: Salluci <69561145+Salluci@users.noreply.github.com>
Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>
This commit is contained in:
Grim 2023-07-06 06:52:04 +03:00 committed by GitHub
parent 50430e47ef
commit 04e41a4d5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 366 additions and 86 deletions

View File

@ -3,10 +3,11 @@ class ACE_Repair {
class ReplaceWheel { class ReplaceWheel {
displayName = CSTRING(ReplaceWheel); displayName = CSTRING(ReplaceWheel);
displayNameProgress = CSTRING(ReplacingWheel); displayNameProgress = CSTRING(ReplacingWheel);
forceDisplayName = 0;
repairLocations[] = {"All"}; repairLocations[] = {"All"};
requiredEngineer = QGVAR(engineerSetting_Wheel); requiredEngineer = QGVAR(engineerSetting_Wheel);
repairingTime = 10; repairingTime = QGVAR(wheelChangeTime);
repairingTimeSelfCoef = 1; repairingTimeSelfCoef = 1;
items = QGVAR(wheelRepairRequiredItems); items = QGVAR(wheelRepairRequiredItems);
condition = QFUNC(canReplaceWheel); condition = QFUNC(canReplaceWheel);
@ -21,6 +22,7 @@ class ACE_Repair {
animationCallerProne = "Acts_carFixingWheel"; animationCallerProne = "Acts_carFixingWheel";
animationCallerSelf = "Acts_carFixingWheel"; animationCallerSelf = "Acts_carFixingWheel";
animationCallerSelfProne = "Acts_carFixingWheel"; animationCallerSelfProne = "Acts_carFixingWheel";
loopAnimation = 0;
litter[] = {}; litter[] = {};
}; };
class RemoveWheel: ReplaceWheel { class RemoveWheel: ReplaceWheel {
@ -46,7 +48,7 @@ class ACE_Repair {
displayNameProgress = CSTRING(RepairingHitPoint); displayNameProgress = CSTRING(RepairingHitPoint);
condition = QFUNC(canMiscRepair); condition = QFUNC(canMiscRepair);
requiredEngineer = QGVAR(engineerSetting_Repair); requiredEngineer = QGVAR(engineerSetting_Repair);
repairingTime = 15; repairingTime = QGVAR(miscRepairTime);
callbackSuccess = QFUNC(doRepair); callbackSuccess = QFUNC(doRepair);
items = QGVAR(miscRepairRequiredItems); items = QGVAR(miscRepairRequiredItems);
itemConsumed = QGVAR(consumeItem_ToolKit); itemConsumed = QGVAR(consumeItem_ToolKit);
@ -80,11 +82,14 @@ class ACE_Repair {
class FullRepair: MiscRepair { class FullRepair: MiscRepair {
displayName = CSTRING(fullRepair); displayName = CSTRING(fullRepair);
displayNameProgress = CSTRING(fullyRepairing); displayNameProgress = CSTRING(fullyRepairing);
forceDisplayName = 1;
loopAnimation = 1;
requiredEngineer = QGVAR(engineerSetting_fullRepair); requiredEngineer = QGVAR(engineerSetting_fullRepair);
repairLocations[] = {QGVAR(fullRepairLocation)}; repairLocations[] = {QGVAR(fullRepairLocation)};
repairingTime = 30; repairingTime = QFUNC(getFullRepairTime);
condition = "-1 != ((getAllHitPointsDamage _target param [2,[]]) findIf {_x > 0})"; condition = "((getAllHitPointsDamage _target) select 2) findIf {_x > 0} != -1";
callbackSuccess = QFUNC(doFullRepair); callbackSuccess = QFUNC(doFullRepair);
callbackProgress = QFUNC(fullRepairProgress);
items = QGVAR(fullRepairRequiredItems); items = QGVAR(fullRepairRequiredItems);
itemConsumed = QGVAR(consumeItem_ToolKit); itemConsumed = QGVAR(consumeItem_ToolKit);
}; };

View File

@ -17,8 +17,11 @@ PREP(doRepair);
PREP(doRepairTrack); PREP(doRepairTrack);
PREP(doReplaceTrack); PREP(doReplaceTrack);
PREP(doReplaceWheel); PREP(doReplaceWheel);
PREP(fullRepairProgress);
PREP(getClaimObjects); PREP(getClaimObjects);
PREP(getFullRepairTime);
PREP(getHitPointString); PREP(getHitPointString);
PREP(getHitPointsToIgnore);
PREP(getPatchWheelTime); PREP(getPatchWheelTime);
PREP(getPostRepairDamage); PREP(getPostRepairDamage);
PREP(getRepairItems); PREP(getRepairItems);

View File

@ -25,6 +25,9 @@ TRACE_2("addRepairActions", _vehicle,_type);
private _initializedClasses = GETMVAR(GVAR(initializedClasses),[]); private _initializedClasses = GETMVAR(GVAR(initializedClasses),[]);
if (_type in _initializedClasses) exitWith {}; if (_type in _initializedClasses) exitWith {};
// get hitPoints to ignore
private _hitPointsToIgnore = [_vehicle] call FUNC(getHitPointsToIgnore);
// get all hitpoints and selections // get all hitpoints and selections
(getAllHitPointsDamage _vehicle) params [["_hitPoints", []], ["_hitSelections", []]]; // Since 1.82 these are all lower case (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; private _vehCfg = configOf _vehicle;
// Custom position can be defined via config for associated hitpoint // Custom position can be defined via config for associated hitpoint
private _hitpointPositions = getArray (_vehCfg >> QGVAR(hitpointPositions)); 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 // Get turret paths
private _turretPaths = ((fullCrew [_vehicle, "gunner", true]) + (fullCrew [_vehicle, "commander", true])) apply {_x # 3}; 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; _processedSelections pushBack _selection;
} else { } else {
// Empty hitpoints don't contain enough information // Skip ignored hitpoints
if (_hitpoint isEqualTo "") exitWith { TRACE_3("Skipping Empty Hit",_hitpoint,_forEachIndex,_selection); }; if (_hitpoint in _hitPointsToIgnore) exitWith {
// Ignore glass hitpoints TRACE_3("Skipping ignored hitpoint",_hitpoint,_forEachIndex,_selection);
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); };
// Some hitpoints do not have a selection but do have an armorComponent value (seems to mainly be RHS) // 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 // 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') // this code won't support identically named hitpoints (e.g. commander turret: Duplicate HitPoint name 'HitTurret')
private _armorComponent = ""; private _armorComponent = "";
if (_selection == "") then { if (_selection == "") then {
{ private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints");
private _turretHitpointCfg = ([_vehCfg, _x] call CBA_fnc_getTurret) >> "HitPoints"; if (_hitpointsCfg isNotEqualTo []) then {
private _hitpointsCfg = "configName _x == _hitpoint" configClasses _turretHitpointCfg; _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent");
if (_hitpointsCfg isNotEqualTo []) exitWith { };
TRACE_2("turret hitpoint configFound",_hitpoint,_x); if (_armorComponent == "") then {
// 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 _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"); _armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent");
}; };
}; } forEach _turretPaths;
} forEach _turretPaths;
if (_armorComponent == "") then {
private _hitpointsCfg = "configName _x == _hitpoint" configClasses (_vehCfg >> "HitPoints");
if ((getText (_hitpointsCfg # 0 >> "visual")) != "") then {
_armorComponent = getText (_hitpointsCfg # 0 >> "armorComponent");
};
}; };
if (_armorComponent != "") then { INFO_3("%1: %2 no selection: using armorComponent %3",_type,_hitpoint,_armorComponent); }; 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 // Find the action position
private _position = compile format ["_target selectionPosition ['%1', 'HitPoints'];", _selection]; private _position = compile format ["_target selectionPosition ['%1', 'HitPoints'];", _selection];

View File

@ -7,6 +7,7 @@
* 0: Unit that does the repairing <OBJECT> * 0: Unit that does the repairing <OBJECT>
* 1: Vehicle to repair <OBJECT> * 1: Vehicle to repair <OBJECT>
* 2: Selected hitpointIndex <NUMBER> * 2: Selected hitpointIndex <NUMBER>
* 3: Repair action classname <STRING>
* *
* Return Value: * Return Value:
* None * None
@ -17,10 +18,11 @@
* Public: No * Public: No
*/ */
params ["_unit", "_vehicle", "_hitPointIndex"]; params ["_unit", "_vehicle", "_hitPointIndex", "_action"];
TRACE_3("params",_unit,_vehicle,_hitPointIndex); 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"]; (getAllHitPointsDamage _vehicle) params ["_allHitPoints"];
private _hitPointClassname = _allHitPoints select _hitPointIndex; private _hitPointClassname = _allHitPoints select _hitPointIndex;

View File

@ -0,0 +1,50 @@
#include "script_component.hpp"
/*
* Author: LinkIsGrim
* Handles full repair by periodically repairing damaged hitpoints.
*
* Arguments:
* 0: Arguments <ARRAY>
* 0: Engineer <OBJECT>
* 1: Vehicle <OBJECT>
* 2: Hitpoint <STRING> (unused)
* 3: Repair action classname <STRING>
* 1: Elapsed Time <NUMBER>
* 2: Total Time <NUMBER>
*
* Return Value:
* Continue Repair <BOOL>
*
* 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

View File

@ -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 <OBJECT>
* 1: Vehicle <OBJECT>
*
* Return Value:
* Repair Time <NUMBER>
*
* 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

View File

@ -0,0 +1,142 @@
#include "script_component.hpp"
/*
* Author: commy2, kymckay, LinkIsGrim
* Get list of vehicle hitpoints to ignore
*
* Arguments:
* 0: Vehicle <OBJECT>
*
* Return Value:
* HitPoints to ignore <ARRAY>
*
* 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

View File

@ -5,6 +5,7 @@
* *
* Arguments: * Arguments:
* 0: Unit that does the repairing <OBJECT> * 0: Unit that does the repairing <OBJECT>
* 1: Override for full repair <BOOL> (default: false)
* *
* Return Value: * Return Value:
* 0: Repair Damage Threshold <NUMBER> * 0: Repair Damage Threshold <NUMBER>
@ -15,11 +16,11 @@
* Public: No * Public: No
*/ */
params ["_unit"]; params ["_unit", ["_override", false]];
TRACE_1("params",_unit); TRACE_2("params",_unit,_override);
//If in facility or near vehicle then complete repair of hitpoint: //If in facility, near vehicle, or doing full repair then complete repair of hitpoint:
if (([_unit] call FUNC(isInRepairFacility) || {[_unit] call FUNC(isNearRepairVehicle)})) exitWith {0}; if ((_override || {[_unit] call FUNC(isInRepairFacility)} || {[_unit] call FUNC(isNearRepairVehicle)})) exitWith {0};
private _class = _unit getVariable ["ACE_IsEngineer", getNumber (configOf _unit >> "engineer")]; private _class = _unit getVariable ["ACE_IsEngineer", getNumber (configOf _unit >> "engineer")];
//If advanced or more qualified than min, then use engineer threshold: //If advanced or more qualified than min, then use engineer threshold:

View File

@ -15,28 +15,15 @@
* Public: Yes * 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]]]; params [["_object", objNull, [objNull]]];
TRACE_1("params",_object); TRACE_1("params",_object);
private _position = getPosASL _object;
private _isInBuilding = false;
private _checkObject = { private _fnc_check = {
if ( private _position = _object modelToWorldVisual [0, 0, eyePos _object select 2];
_x getVariable ["ACE_isRepairFacility", getNumber (configOf _x >> QGVAR(canRepair))] > 0 CHECK_OBJECTS(lineIntersectsWith [ARR_3(_position, _position vectorAdd [ARR_3(0, 0, 10)], _object)]) || {CHECK_OBJECTS(_object nearObjects 7.5)}
&& {!(_x isKindOf "AllVehicles")} // check if it's not repair vehicle
&& {alive _x}
) exitWith {
_isInBuilding = true;
};
}; };
private _objects = (lineIntersectsWith [_object modelToWorldVisual [0, 0, (_position select 2)], _object modelToWorldVisual [0, 0, (_position select 2) +10], _object]); [[], _fnc_check, _object, QGVAR(inRepairFacilityCache), IN_REPAIR_FACILITY_CACHE_EXPIRY] call EFUNC(common,cachedCall);
_checkObject forEach _objects;
if (_isInBuilding) exitWith {true};
_objects = _object nearObjects 7.5;
_checkObject forEach _objects;
_isInBuilding

View File

@ -15,14 +15,14 @@
* Public: Yes * Public: Yes
*/ */
#define CHECK_OBJECTS(var) ((var) findIf {alive _x && {[_x] call FUNC(isRepairVehicle)}} != -1)
params ["_unit"]; params ["_unit"];
TRACE_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; [[], _fnc_check, _unit, QGVAR(nearRepairVehicleCache), NEAR_REPAIR_VEHICLE_CACHE_EXPIRY] call EFUNC(common,cachedCall);
{
if (alive _x && {[_x] call FUNC(isRepairVehicle)}) exitWith {_return = true;};
} forEach _nearObjects;
_return;

View File

@ -148,6 +148,7 @@ if (_callbackProgress == "") then {
// Player Animation // Player Animation
private _callerAnim = [getText (_config >> "animationCaller"), getText (_config >> "animationCallerProne")] select (stance _caller == "PRONE"); 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]; _caller setVariable [QGVAR(selectedWeaponOnrepair), currentWeapon _caller];
// Cannot use secondairy weapon for animation // Cannot use secondairy weapon for animation
@ -171,10 +172,27 @@ if (vehicle _caller == _caller && {_callerAnim != ""}) then {
} else { } else {
_caller setVariable [QGVAR(repairPrevAnimCaller), animationState _caller]; _caller setVariable [QGVAR(repairPrevAnimCaller), animationState _caller];
}; };
_caller setVariable [QGVAR(repairCurrentAnimCaller), toLower _callerAnim];
[_caller, _callerAnim] call EFUNC(common,doAnimation); [_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"); private _soundPosition = _caller modelToWorldVisualWorld (_caller selectionPosition "RightHand");
["Acts_carFixingWheel", _soundPosition, nil, 50] call EFUNC(common,playConfigSound3D); ["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 _processText = getText (_config >> "displayNameProgress");
private _backupText = format [localize LSTRING(RepairingHitPoint), _hitPointClassname]; 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); TRACE_4("display",_hitPoint,_hitPointClassname,_processText,_text);

View File

@ -29,9 +29,13 @@ TRACE_5("params",_caller,_target,_selectionName,_className,_usersOfItems);
if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then { if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then {
_caller removeWeapon "ACE_FakePrimaryWeapon"; _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 { if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) then {
[_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation); [_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation);
}; };
_caller setVariable [QGVAR(repairCurrentAnimCaller), nil];
_caller setVariable [QGVAR(repairPrevAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil];
private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]);

View File

@ -29,9 +29,13 @@ TRACE_4("params",_caller,_target,_selectionName,_className);
if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then { if (primaryWeapon _caller == "ACE_FakePrimaryWeapon") then {
_caller removeWeapon "ACE_FakePrimaryWeapon"; _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 { if (vehicle _caller == _caller && {!(_caller call EFUNC(common,isSwimming))}) then {
[_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation); [_caller, _caller getVariable [QGVAR(repairPrevAnimCaller), ""], 2] call EFUNC(common,doAnimation);
}; };
_caller setVariable [QGVAR(repairCurrentAnimCaller), nil];
_caller setVariable [QGVAR(repairPrevAnimCaller), nil]; _caller setVariable [QGVAR(repairPrevAnimCaller), nil];
private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]); private _weaponSelect = (_caller getVariable [QGVAR(selectedWeaponOnrepair), ""]);

View File

@ -107,6 +107,14 @@ private _category = format ["ACE %1", LLSTRING(Repair)];
{[QGVAR(engineerSetting_fullRepair), _this] call EFUNC(common,cbaSettings_settingChanged)} {[QGVAR(engineerSetting_fullRepair), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] 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", QGVAR(addSpareParts), "CHECKBOX",
[LSTRING(addSpareParts_name), LSTRING(addSpareParts_description)], [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)} {[QGVAR(autoShutOffEngineWhenStartingRepair), _this] call EFUNC(common,cbaSettings_settingChanged)}
] call CBA_fnc_addSetting; ] 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), QGVAR(patchWheelTime),

View File

@ -20,6 +20,10 @@
#define DAMAGE_COLOR_SCALE ["#FFFFFF", "#FFFF7E", "#FFEC4D", "#FFD52C", "#FCB121", "#FF9916", "#FF7D16", "#FF4400", "#FF0000"] #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 ANY_TOOLKIT_FAKECLASS QGVAR(anyToolKit)
#define PATCH_WHEEL_STEP_TIME 0.05 #define PATCH_WHEEL_STEP_TIME 0.05

View File

@ -266,6 +266,12 @@
<Chinese>維修載具中...</Chinese> <Chinese>維修載具中...</Chinese>
<Turkish>Tamir Ediliyor...</Turkish> <Turkish>Tamir Ediliyor...</Turkish>
</Key> </Key>
<Key ID="STR_ACE_Repair_timeCoefficientFullRepair_name">
<English>Full Repair Time Coefficient</English>
</Key>
<Key ID="STR_ACE_Repair_timeCoefficientFullRepair_description">
<English>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.</English>
</Key>
<Key ID="STR_ACE_Repair_LocationsBoostTraining_Description"> <Key ID="STR_ACE_Repair_LocationsBoostTraining_Description">
<English>Boost engineer training when in repair vehicles or facilities. Untrained becomes engineer, engineer becomes advanced engineer.</English> <English>Boost engineer training when in repair vehicles or facilities. Untrained becomes engineer, engineer becomes advanced engineer.</English>
<French>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é.</French> <French>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é.</French>
@ -1860,7 +1866,7 @@
<Chinese>選擇的備件數量</Chinese> <Chinese>選擇的備件數量</Chinese>
</Key> </Key>
<Key ID="STR_ACE_Repair_WheelRepairRequiredItems_DisplayName"> <Key ID="STR_ACE_Repair_WheelRepairRequiredItems_DisplayName">
<English>Wheel Repair Requirements</English> <English>Wheel Change Requirements</English>
<German>Bedingungen für die Reifenreperatur</German> <German>Bedingungen für die Reifenreperatur</German>
<Polish>Wym. naprawy kół</Polish> <Polish>Wym. naprawy kół</Polish>
<Spanish>Requisitos de reparación de ruedas</Spanish> <Spanish>Requisitos de reparación de ruedas</Spanish>
@ -2062,6 +2068,18 @@
<Spanish>Apagar el motor automáticamente al efectuar una reparación</Spanish> <Spanish>Apagar el motor automáticamente al efectuar una reparación</Spanish>
<Korean>수리 시 엔진을 자동으로 끕니다.</Korean> <Korean>수리 시 엔진을 자동으로 끕니다.</Korean>
</Key> </Key>
<Key ID="STR_ACE_Repair_miscRepairTime_name">
<English>Part Repair Time</English>
</Key>
<Key ID="STR_ACE_Repair_miscRepairTime_description">
<English>Time in seconds to complete a repair.</English>
</Key>
<Key ID="STR_ACE_Repair_wheelChangeTime_name">
<English>Wheel Change Time</English>
</Key>
<Key ID="STR_ACE_Repair_wheelChangeTime_description">
<English>Time in seconds to remove or change a wheel.</English>
</Key>
<Key ID="STR_ACE_Repair_PatchWheel"> <Key ID="STR_ACE_Repair_PatchWheel">
<English>Patch Wheel</English> <English>Patch Wheel</English>
<German>Radflicken</German> <German>Radflicken</German>
@ -2071,16 +2089,16 @@
<German>Radflicken...</German> <German>Radflicken...</German>
</Key> </Key>
<Key ID="STR_ACE_Repair_patchWheelTime_DisplayName"> <Key ID="STR_ACE_Repair_patchWheelTime_DisplayName">
<English>Patch wheel time</English> <English>Wheel Patch Time</English>
</Key> </Key>
<Key ID="STR_ACE_Repair_patchWheelTime_Description"> <Key ID="STR_ACE_Repair_patchWheelTime_Description">
<English>Time it takes to patch a wheel by 5%.</English> <English>Time it takes to patch a wheel by 5%.</English>
</Key> </Key>
<Key ID="STR_ACE_Repair_patchWheelMaximumRepair_DisplayName"> <Key ID="STR_ACE_Repair_patchWheelMaximumRepair_DisplayName">
<English>Patch wheel maximum repair</English> <English>Patch Wheel Threshold</English>
</Key> </Key>
<Key ID="STR_ACE_Repair_patchWheelMaximumRepair_Description"> <Key ID="STR_ACE_Repair_patchWheelMaximumRepair_Description">
<English>Maximum level a wheel can be patched.</English> <English>Maximum level to which a wheel can be patched.</English>
</Key> </Key>
<Key ID="STR_ACE_Repair_patchWheelLocation_DisplayName"> <Key ID="STR_ACE_Repair_patchWheelLocation_DisplayName">
<English>Wheel Patch Location</English> <English>Wheel Patch Location</English>