Merge branch 'acemod:master' into master

This commit is contained in:
lambdatiger 2024-07-16 23:06:16 -05:00 committed by GitHub
commit 15d5256dcd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
161 changed files with 2741 additions and 1518 deletions

View File

@ -9,3 +9,4 @@ PREP(handleStaminaBar);
PREP(mainLoop);
PREP(moduleSettings);
PREP(removeDutyFactor);
PREP(renderDebugLines);

View File

@ -2,6 +2,10 @@
if (!hasInterface) exitWith {};
#ifdef DEBUG_MODE_FULL
call FUNC(renderDebugLines);
#endif
// recheck weapon inertia after weapon swap, change of attachments or switching unit
["weapon", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler;
["loadout", {[ACE_player] call FUNC(getWeaponInertia)}, true] call CBA_fnc_addPlayerEventHandler;
@ -33,25 +37,23 @@ if (!hasInterface) exitWith {};
GVAR(ppeBlackout) ppEffectCommit 0.4;
// - GVAR updating and initialization -----------------------------------------
["unit", LINKFUNC(handlePlayerChanged), true] call CBA_fnc_addPlayerEventHandler;
["unit", LINKFUNC(handlePlayerChanged)] call CBA_fnc_addPlayerEventHandler;
["visibleMap", {
params ["", "_visibleMap"]; // command visibleMap is updated one frame later
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlShow ((!_visibleMap) && {(vehicle ACE_player) == ACE_player});
(uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!_visibleMap && isNull objectParent ACE_player);
}, true] call CBA_fnc_addPlayerEventHandler;
["vehicle", {
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlShow ((!visibleMap) && {(vehicle ACE_player) == ACE_player});
(uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull]) ctrlShow (!visibleMap && isNull objectParent ACE_player);
}, true] call CBA_fnc_addPlayerEventHandler;
// - Duty factors -------------------------------------------------------------
if (GETEGVAR(medical,enabled,false)) then {
[QEGVAR(medical,pain), { // 0->1.0, 0.5->1.05, 1->1.1
linearConversion [0, 1, (_this getVariable [QEGVAR(medical,pain), 0]), 1, 1.1, true];
linearConversion [0, 1, _this getVariable [QEGVAR(medical,pain), 0], 1, 1.1, true];
}] call FUNC(addDutyFactor);
[QEGVAR(medical,bloodVolume), { // 6->1.0, 5->1.167, 4->1.33
linearConversion [6, 0, (_this getVariable [QEGVAR(medical,bloodVolume), 6]), 1, 2, true];
linearConversion [6, 0, _this getVariable [QEGVAR(medical,bloodVolume), 6], 1, 2, true];
}] call FUNC(addDutyFactor);
};
if (["ace_dragging"] call EFUNC(common,isModLoaded)) then {
@ -62,7 +64,7 @@ if (!hasInterface) exitWith {};
// Weather has an off switch, Dragging & Medical don't.
if (missionNamespace getVariable [QEGVAR(weather,enabled), false]) then {
[QEGVAR(weather,temperature), { // 35->1, 45->2
linearConversion [35, 45, (missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25]), 1, 2, true];
linearConversion [35, 45, missionNamespace getVariable [QEGVAR(weather,currentTemperature), 25], 1, 2, true];
}] call FUNC(addDutyFactor);
};

View File

@ -1,7 +1,7 @@
#include "..\script_component.hpp"
/*
* Author: BaerMitUmlaut
* Calculates the duty of the current animation.
* Calculates the duty ('postureWeight') of the current animation.
*
* Arguments:
* 0: Unit <OBJECT>

View File

@ -1,54 +1,74 @@
#include "..\script_component.hpp"
/*
* Author: BaerMitUmlaut
* Calculates the current metabolic costs for a unit.
* Author: BaerMitUmlaut, ulteq
* Calculates the current metabolic costs.
* Calculation is done according to the Pandolf/Wojtowicz formulas.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Speed <NUMBER>
* 0: Duty of animation
* 1: Mass of unit <NUMBER>
* 2: Terrain gradient <NUMBER>
* 3: Terrain factor <NUMBER>
* 4: Speed <NUMBER>
*
* Return Value:
* Metabolic cost <NUMBER>
*
* Example:
* [player, 3.3] call ace_advanced_fatigue_fnc_getMetabolicCosts
* [1, 840, 20, 1, 4] call ace_advanced_fatigue_fnc_getMetabolicCosts
*
* Public: No
*/
params ["_unit", "_velocity"];
private _gearMass = ((_unit getVariable [QEGVAR(movement,totalLoad), loadAbs _unit]) / 22.046) * GVAR(loadFactor);
private _terrainAngle = asin (1 - ((surfaceNormal getPosASL _unit) select 2));
private _terrainGradient = (_terrainAngle / 45 min 1) * 5 * GVAR(terrainGradientFactor);
private _duty = GVAR(animDuty);
{
if (_x isEqualType 0) then {
_duty = _duty * _x;
} else {
_duty = _duty * (_unit call _x);
};
} forEach (values GVAR(dutyList));
if (GVAR(isSwimming)) then {
_terrainGradient = 0;
};
params ["_duty", "_gearMass", "_terrainGradient", "_terrainFactor", "_speed"];
// Metabolic cost for walking and running is different
if (_velocity > 2) then {
if (_speed > 2) then {
// Running
#ifdef DEBUG_MODE_FULL
private _baseline = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 0.9 * (_speed ^ 2);
private _graded = 2.1 * SIM_BODYMASS + 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
private _terrainImpact = abs ((_graded / _baseline) - 1);
hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9",
_fwdAngle toFixed 1,
_sideAngle toFixed 1,
_terrainFactor toFixed 2,
_terrainGradient toFixed 1,
_terrainImpact toFixed 2,
_speed toFixed 2,
_gearMass toFixed 1,
_duty toFixed 2,
round (_graded * BIOMECH_EFFICIENCY * _duty)
];
#endif
(
2.10 * SIM_BODYMASS
2.1 * SIM_BODYMASS
+ 4 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
+ (SIM_BODYMASS + _gearMass) * (0.9 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
) * 0.23 * _duty
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (0.9 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient)
) * BIOMECH_EFFICIENCY * _duty
} else {
// Walking
#ifdef DEBUG_MODE_FULL
private _baseline = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + (SIM_BODYMASS + _gearMass) * 1.15 * (_speed ^ 2);
private _graded = 1.05 * SIM_BODYMASS + 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2) + _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient);
private _terrainImpact = abs ((_graded / _baseline) - 1);
hintSilent format ["FwdAngle: %1 | SideAngle: %2 \n TerrainFactor: %3 | TerrainGradient: %4 \n TerrainImpact: %5 \n Speed: %6 | CarriedLoad: %7 \n Duty: %8 | Work: %9",
_fwdAngle toFixed 1,
_sideAngle toFixed 1,
_terrainFactor toFixed 2,
_terrainGradient toFixed 1,
_terrainImpact toFixed 2,
_speed toFixed 2,
_gearMass toFixed 1,
_duty toFixed 2,
round (_graded * BIOMECH_EFFICIENCY * _duty)
];
#endif
(
1.05 * SIM_BODYMASS
+ 2 * (SIM_BODYMASS + _gearMass) * ((_gearMass / SIM_BODYMASS) ^ 2)
+ (SIM_BODYMASS + _gearMass) * (1.15 * (_velocity ^ 2) + 0.66 * _velocity * _terrainGradient)
) * 0.23 * _duty
+ _terrainFactor * (SIM_BODYMASS + _gearMass) * (1.15 * (_speed ^ 2) + 0.66 * _speed * _terrainGradient)
) * BIOMECH_EFFICIENCY * _duty
};

View File

@ -1,44 +1,44 @@
#include "..\script_component.hpp"
/*
* Author: BaerMitUmlaut
* Author: BaerMitUmlaut, ulteq
* Handles any audible, visual and physical effects of fatigue.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Fatigue <NUMBER>
* 2: Speed <NUMBER>
* 3: Overexhausted <BOOL>
* 2: Overexhausted <BOOL>
* 3: Forward Angle <NUMBER>
* 4: Side Angle <NUMBER>
*
* Return Value:
* None
*
* Example:
* [_player, 0.5, 3.3, true] call ace_advanced_fatigue_fnc_handleEffects
* [_player, 0.5, 3.3, true, 0, 0] call ace_advanced_fatigue_fnc_handleEffects
*
* Public: No
*/
params ["_unit", "_fatigue", "_speed", "_overexhausted"];
#ifdef DEBUG_MODE_FULL
systemChat str _fatigue;
systemChat str vectorMagnitude velocity _unit;
#endif
params ["_unit", "_fatigue", "_overexhausted", "_fwdAngle", "_sideAngle"];
// - Audible effects ----------------------------------------------------------
GVAR(lastBreath) = GVAR(lastBreath) + 1;
if (_fatigue > 0.4 && {GVAR(lastBreath) > (_fatigue * -10 + 9)} && {!underwater _unit}) then {
if (!isGameFocused) exitWith {};
switch (true) do {
case (_fatigue < 0.6): {
playSound (QGVAR(breathLow) + str(floor random 6));
playSound (QGVAR(breathLow) + str (floor random 6));
};
case (_fatigue < 0.85): {
playSound (QGVAR(breathMid) + str(floor random 6));
playSound (QGVAR(breathMid) + str (floor random 6));
};
default {
playSound (QGVAR(breathMax) + str(floor random 6));
playSound (QGVAR(breathMax) + str (floor random 6));
};
};
GVAR(lastBreath) = 0;
};
@ -62,31 +62,35 @@ if (GVAR(isSwimming)) exitWith {
if (GVAR(setAnimExclusions) isEqualTo []) then {
_unit setAnimSpeedCoef linearConversion [0.7, 0.9, _fatigue, 1, 0.5, true];
};
if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
if (isSprintAllowed _unit && _fatigue > 0.7) then { // small checks like these are faster without lazy eval
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else {
if ((!isSprintAllowed _unit) && {_fatigue < 0.7}) then {
if (!isSprintAllowed _unit && _fatigue < 0.7) then {
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
};
};
};
if ((getAnimSpeedCoef _unit) != 1) then {
if (GVAR(setAnimExclusions) isEqualTo []) then {
TRACE_1("reset",getAnimSpeedCoef _unit);
_unit setAnimSpeedCoef 1;
};
// If other components are setting setAnimSpeedCoef, do not change animSpeedCoef
if (getAnimSpeedCoef _unit != 1 && {GVAR(setAnimExclusions) isEqualTo []}) then {
TRACE_1("reset",getAnimSpeedCoef _unit);
_unit setAnimSpeedCoef 1;
};
if (_overexhausted) then {
if (!isForcedWalk _unit && _fatigue >= 1) then { // small checks like these are faster without lazy eval
[_unit, "forceWalk", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else {
if (isForcedWalk _unit && {_fatigue < 0.7}) then {
if (isForcedWalk _unit && _fatigue < 0.7) then {
[_unit, "forceWalk", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
} else {
if ((isSprintAllowed _unit) && {_fatigue > 0.7}) then {
// Forward angle is the slope of the terrain, side angle simulates the unevenness/roughness of the terrain
if (isSprintAllowed _unit && {_fatigue > 0.7 || abs _fwdAngle > 20 || abs _sideAngle > 20}) then {
[_unit, "blockSprint", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
} else {
if ((!isSprintAllowed _unit) && {_fatigue < 0.6}) then {
if (!isSprintAllowed _unit && _fatigue < 0.6 && abs _fwdAngle < 20 && abs _sideAngle < 20) then {
[_unit, "blockSprint", QUOTE(ADDON), false] call EFUNC(common,statusEffect_set);
};
};

View File

@ -1,7 +1,7 @@
#include "..\script_component.hpp"
/*
* Author: BaerMitUmlaut
* Handles switching units (once on init and afterwards via Zeus).
* Author: BaerMitUmlaut, ulteq
* Handles switching units (once on init and afterwards via Zeus). Also handles CBA setting change for performance factor.
*
* Arguments:
* 0: New Unit <OBJECT>
@ -15,20 +15,24 @@
*
* Public: No
*/
params ["_newUnit", "_oldUnit"];
TRACE_2("unit changed",_newUnit,_oldUnit);
if !(isNull _oldUnit) then {
if (!isNull _oldUnit) then {
TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler));
_oldUnit enableStamina true;
_oldUnit removeEventHandler ["AnimChanged", _oldUnit getVariable [QGVAR(animHandler), -1]];
_oldUnit setVariable [QGVAR(animHandler), nil];
TRACE_1("remove old",_oldUnit getVariable QGVAR(animHandler));
_oldUnit setVariable [QGVAR(ae1Reserve), GVAR(ae1Reserve)];
_oldUnit setVariable [QGVAR(ae2Reserve), GVAR(ae2Reserve)];
_oldUnit setVariable [QGVAR(anReserve), GVAR(anReserve)];
_oldUnit setVariable [QGVAR(anFatigue), GVAR(anFatigue)];
_oldUnit setVariable [QGVAR(muscleDamage), GVAR(muscleDamage)];
_oldUnit setVariable [QGVAR(respiratoryRate), GVAR(respiratoryRate)];
};
_newUnit enableStamina false;
@ -38,6 +42,7 @@ if (_newUnit getVariable [QGVAR(animHandler), -1] == -1) then {
private _animHandler = _newUnit addEventHandler ["AnimChanged", {
GVAR(animDuty) = _this call FUNC(getAnimDuty);
}];
TRACE_1("add new",_animHandler);
_newUnit setVariable [QGVAR(animHandler), _animHandler];
};
@ -47,18 +52,27 @@ GVAR(ae2Reserve) = _newUnit getVariable [QGVAR(ae2Reserve), AE2_MAXRESERVE]
GVAR(anReserve) = _newUnit getVariable [QGVAR(anReserve), AN_MAXRESERVE];
GVAR(anFatigue) = _newUnit getVariable [QGVAR(anFatigue), 0];
GVAR(muscleDamage) = _newUnit getVariable [QGVAR(muscleDamage), 0];
GVAR(respiratoryRate) = _newUnit getVariable [QGVAR(respiratoryRate), 0];
// Clean variables for respawning units
{
_newUnit setVariable [_x, nil];
} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage)];
} forEach [QGVAR(ae1Reserve), QGVAR(ae2Reserve), QGVAR(anReserve), QGVAR(anFatigue), QGVAR(muscleDamage), QGVAR(respiratoryRate)];
GVAR(VO2Max) = 35 + 20 * (_newUnit getVariable [QGVAR(performanceFactor), GVAR(performanceFactor)]);
GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * 0.23 * JOULES_PER_ML_O2 / 60;
GVAR(VO2MaxPower) = GVAR(VO2Max) * SIM_BODYMASS * BIOMECH_EFFICIENCY * JOULES_PER_ML_O2 / 60;
GVAR(peakPower) = VO2MAX_STRENGTH * GVAR(VO2MaxPower);
GVAR(ae1PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 13.3 * ANTPERCENT ^ 1.28 * 1.362;
GVAR(ae2PathwayPower) = GVAR(peakPower) / (13.3 + 16.7 + 113.3) * 16.7 * ANTPERCENT ^ 1.28 * 1.362;
GVAR(ae1PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE1_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362;
GVAR(ae2PathwayPower) = GVAR(peakPower) / (AE1_ATP_RELEASE_RATE + AE2_ATP_RELEASE_RATE + AN_ATP_RELEASE_RATE) * AE2_ATP_RELEASE_RATE * ANTPERCENT ^ 1.28 * 1.362;
GVAR(aePathwayPower) = GVAR(ae1PathwayPower) + GVAR(ae2PathwayPower);
GVAR(anPathwayPower) = GVAR(peakPower) - GVAR(aePathwayPower);
GVAR(aeWattsPerATP) = GVAR(ae1PathwayPower) / AE1_ATP_RELEASE_RATE;
GVAR(anWattsPerATP) = GVAR(anPathwayPower) / AN_ATP_RELEASE_RATE;
GVAR(respiratoryBufferDivisor) = (RESPIRATORY_BUFFER - 1) / RESPIRATORY_BUFFER;
GVAR(maxPowerFatigueRatio) = 0.057 / GVAR(peakPower);
GVAR(ppeBlackoutLast) = 100;
GVAR(lastBreath) = 0;

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp"
/*
* Author: BaerMitUmlaut
* Author: BaerMitUmlaut, ulteq
* Main looping function that updates fatigue values.
*
* Arguments:
@ -17,73 +17,131 @@
// Dead people don't breathe, will also handle null (map intros)
if (!alive ACE_player) exitWith {
[FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
[LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 1;
_staminaBarContainer ctrlCommit 1;
};
private _oxygen = 0.9; // Default AF oxygen saturation
if (GETEGVAR(medical,enabled,false) && {EGVAR(medical_vitals,simulateSpo2)}) then {
_oxygen = (ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100;
};
private _velocity = velocity ACE_player;
private _normal = surfaceNormal (getPosWorld ACE_player);
private _movementVector = vectorNormalized _velocity;
private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal);
private _fwdAngle = asin (_movementVector select 2);
private _sideAngle = asin (_sideVector select 2);
private _currentWork = REE;
private _currentSpeed = (vectorMagnitude (velocity ACE_player)) min 6;
private _currentSpeed = (vectorMagnitude _velocity) min 6;
// fix #4481. Diving to the ground is recorded as PRONE stance with running speed velocity. Cap maximum speed to fix.
if (GVAR(isProne)) then {
_currentSpeed = _currentSpeed min 1.5;
};
if ((vehicle ACE_player == ACE_player) && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then {
_currentWork = [ACE_player, _currentSpeed] call FUNC(getMetabolicCosts);
// Get the current duty
private _duty = GVAR(animDuty);
{
if (_x isEqualType 0) then {
_duty = _duty * _x;
} else {
_duty = _duty * (ACE_player call _x);
};
} forEach (values GVAR(dutyList));
private _terrainGradient = abs _fwdAngle;
private _terrainFactor = 1;
private _gearMass = 0 max (((ACE_player getVariable [QEGVAR(movement,totalLoad), loadAbs ACE_player]) / 22.046 - UNDERWEAR_WEIGHT) * GVAR(loadFactor));
if (isNull objectParent ACE_player && {_currentSpeed > 0.1} && {isTouchingGround ACE_player || {underwater ACE_player}}) then {
if (!GVAR(isSwimming)) then {
// If the unit is going downhill, it's much less demanding
if (_fwdAngle < 0) then {
_terrainGradient = 0.15 * _terrainGradient;
};
// Used to simulate the unevenness/roughness of the terrain
if ((getPosATL ACE_player) select 2 < 0.01) then {
private _sideGradient = abs (_sideAngle / 45) min 1;
_terrainFactor = 1 + _sideGradient ^ 4;
};
};
_currentWork = [_duty, _gearMass, _terrainGradient * GVAR(terrainGradientFactor), _terrainFactor, _currentSpeed] call FUNC(getMetabolicCosts);
_currentWork = _currentWork max REE;
};
// Oxygen calculation
private _oxygen = if (GETEGVAR(medical,enabled,false) && {EGVAR(medical_vitals,simulateSpo2)}) then { // Defer to medical
(ACE_player getVariable [QEGVAR(medical,spo2), 97]) / 100
} else {
1 - 0.131 * GVAR(respiratoryRate) ^ 2 // Default AF oxygen saturation
};
// Calculate muscle damage increase
// Note: Muscle damage recovery is ignored as it takes multiple days
GVAR(muscleDamage) = (GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * 0.00004) min 1;
private _muscleIntegritySqrt = sqrt (1 - GVAR(muscleDamage));
GVAR(muscleDamage) = GVAR(muscleDamage) + (_currentWork / GVAR(peakPower)) ^ 3.2 * MUSCLE_TEAR_RATE;
// Calculate muscle damage recovery
GVAR(muscleDamage) = 0 max (GVAR(muscleDamage) - MUSCLE_RECOVERY * GVAR(recoveryFactor)) min 1;
private _muscleIntegrity = 1 - GVAR(muscleDamage);
private _muscleFactor = sqrt _muscleIntegrity;
// Calculate available power
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleIntegritySqrt;
private _ae1PathwayPowerFatigued = GVAR(ae1PathwayPower) * sqrt (GVAR(ae1Reserve) / AE1_MAXRESERVE) * _oxygen * _muscleFactor;
private _ae2PathwayPowerFatigued = GVAR(ae2PathwayPower) * sqrt (GVAR(ae2Reserve) / AE2_MAXRESERVE) * _oxygen * _muscleFactor;
private _aePathwayPowerFatigued = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued;
private _anPathwayPowerFatigued = GVAR(anPathwayPower) * sqrt (GVAR(anReserve) / AN_MAXRESERVE) * _oxygen * _muscleIntegrity;
// Calculate how much power is consumed from each reserve
private _ae1Power = _currentWork min _ae1PathwayPowerFatigued;
private _ae2Power = ((_currentWork - _ae1Power) max 0) min _ae2PathwayPowerFatigued;
private _anPower = (_currentWork - _ae1Power - _ae2Power) max 0;
private _ae2Power = (_currentWork - _ae1Power) min _ae2PathwayPowerFatigued;
private _anPower = 0 max (_currentWork - _ae1Power - _ae2Power);
// Remove ATP from reserves for current work
GVAR(ae1Reserve) = GVAR(ae1Reserve) - _ae1Power / WATTSPERATP;
GVAR(ae2Reserve) = GVAR(ae2Reserve) - _ae2Power / WATTSPERATP;
GVAR(anReserve) = GVAR(anReserve) - _anPower / WATTSPERATP;
// Increase anearobic fatigue
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * (0.057 / GVAR(peakPower)) * 1.1;
GVAR(ae1Reserve) = 0 max (GVAR(ae1Reserve) - _ae1Power / GVAR(aeWattsPerATP));
GVAR(ae2Reserve) = 0 max (GVAR(ae2Reserve) - _ae2Power / GVAR(aeWattsPerATP));
GVAR(anReserve) = 0 max (GVAR(anReserve) - _anPower / GVAR(anWattsPerATP));
// Acidosis accumulation
GVAR(anFatigue) = GVAR(anFatigue) + _anPower * GVAR(maxPowerFatigueRatio) * 1.1;
// Aerobic ATP reserve recovery
GVAR(ae1Reserve) = ((GVAR(ae1Reserve) + _oxygen * 6.60 * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower) * GVAR(recoveryFactor)) min AE1_MAXRESERVE) max 0;
GVAR(ae2Reserve) = ((GVAR(ae2Reserve) + _oxygen * 5.83 * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower) * GVAR(recoveryFactor)) min AE2_MAXRESERVE) max 0;
GVAR(ae1Reserve) = (GVAR(ae1Reserve) + _oxygen * GVAR(recoveryFactor) * AE1_ATP_RECOVERY * (GVAR(ae1PathwayPower) - _ae1Power) / GVAR(ae1PathwayPower)) min AE1_MAXRESERVE;
GVAR(ae2Reserve) = (GVAR(ae2Reserve) + _oxygen * GVAR(recoveryFactor) * AE2_ATP_RECOVERY * (GVAR(ae2PathwayPower) - _ae2Power) / GVAR(ae2PathwayPower)) min AE2_MAXRESERVE;
// Anaerobic ATP reserver and fatigue recovery
GVAR(anReserve) = ((GVAR(anReserve)
+ (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) / GVAR(VO2MaxPower) * 56.7 * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
) min AN_MAXRESERVE) max 0;
private _aeSurplus = _ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power;
GVAR(anFatigue) = ((GVAR(anFatigue)
- (_ae1PathwayPowerFatigued + _ae2PathwayPowerFatigued - _ae1Power - _ae2Power) * (0.057 / GVAR(peakPower)) * GVAR(anFatigue) ^ 2 * GVAR(recoveryFactor)
) min 1) max 0;
// Anaerobic ATP reserve recovery
GVAR(anReserve) = 0 max (GVAR(anReserve) + _aeSurplus / GVAR(VO2MaxPower) * AN_ATP_RECOVERY * GVAR(recoveryFactor) * (GVAR(anFatigue) max linearConversion [AN_MAXRESERVE, 0, GVAR(anReserve), 0, 0.75, true]) ^ 2) min AN_MAXRESERVE; // max linearConversion ensures that if GVAR(anFatigue) is very low, it will still regenerate reserves
// Acidosis recovery
GVAR(anFatigue) = 0 max (GVAR(anFatigue) - _aeSurplus * GVAR(maxPowerFatigueRatio) * GVAR(recoveryFactor) * GVAR(anFatigue) ^ 2) min 1;
// Respiratory rate decrease
GVAR(respiratoryRate) = GVAR(respiratoryRate) * GVAR(respiratoryBufferDivisor);
// Respiratory rate increase
private _aePowerRatio = (GVAR(aePathwayPower) / _aePathwayPowerFatigued) min 2;
private _respiratorySampleDivisor = 1 / (RESPIRATORY_BUFFER * 4.72 * GVAR(VO2Max));
GVAR(respiratoryRate) = (GVAR(respiratoryRate) + _currentWork * _respiratorySampleDivisor * _aePowerRatio) min 1;
// Calculate a pseudo-perceived fatigue, which is used for effects
GVAR(aeReservePercentage) = (GVAR(ae1Reserve) / AE1_MAXRESERVE + GVAR(ae2Reserve) / AE2_MAXRESERVE) / 2;
GVAR(anReservePercentage) = GVAR(anReserve) / AN_MAXRESERVE;
private _perceivedFatigue = 1 - (GVAR(anReservePercentage) min GVAR(aeReservePercentage));
[ACE_player, _perceivedFatigue, _currentSpeed, GVAR(anReserve) == 0] call FUNC(handleEffects);
#ifdef DEBUG_MODE_FULL
systemChat format ["---- muscleDamage: %1 ----", GVAR(muscleDamage) toFixed 8];
systemChat format ["---- ae2: %1 - an: %2 ----", (GVAR(ae2Reserve) / AE2_MAXRESERVE) toFixed 2, (GVAR(anReserve) / AN_MAXRESERVE) toFixed 2];
systemChat format ["---- anFatigue: %1 - perceivedFatigue: %2 ----", GVAR(anFatigue) toFixed 2, _perceivedFatigue toFixed 2];
systemChat format ["---- velocity %1 - respiratoryRate: %2 ----", (vectorMagnitude _velocity) toFixed 2, GVAR(respiratoryRate) toFixed 2];
// systemChat format ["---- aePower: %1 ----", _aePathwayPowerFatigued toFixed 1];
#endif
[ACE_player, _perceivedFatigue, GVAR(anReserve) == 0, _fwdAngle, _sideAngle] call FUNC(handleEffects);
if (GVAR(enableStaminaBar)) then {
[GVAR(anReserve) / AN_MAXRESERVE] call FUNC(handleStaminaBar);
};
[FUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;
[LINKFUNC(mainLoop), [], 1] call CBA_fnc_waitAndExecute;

View File

@ -0,0 +1,40 @@
#include "..\script_component.hpp"
/*
* Author: ulteq
* Draw lines for debugging.
*
* Arguments:
* None
*
* Return Value:
* None
*
* Example:
* call ace_advanced_fatigue_fnc_renderDebugLines
*
* Public: No
*/
addMissionEventHandler ["Draw3D", {
private _normal = surfaceNormal (getPosWorld ACE_player);
private _beg = (getPosWorld ACE_player) vectorAdd (_normal vectorMultiply 0.5);
private _end = _beg vectorAdd (_normal vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 0, 1]];
private _side = vectorNormalized (_normal vectorCrossProduct [0, 0, 1]);
private _end = _beg vectorAdd (_side vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 0, 1, 1]];
private _up = vectorNormalized (_normal vectorCrossProduct _side);
private _end = _beg vectorAdd (_up vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 0, 0, 1]];
private _movementVector = vectorNormalized (velocity ACE_player);
private _end = _beg vectorAdd (_movementVector vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [1, 1, 0, 1]];
private _sideVector = vectorNormalized (_movementVector vectorCrossProduct _normal);
_sideVector set [2, 0];
private _end = _beg vectorAdd (_sideVector vectorMultiply 2);
drawLine3D [ASLToATL _beg, ASLToATL _end, [0, 1, 1, 1]];
}];

View File

@ -4,12 +4,14 @@
[LSTRING(Enabled), LSTRING(Enabled_Description)],
LSTRING(DisplayName),
true,
true, {
1,
{
if (!_this) then {
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 1;
_staminaBarContainer ctrlCommit 0;
};
[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)
},
true // Needs mission restart
@ -21,7 +23,8 @@
[LSTRING(EnableStaminaBar), LSTRING(EnableStaminaBar_Description)],
LSTRING(DisplayName),
true,
true, {
1,
{
if (!_this) then {
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 1;
@ -36,7 +39,8 @@
[LSTRING(FadeStaminaBar), LSTRING(FadeStaminaBar_Description)],
LSTRING(DisplayName),
true,
false, {
0,
{
if (!_this && GVAR(enabled) && GVAR(enableStaminaBar)) then {
private _staminaBarContainer = uiNamespace getVariable [QGVAR(staminaBarContainer), controlNull];
_staminaBarContainer ctrlSetFade 0;
@ -50,8 +54,14 @@
"SLIDER",
[LSTRING(PerformanceFactor), LSTRING(PerformanceFactor_Description)],
LSTRING(DisplayName),
[0, 5, 1, 1],
true
[0, 10, 1, 2],
1,
{
// Recalculate values if the setting is changed mid-mission
if (GVAR(enabled) && hasInterface && !isNull ACE_player) then {
[ACE_player, ACE_player] call FUNC(handlePlayerChanged);
};
}
] call CBA_fnc_addSetting;
[
@ -59,8 +69,8 @@
"SLIDER",
[LSTRING(RecoveryFactor), LSTRING(RecoveryFactor_Description)],
LSTRING(DisplayName),
[0, 5, 1, 1],
true
[0, 10, 1, 2],
1
] call CBA_fnc_addSetting;
[
@ -68,8 +78,8 @@
"SLIDER",
[LSTRING(LoadFactor), LSTRING(LoadFactor_Description)],
LSTRING(DisplayName),
[0, 5, 1, 1],
true
[0, 5, 1, 2],
1
] call CBA_fnc_addSetting;
[
@ -77,6 +87,6 @@
"SLIDER",
[LSTRING(TerrainGradientFactor), LSTRING(TerrainGradientFactor_Description)],
LSTRING(DisplayName),
[0, 5, 1, 1],
true
[0, 5, 1, 2],
1
] call CBA_fnc_addSetting;

View File

@ -16,14 +16,28 @@
#include "\z\ace\addons\main\script_macros.hpp"
#define UNDERWEAR_WEIGHT 3.5
#define ANTPERCENT 0.8
#define SIM_BODYMASS 70
#define JOULES_PER_ML_O2 20.9
#define VO2MAX_STRENGTH 4.1
#define REE 18.83 //((0.5617 * SIM_BODYMASS + 42.57) * 0.23)
#define OXYGEN 0.9
#define WATTSPERATP 7
#define BIOMECH_EFFICIENCY 0.23
#define REE 18.83 // ((0.5617 * SIM_BODYMASS + 42.57) * BIOMECH_EFFICIENCY)
#define AE1_MAXRESERVE 4000000
#define AE2_MAXRESERVE 84000
#define AN_MAXRESERVE 2300
#define RESPIRATORY_BUFFER 60
#define MUSCLE_TEAR_RATE 0.00004
#define MUSCLE_RECOVERY 0.00000386
#define AE1_ATP_RELEASE_RATE 13.3 // mmol
#define AE2_ATP_RELEASE_RATE 16.7 // mmol
#define AN_ATP_RELEASE_RATE 113.3 // mmol
#define AE1_ATP_RECOVERY 6.60 // mmol
#define AE2_ATP_RECOVERY 5.83 // mmol
#define AN_ATP_RECOVERY 56.70 // mmol
#define AE1_MAXRESERVE 4000000 // mmol
#define AE2_MAXRESERVE 84000 // mmol
#define AN_MAXRESERVE 2300 // mmol

View File

@ -144,7 +144,7 @@
<English>Enables ability to pick up throwables from the ground.</English>
<Spanish>Activa la habilidad de coger objetos lanzados del suelo</Spanish>
<Russian>Включает возможность подбирать гранаты с земли.</Russian>
<Japanese>地面に落ちている投擲物を拾い上げる機能を有効化します。</Japanese>
<Japanese>地面に落ちている投擲物を拾機能を有効化します。</Japanese>
<Polish>Umożliwia podnoszenie obiektów miotanych z ziemi.</Polish>
<German>Aktiviert die Möglichkeit, geworfene Objekte wieder vom Boden aufzuheben.</German>
<Korean>땅에 떨어진 투척물을 주울 수 있게 해줍니다.</Korean>
@ -174,7 +174,7 @@
<English>Enables ability to pick up throwables from attached objects.</English>
<Spanish>Activa la habilidad de lanzar objetos enganchados</Spanish>
<Russian>Включает возможность подбирать гранаты, прикрепленные к объектам.</Russian>
<Japanese>オブジェクトに装着された投擲可能物を拾い上げる機能を有効化します。</Japanese>
<Japanese>オブジェクトに装着された投擲物を拾う機能を有効化します。</Japanese>
<Polish>Umożliwia podnoszenie obiektów miotanych przyczepionych do innych obiektów.</Polish>
<German>Aktiviert die Möglichkeit, befestigte Wurfobjekte erneut aufzunehmen.</German>
<Korean>부착된 투척물을 주울 수 있게 해줍니다.</Korean>
@ -254,7 +254,7 @@
<English>Primed</English>
<Spanish>Preparado</Spanish>
<Russian>Подготовлена</Russian>
<Japanese>点火</Japanese>
<Japanese>点火した</Japanese>
<Polish>Odbezpieczony</Polish>
<German>Scharf gemacht</German>
<Korean>뇌관 작동</Korean>

View File

@ -22,7 +22,7 @@ if (!alive _vehicle) exitWith {};
if (_vehicle getVariable [QGVAR(droneActionsAdded), false]) exitWith {};
_vehicle setVariable [QGVAR(droneActionsAdded), true];
// move to location
// Move to location
private _condition = {
params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
@ -37,14 +37,63 @@ private _action = [QGVAR(droneSetWaypointMove), localize "$STR_AC_MOVE",
"\a3\3DEN\Data\CfgWaypoints\Move_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// Follow unit/vehicle at turret location
_condition = {
params ["_vehicle"];
private _target = cursorTarget;
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {!isNull _target} && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}
};
_statement = {
params ["_vehicle"];
private _group = group driver _vehicle;
private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0;
[QGVAR(droneSetWaypoint), [_vehicle, _group, _pos, "FOLLOW", cursorTarget], _group] call CBA_fnc_targetEvent;
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
[[LLSTRING(DroneFollowHint), _followDistance], 3] call EFUNC(common,displayTextStructured);
};
_action = [QGVAR(droneSetWaypointFollow), localize "$STR_AC_FOLLOW", "\a3\3DEN\Data\CfgWaypoints\Follow_ca.paa", _statement, _condition] call EFUNC(interact_menu,createAction);
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// Set drone follow distance
_condition = {
params ["_vehicle"];
private _group = group driver _vehicle;
private _index = (currentWaypoint _group) min count waypoints _group;
private _waypoint = [_group, _index];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]} && {(waypointType _waypoint) == "HOLD"}
};
_statement = {
params ["_vehicle", "", "_value"];
_vehicle setVariable [QGVAR(wpFollowDistance), _value];
[[LLSTRING(DroneFollowHint), _value], 3] call EFUNC(common,displayTextStructured);
};
_action = [QGVAR(droneSetFollowDistance), LLSTRING(DroneFollowDistance), "", {}, _condition] call EFUNC(interact_menu,createAction);
private _base = [_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
private _followDistances = if (_vehicle isKindOf "Car_F") then {
[0, 25, 50, 100, 200]
} else {
[0, 100, 200, 300, 400, 500]
};
{
_action = [
QGVAR(droneSetFollowDistance_) + str _x,
str _x,
"",
_statement,
{true},
{},
_x
] call EFUNC(interact_menu,createAction);
[_vehicle, 1, _base, _action] call EFUNC(interact_menu,addActionToObject);
} forEach _followDistances;
if (_vehicle isKindOf "Air") then {
// loiter at location
// Loiter at location
_condition = {
params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
};
_statement = {
_statement = {
params ["_vehicle"];
private _group = group driver _vehicle;
private _pos = ([_vehicle, [0]] call FUNC(droneGetTurretTargetPos)) select 0;
@ -55,7 +104,7 @@ if (_vehicle isKindOf "Air") then {
[_vehicle, 1, ["ACE_SelfActions"], _action] call EFUNC(interact_menu,addActionToObject);
// set height
// Set height
_condition = {
params ["_vehicle"];
(missionNamespace getVariable [QGVAR(droneWaypoints), true]) && {waypointsEnabledUAV _vehicle} && {(ACE_controlledUAV select 2) isEqualTo [0]}
@ -74,7 +123,7 @@ if (_vehicle isKindOf "Air") then {
} forEach [20, 50, 200, 500, 2000];
// set loiter radius
// Set loiter radius
_condition = {
params ["_vehicle"];
private _group = group driver _vehicle;
@ -97,7 +146,7 @@ if (_vehicle isKindOf "Air") then {
} forEach [500, 750, 1000, 1250, 1500];
// set loiter direction
// Set loiter direction
_condition = {
params ["_vehicle", "", "_args"];
private _group = group driver _vehicle;

View File

@ -8,6 +8,7 @@
* 1: Group <GROUP>
* 2: Pos 2D <ARRAY>
* 3: Type <STRING>
* 4: Target to follow <OBJECT> (default: objNull)
*
* Return Value:
* None
@ -18,7 +19,7 @@
* Public: No
*/
params ["_vehicle", "_group", "_pos", "_type"];
params ["_vehicle", "_group", "_pos", "_type", ["_target", objNull]];
TRACE_4("droneSetWaypoint",_vehicle,_group,_pos,_type);
private _index = (currentWaypoint _group) min count waypoints _group;
@ -34,9 +35,34 @@ _pos set [
[0, _currentHeight] select (_currentHeight >= 50)
];
// [_group] call CBA_fnc_clearWaypoints;
_waypoint = _group addWaypoint [_pos, 0];
_waypoint setWaypointType _type;
// The Vanilla "FOLLOW"-type waypoint is not used directly, due to 2 main issues (as of v2.16):
// - It does not work at all for UGVs, which is a known issue https://feedback.bistudio.com/T126283;
// - No clear scripting way was found to mimic the UAV Terminal's "Follow Distance" functionality;
// Instead, the solution for both UAV and UGV following consists of a CBA PFH that moves a "HOLD"-type Waypoint every 3 seconds.
// Either on the target itself, or on the Drone's current position if the target is within the desired follow distance.
if (_type == "FOLLOW" && {["CAManBase", "LandVehicle", "Ship"] findIf {_target isKindOf _x} != -1}) then {
_waypoint setWaypointType "HOLD";
[{
params ["_args", "_handle"];
_args params ["_vehicle", "_group", "_waypoint", "_target"];
if ( // Abort PFH if a new waypoint is created via UAV Terminal or ACE Interaction
_waypoint select 1 != currentWaypoint _group ||
{!alive _vehicle} || {isNull _target}
) exitWith {
deleteWaypoint _waypoint;
[_handle] call CBA_fnc_removePerFrameHandler;
};
private _followDistance = _vehicle getVariable [QGVAR(wpFollowDistance), 0];
if ((_vehicle distance2D _target) < _followDistance) then {
_waypoint setWaypointPosition [getPosASL _vehicle, -1];
} else {
_waypoint setWaypointPosition [getPosASL _target, -1];
};
}, 3, [_vehicle, _group, _waypoint, _target]] call CBA_fnc_addPerFrameHandler;
};
TRACE_3("",_currentHeight,_currentLoiterRadius,_currentLoiterType);
if (_currentHeight > 1) then { _vehicle flyInHeight _currentHeight; };

View File

@ -129,7 +129,7 @@
<Japanese>30mm コンバット ミックス 4:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese>
<Czech>30mm Bojový Mix 4:1 DU:HEI</Czech>
<Russian>30мм Смешанное боепитание 4:1 ОУ:ОФЗ</Russian>
<Korean>30mm 4:1 열화:고폭소이</Korean>
<Korean>30mm 열화우라늄:고폭소이 4:1 혼합</Korean>
<Portuguese>30mm Mix de Combate 4:1 DU:AEI</Portuguese>
</Key>
<Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM41">
@ -145,7 +145,7 @@
<Japanese>30mm CM 4:1</Japanese>
<Czech>30mm BM 4:1</Czech>
<Russian>30мм СБ 4:1</Russian>
<Korean>30mm CM 4:1</Korean>
<Korean>30mm 4:1 혼합</Korean>
</Key>
<Key ID="STR_ACE_Aircraft_GatlingDescriptionCM51">
<English>30mm Combat Mix 5:1 DU:HEI</English>
@ -160,7 +160,7 @@
<Japanese>30mm コンバット ミックス 5:1 劣化ウラン徹甲弾:焼夷榴弾</Japanese>
<Czech>30mm Bojový Mix 5:1 DU:HEI</Czech>
<Russian>30мм Смешанное боепитание 5:1 ОУ:ОФЗ</Russian>
<Korean>30mm 5:1 열화:고폭소이</Korean>
<Korean>30mm 열화우라늄:고폭소이 5:1 혼합</Korean>
</Key>
<Key ID="STR_ACE_Aircraft_GatlingDescriptionShortCM51">
<English>30mm CM 5:1</English>
@ -175,7 +175,21 @@
<Japanese>30mm CM 5:1</Japanese>
<Czech>30mm BM 5:1</Czech>
<Russian>30мм СБ 5:1</Russian>
<Korean>30mm CM 5:1</Korean>
<Korean>30mm 5:1 혼합</Korean>
</Key>
<Key ID="STR_ACE_Aircraft_DroneFollowDistance">
<English>Follow Distance</English>
<Italian>Distanza di seguimento</Italian>
<German>Folge-Entfernung</German>
<Korean>따라가는 거리</Korean>
<Japanese>追跡距離</Japanese>
</Key>
<Key ID="STR_ACE_Aircraft_DroneFollowHint">
<English>Following unit within %1m</English>
<Italian>Seguendo unità entro %1m</Italian>
<German>Folgt Einheit bis zu %1m</German>
<Korean>%1m 이내로 유닛을 따라갑니다</Korean>
<Japanese>%1m 間隔で 目標を追跡します</Japanese>
</Key>
</Package>
</Project>

View File

@ -23,7 +23,7 @@
<French>Masque l'interface</French>
<German>Oberfläche verstecken</German>
<Polish>Ukryj interfejs</Polish>
<Japanese>インタフェースを隠す</Japanese>
<Japanese>インタフェースを隠す</Japanese>
<Italian>Nascondi interfaccia</Italian>
<Korean>인터페이스 숨기기</Korean>
<Chinese>隱藏介面</Chinese>

View File

@ -35,7 +35,7 @@ if (isNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction)))
_airFriction = getNumber (configFile >> "CfgMagazines" >> _magazine >> QGVAR(airFriction));
};
TRACE_1("",_airFriction);
if (_airFriction >= 0) exitWith {}; // 0 disables everything, >0 makes no sense
if (_airFriction == 0) exitWith {}; // 0 disables everything
BEGIN_COUNTER(adjustmentsCalc);
@ -60,6 +60,7 @@ if (_newMuzzleVelocityCoefficent != 1) then {
_projectile setVelocity _bulletVelocity;
};
if (_airFriction > 0) exitWith {}; // positive value indicates it has vanilla airFriction, so we can just exit
[{
params ["_projectile", "_kFactor", "_time"];

View File

@ -41,8 +41,15 @@ _mags = _mags apply {
private _initSpeed = getNumber (_magCfg >> _x >> "initSpeed");
_magParamsArray pushBackUnique _initSpeed;
private _airFriction = 0;
if (_advCorrection) then {
_airFriction = if (isNumber (_magCfg >> _x >> QGVAR(airFriction))) then { getNumber (_magCfg >> _x >> QGVAR(airFriction)) } else { DEFAULT_AIR_FRICTION };
private _magAirFriction = getNumber (_magCfg >> _x >> QGVAR(airFriction));
if (_magAirFriction <= 0) then {
if (_advCorrection) then {
_airFriction = [DEFAULT_AIR_FRICTION, _magAirFriction] select (isNumber (_magCfg >> _x >> QGVAR(airFriction)));
};
} else {
// positive value, use ammo's airFriction (regardless of setting)
private _ammo = getText (_magCfg >> _x >> "ammo");
_airFriction = getNumber (configFile >> "CfgAmmo" >> _ammo >> "airFriction");
};
_magParamsArray pushBackUnique _airFriction;
[getText (_magCfg >> _x >> "displayNameShort"), getText (_magCfg >> _x >> "displayName"), _initSpeed, _airFriction]

View File

@ -1505,7 +1505,7 @@
<Portuguese>Carregador de 10 cartuchos 9.3 mm traçantes IR-DIM</Portuguese>
<Hungarian>9,3 mm 10-lövedékes infravörös nyomkövető tár</Hungarian>
<Japanese>9.3mm 10Rnd IR-DIM トレーサー マガジン</Japanese>
<Korean>10발들이 9.3mm IR-DIM 예광탄 탄창</Korean>
<Korean>10발 들이 9.3mm IR-DIM 예광탄 탄창</Korean>
<Chinese>9.3毫米 10發 低視度紅外線曳光彈 彈匣</Chinese>
<Chinesesimp>9.3 mm 10发 弹匣(红外曳光)</Chinesesimp>
<Turkish>9.3 mm 10Rnd Tracer IR-DIM Mag</Turkish>
@ -1608,7 +1608,7 @@
<Portuguese>Cinto de munição traçante 9.3 mm IR-DIM com 150 cartuchos</Portuguese>
<Hungarian>9,3 mm 150-lövedékes infravörös nyomkövető heveder</Hungarian>
<Japanese>9.3mm 150Rnd IR-DIM トレーサー ベルト</Japanese>
<Korean>150발들이 9.3mm IR-DIM 예광탄 벨트</Korean>
<Korean>150발 들이 9.3mm IR-DIM 예광탄 벨트</Korean>
<Chinese>9.3毫米 150發 低視度紅外線曳光彈 彈鏈</Chinese>
<Chinesesimp>9.3 mm 150发 弹链(红外曳光)</Chinesesimp>
<Turkish>9.3 mm 150Rnd Tracer IR-DIM Belt</Turkish>
@ -1659,7 +1659,7 @@
<Portuguese>Cinto de munição 9.3 mm AP com 150 cartuchos</Portuguese>
<Hungarian>9,3 mm 150-lövedékes páncéltörő heveder</Hungarian>
<Japanese>9.3mm 150Rnd 徹甲弾 ベルト</Japanese>
<Korean>150발들이 9.3mm 철갑탄 벨트</Korean>
<Korean>150발 들이 9.3mm 철갑탄 벨트</Korean>
<Chinese>9.3毫米 150發 穿甲彈 彈鏈</Chinese>
<Chinesesimp>9.3 mm 150发 弹链(穿甲)</Chinesesimp>
<Turkish>9.3 mm 150Rnd AP Belt</Turkish>
@ -1710,7 +1710,7 @@
<Portuguese>Carregador de 16 cartuchos 9x19 mm</Portuguese>
<Hungarian>9x19 mm 16-lövedékes tár</Hungarian>
<Japanese>9x19 mm 16Rnd マガジン</Japanese>
<Korean>17발들이 9x19mm 탄창</Korean>
<Korean>16발 들이 9x19mm 탄창</Korean>
<Chinese>9x19毫米 16發 彈匣</Chinese>
<Chinesesimp>9x19 mm 16发 弹匣</Chinesesimp>
<Turkish>9x19 mm 16Rnd Mag</Turkish>
@ -2016,7 +2016,7 @@
<Portuguese>Carregador 5.56 mm com 30 cartuchos (Mk318)</Portuguese>
<Hungarian>5,56 mm 30-lövedékes tár (Mk318)</Hungarian>
<Japanese>5.56mm 30Rnd マガジン (Mk318)</Japanese>
<Korean>30발들이 5.56mm 탄창 (Mk.318)</Korean>
<Korean>30발 들이 5.56mm 탄창 (Mk.318)</Korean>
<Chinese>5.56毫米 30發 彈匣 (Mk318 特戰專用彈)</Chinese>
<Chinesesimp>5.56 mm 30发 弹匣Mk318</Chinesesimp>
<Turkish>5.56 mm 30Rnd Mag (Mk318)</Turkish>
@ -2322,7 +2322,7 @@
<Portuguese>Carregador 7.62 mm com 10 cartuchos (Mk319 Mod 0)</Portuguese>
<Hungarian>7,62 mm 10-lövedékes tár (Mk319 Mod 0)</Hungarian>
<Japanese>7.62mm 10Rnd マガジン (Mk319 Mod 0)</Japanese>
<Korean>10발들이 7.62mm 탄창 (Mk.319 Mod 0)</Korean>
<Korean>10발 들이 7.62mm 탄창 (Mk.319 Mod 0)</Korean>
<Chinese>7.62毫米 10發 彈匣 (Mk319 Mod 0 特戰專用彈)</Chinese>
<Chinesesimp>7.62 mm 10发 弹匣Mk319 Mod 0</Chinesesimp>
<Turkish>7.62 mm 10Rnd Mag (Mk319 Mod 0)</Turkish>
@ -3344,7 +3344,7 @@
<Portuguese>Carregador 12.7x99 mm (AMAX) com 5 cartuchos </Portuguese>
<Hungarian>12,7x99 mm 5-lövedékes tár (AMAX)</Hungarian>
<Japanese>12.7x99mm 5Rnd マガジン (AMAX)</Japanese>
<Korean>5발들이 12.7x99mm 탄창 (AMAX)</Korean>
<Korean>5발 들이 12.7x99mm 탄창 (AMAX)</Korean>
<Chinese>12.7x99毫米 5發 彈匣 (AMAX 比賽專用彈)</Chinese>
<Chinesesimp>12.7x99 mm 5发 弹匣AMAX</Chinesesimp>
<Turkish>12.7x99 mm 5Rnd Şarjör (AMAX)</Turkish>
@ -3378,7 +3378,7 @@
<Portuguese>Carregador 12.7x99 mm (AMAX) com 10 cartuchos </Portuguese>
<Hungarian>12,7x99 mm 10-lövedékes tár (AMAX)</Hungarian>
<Japanese>12.7x99mm 10Rnd マガジン (AMAX)</Japanese>
<Korean>10발들이 12.7x99mm 탄창 (AMAX)</Korean>
<Korean>10발 들이 12.7x99mm 탄창 (AMAX)</Korean>
<Chinese>12.7x99毫米 10發 彈匣 (AMAX 比賽專用彈)</Chinese>
<Chinesesimp>12.7x99 mm 10发 弹匣AMAX</Chinesesimp>
<Turkish>12.7x99 mm 10Rnd Şarjör (AMAX)</Turkish>

View File

@ -21,7 +21,6 @@ params ["_unit", "_target"];
(_target getVariable [QGVAR(isHandcuffed), false]) &&
{isNull (attachedTo _target)} &&
{alive _target} &&
{!(_target getVariable ["ACE_isUnconscious", false])} &&
{_target call EFUNC(common,isAwake)} &&
{(vehicle _unit) == _unit} &&
{(vehicle _target) == _target}

View File

@ -20,7 +20,7 @@
params ["_unit", "_target", "_vehicle"];
// Don't show "Load Captive" if unit is unconscious (already has "Load Patient")
if (_target getVariable ["ACE_isUnconscious", false]) exitWith {false};
if !(_target call EFUNC(common,isAwake)) exitWith {false};
if ((isNull _target) && {_unit getVariable [QGVAR(isEscorting), false]}) then {
//Looking at a vehicle while escorting, get target from attached objects:

View File

@ -39,7 +39,7 @@ if (_state) then {
_args params ["_unit", "_target", "_actionID"];
if (_unit getVariable [QGVAR(isEscorting), false]) then {
if (!alive _target || {!alive _unit} || {!canStand _target} || {!canStand _unit} || {_target getVariable ["ACE_isUnconscious", false]} || {_unit getVariable ["ACE_isUnconscious", false]} || {!isNull (attachedTo _unit)}) then {
if (!canStand _target || {!canStand _unit} || {!(_target call EFUNC(common,isAwake))} || {!(_unit call EFUNC(common,isAwake))} || {!isNull (attachedTo _unit)}) then {
_unit setVariable [QGVAR(isEscorting), false, true];
};
};

View File

@ -19,7 +19,7 @@
params ["_unit", "_newAnimation"];
TRACE_2("AnimChanged",_unit,_newAnimation);
if (_unit == (vehicle _unit)) then {
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {!(_unit getVariable ["ACE_isUnconscious", false])}) then {
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {_unit call EFUNC(common,isAwake)}) then {
TRACE_1("Handcuff animation interrupted",_newAnimation);
[_unit, "ACE_AmovPercMstpScapWnonDnon", 1] call EFUNC(common,doAnimation);
};

View File

@ -19,7 +19,7 @@
params ["_unit", "_newAnimation"];
TRACE_2("AnimChanged",_unit,_newAnimation);
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {!(_unit getVariable ["ACE_isUnconscious", false])}) then {
if ((_newAnimation != "ACE_AmovPercMstpSsurWnonDnon") && {_unit call EFUNC(common,isAwake)}) then {
TRACE_1("Surrender animation interrupted",_newAnimation);
[_unit, "ACE_AmovPercMstpSsurWnonDnon", 1] call EFUNC(common,doAnimation);
};

View File

@ -91,7 +91,7 @@ if (_state) then {
_unit removeEventHandler ["AnimChanged", _animChangedEHID];
_unit setVariable [QGVAR(handcuffAnimEHID), -1];
if (((vehicle _unit) == _unit) && {!(_unit getVariable ["ACE_isUnconscious", false])}) then {
if (((vehicle _unit) == _unit) && {_unit call EFUNC(common,isAwake)}) then {
//Break out of hands up animation loop
[_unit, "ACE_AmovPercMstpScapWnonDnon_AmovPercMstpSnonWnonDnon", 2] call EFUNC(common,doAnimation);
};

View File

@ -86,8 +86,7 @@ if (_state) then {
};
};
if (!alive _unit) exitWith {};
if (_unit getVariable ["ACE_isUnconscious", false]) exitWith {}; //don't touch animations if unconscious
if !(_unit call EFUNC(common,isAwake)) exitWith {}; //don't touch animations if unconscious
//if we are in "hands up" animationState, crack it now
if (((vehicle _unit) == _unit) && {(animationState _unit) == "ACE_AmovPercMstpSsurWnonDnon"}) then {
@ -99,7 +98,7 @@ if (_state) then {
params ["_args", "_pfID"];
_args params ["_unit", "_maxTime"];
//If waited long enough or they re-surrendered or they are unconscious, exit loop
if ((CBA_missionTime > _maxTime) || {_unit getVariable [QGVAR(isSurrendering), false]} || {_unit getVariable ["ACE_isUnconscious", false]}) exitWith {
if ((CBA_missionTime > _maxTime) || {_unit getVariable [QGVAR(isSurrendering), false]} || {!(_unit call EFUNC(common,isAwake))}) exitWith {
[_pfID] call CBA_fnc_removePerFrameHandler;
};
//Only break animation if they are actualy the "hands up" animation (because we are using switchmove there won't be an transition)

View File

@ -41,6 +41,8 @@ if (_item isEqualType "") then {
TRACE_1("loaded",_loaded);
// Invoke listenable event
["ace_cargoAdded", [_item, _vehicle, _loaded]] call CBA_fnc_globalEvent;
if (_loaded > 0) then {
["ace_cargoAdded", [_item, _vehicle, _loaded]] call CBA_fnc_globalEvent;
};
_loaded // return

View File

@ -506,7 +506,7 @@
<German>Ladezeitmultiplikator</German>
<Japanese>積載の所要時間係数</Japanese>
<Polish>Współczynnik czasu załadowania</Polish>
<Italian>Coefficente Tempo Caricamento</Italian>
<Italian>Coefficiente Tempo Caricamento</Italian>
<Russian>Коэф. времени погрузки</Russian>
<Portuguese>Fator de tempo para carregar</Portuguese>
<French>Coefficient du temps de chargement</French>

View File

@ -1,7 +1,12 @@
#include "script_component.hpp"
if (!hasInterface || !GVAR(enabled)) exitWith {};
if (!hasInterface) exitWith {};
GVAR(cachedCasings) = createHashMap;
GVAR(casings) = [];
["CAManBase", "FiredMan", LINKFUNC(createCasing)] call CBA_fnc_addClassEventHandler;
["CBA_settingsInitialized", {
if (!GVAR(enabled)) exitWith {};
GVAR(cachedCasings) = createHashMap;
GVAR(casings) = [];
["CAManBase", "FiredMan", LINKFUNC(createCasing)] call CBA_fnc_addClassEventHandler;
}] call CBA_fnc_addEventHandler;

View File

@ -30,6 +30,7 @@ PREP(changeProjectileDirection);
PREP(checkFiles);
PREP(checkFiles_diagnoseACE);
PREP(checkPBOs);
PREP(checkVersionNumber);
PREP(claim);
PREP(claimSafeServer);
PREP(codeToString);

View File

@ -2,12 +2,14 @@
/*
* Author: PabstMirror
* Adds event handler just to ACE_player
* Can be removed after cba 3.18 is released for CBA_fnc_addBISPlayerEventHandler
* This never was public in a release
*
* Arguments:
* 0: Key <STRING>
* 1: Event Type <STRING>
* 2: Event Code <CODE>
* 3: Ignore Virtual Units (spectators, virtual zeus, uav RC) <BOOL> (default: false)
* 3: Ignore Virtual Units (spectators, virtual zeus, uav RC) <BOOL> (default: true)
*
* Return Value:
* None
@ -15,9 +17,9 @@
* Example:
* ["example", "FiredNear", {systemChat str _this}] call ace_common_fnc_addPlayerEH
*
* Public: Yes
* Public: No
*/
params [["_key", "", [""]], ["_type", "", [""]], ["_code", {}, [{}]], ["_ignoreVirtual", false, [false]]];
params [["_key", "", [""]], ["_type", "", [""]], ["_code", {}, [{}]], ["_ignoreVirtual", true, [true]]];
TRACE_3("addPlayerEH",_key,_type,_ignoreVirtual);
if (isNil QGVAR(playerEventsHash)) then { // first-run init

View File

@ -15,15 +15,20 @@
* Public: No
*/
///////////////
// check addons
///////////////
private _mainCfg = configFile >> "CfgPatches" >> "ace_main";
private _mainVersion = getText (_mainCfg >> "versionStr");
private _mainSource = configSourceMod _mainCfg;
// Don't execute in scheduled environment
if (canSuspend) exitWith {
[FUNC(checkFiles), nil] call CBA_fnc_directCall;
};
//CBA Versioning check - close main display if using incompatible version
private _cbaVersionAr = getArray (configFile >> "CfgPatches" >> "cba_main" >> "versionAr");
///////////////
// Check addons
///////////////
private _cfgPatches = configFile >> "CfgPatches";
private _mainVersion = getText (_cfgPatches >> "ace_main" >> "versionStr");
private _mainSource = configSourceMod (_cfgPatches >> "ace_main");
// CBA Versioning check - close main display if using incompatible version
private _cbaVersionAr = getArray (_cfgPatches >> "cba_main" >> "versionAr");
private _cbaRequiredAr = getArray (configFile >> "CfgSettings" >> "CBA" >> "Versioning" >> "ACE" >> "dependencies" >> "CBA") select 1;
private _cbaVersionStr = _cbaVersionAr joinString ".";
@ -31,53 +36,62 @@ private _cbaRequiredStr = _cbaRequiredAr joinString ".";
INFO_3("ACE is version %1 - CBA is version %2 (min required %3)",_mainVersion,_cbaVersionStr,_cbaRequiredStr);
if ([_cbaRequiredAr, _cbaVersionAr] call cba_versioning_fnc_version_compare) then {
if ([_cbaRequiredAr, _cbaVersionAr] call CBA_versioning_fnc_version_compare) then {
private _errorMsg = format ["CBA version %1 is outdated (required %2)", _cbaVersionStr, _cbaRequiredStr];
ERROR(_errorMsg);
if (hasInterface) then {
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
};
};
//private _addons = activatedAddons; // broken with High-Command module, see #2134
private _addons = (cba_common_addons select {(_x select [0,4]) == "ace_"}) apply {toLowerANSI _x};
//private _addons = activatedAddons; // Broken with High-Command module, see #2134
private _addons = (CBA_common_addons select {(_x select [0, 4]) == "ace_"}) apply {toLowerANSI _x};
private _oldAddons = [];
private _oldSources = [];
private _oldCompats = [];
{
private _addonCfg = configFile >> "CfgPatches" >> _x;
private _addonVersion = getText (_addonCfg >> "versionStr");
if (_addonVersion != _mainVersion) then {
private _addonSource = configSourceMod _addonCfg;
_oldSources pushBackUnique _addonSource;
// Check ACE install
call FUNC(checkFiles_diagnoseACE);
// Don't block game if it's just an old compat pbo
if ((_x select [0, 10]) != "ace_compat") then {
if (hasInterface) then {
_oldAddons pushBack _x;
};
_oldAddons pushBack _x;
} else {
_oldCompats pushBack [_x, _addonVersion]; // Don't block game if it's just an old compat pbo
_oldCompats pushBack [_x, _addonVersion];
};
};
} forEach _addons;
if (_oldAddons isNotEqualTo []) then {
_oldAddons = _oldAddons apply { format ["%1.pbo", _x] };
private _errorMsg = "";
if (count _oldAddons > 3) then {
_errorMsg = format ["The following files are outdated: %1, and %2 more.<br/>ACE Main version is %3 from %4.<br/>Loaded mods with outdated ACE files: %5", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) -3, _mainVersion, _mainSource, (_oldSources joinString ", ")];
_oldAddons = _oldAddons apply {format ["%1.pbo", _x]};
private _errorMsg = if (count _oldAddons > 3) then {
format ["The following files are outdated: %1, and %2 more.<br/>ACE Main version is %3 from %4.<br/>Loaded mods with outdated ACE files: %5", (_oldAddons select [0, 3]) joinString ", ", (count _oldAddons) - 3, _mainVersion, _mainSource, _oldSources joinString ", "];
} else {
_errorMsg = format ["The following files are outdated: %1.<br/>ACE Main version is %2 from %3.<br/>Loaded mods with outdated ACE files: %4", (_oldAddons) joinString ", ", _mainVersion, _mainSource, (_oldSources) joinString ", "];
format ["The following files are outdated: %1.<br/>ACE Main version is %2 from %3.<br/>Loaded mods with outdated ACE files: %4", _oldAddons joinString ", ", _mainVersion, _mainSource, _oldSources joinString ", "];
};
if (hasInterface) then {
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
};
ERROR(_errorMsg);
};
if (_oldCompats isNotEqualTo []) then {
_oldCompats = _oldCompats apply {format ["%1 (%2)", _x select 0, _x select 1]};
[{
// Lasts for ~10 seconds
ERROR_WITH_TITLE_3("The following ACE compatiblity PBOs are outdated","%1. ACE Main version is %2 from %3.",_this select 0,_this select 1,_this select 2);
@ -85,9 +99,10 @@ if (_oldCompats isNotEqualTo []) then {
};
///////////////
// check extensions
// Check extensions
///////////////
private _platform = toLowerANSI (productVersion select 6);
if (!isServer && {_platform in ["linux", "osx"]}) then {
// Linux and OSX client ports do not support extensions at all
INFO("Operating system does not support extensions");
@ -101,8 +116,10 @@ if (!isServer && {_platform in ["linux", "osx"]}) then {
if ((_isWindows || _isLinux) && {_isClient || _isServer}) then {
private _versionEx = _extension callExtension "version";
if (_versionEx == "") then {
private _extensionFile = _extension;
if (productVersion select 7 == "x64") then {
_extensionFile = format ["%1_x64", _extensionFile];
};
@ -114,7 +131,7 @@ if (!isServer && {_platform in ["linux", "osx"]}) then {
ERROR(_errorMsg);
if (hasInterface) then {
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
};
} else {
// Print the current extension version
@ -123,54 +140,66 @@ if (!isServer && {_platform in ["linux", "osx"]}) then {
};
} forEach ("true" configClasses (configFile >> "ACE_Extensions"));
};
if (isArray (configFile >> "ACE_Extensions" >> "extensions")) then {
WARNING("extensions[] array no longer supported");
};
///////////////
// check server version/addons
// Check server version/addons
///////////////
if (isMultiplayer) then {
// don't check optional addons
_addons = _addons select {getNumber (configFile >> "CfgPatches" >> _x >> "ACE_isOptional") != 1};
// Don't check optional addons
_addons = _addons select {getNumber (_cfgPatches >> _x >> "ACE_isOptional") != 1};
if (isServer) then {
// send servers version of ACE to all clients
GVAR(ServerVersion) = _mainVersion;
GVAR(ServerAddons) = _addons;
publicVariable QGVAR(ServerVersion);
publicVariable QGVAR(ServerAddons);
// Send server's version of ACE to all clients
GVAR(serverVersion) = _mainVersion;
GVAR(serverAddons) = _addons;
GVAR(serverSource) = _mainSource;
publicVariable QGVAR(serverVersion);
publicVariable QGVAR(serverAddons);
publicVariable QGVAR(serverSource);
} else {
// clients have to wait for the variables
[{
if (isNil QGVAR(ServerVersion) || isNil QGVAR(ServerAddons)) exitWith {};
GVAR(clientVersion) = _version;
GVAR(clientAddons) = _addons;
(_this select 0) params ["_mainVersion", "_addons"];
if (_mainVersion != GVAR(ServerVersion)) then {
private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2.", GVAR(ServerVersion), _mainVersion];
private _fnc_check = {
if (GVAR(clientVersion) != GVAR(serverVersion)) then {
private _errorMsg = format ["Client/Server Version Mismatch. Server: %1, Client: %2. Server modDir: %3", GVAR(serverVersion), GVAR(clientVersion), GVAR(serverSource)];
// Check ACE install
call FUNC(checkFiles_diagnoseACE);
ERROR(_errorMsg);
if (hasInterface) then {
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
};
};
_addons = _addons - GVAR(ServerAddons);
private _addons = GVAR(clientAddons) - GVAR(serverAddons);
if (_addons isNotEqualTo []) then {
private _errorMsg = format ["Client/Server Addon Mismatch. Client has extra addons: %1.",_addons];
private _errorMsg = format ["Client/Server Addon Mismatch. Client has additional addons: %1. Server modDir: %2", _addons, GVAR(serverSource)];
// Check ACE install
call FUNC(checkFiles_diagnoseACE);
ERROR(_errorMsg);
if (hasInterface) then {
["[ACE] ERROR", _errorMsg, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
["[ACE] ERROR", _errorMsg] call FUNC(errorMessage);
};
};
};
[_this select 1] call CBA_fnc_removePerFrameHandler;
}, 1, [_mainVersion,_addons]] call CBA_fnc_addPerFrameHandler;
// Clients have to wait for the variables
if (isNil QGVAR(serverVersion) || isNil QGVAR(serverAddons)) then {
GVAR(serverVersion) addPublicVariableEventHandler _fnc_check;
} else {
call _fnc_check;
};
};
};

View File

@ -1,13 +1,13 @@
#include "..\script_component.hpp"
/*
* Author: PabstMirror
* Diagnose ACE install problems, this will only be called if there is a known problem
* Diagnoses ACE install problems, this will only be called if there is a known problem.
*
* Arguments:
* None
*
* Return Value:
* None
* ACE addons' WS IDs <HASHMAP>
*
* Example:
* [] call ace_common_fnc_checkFiles_diagnoseACE
@ -16,43 +16,59 @@
*/
// Only run once
if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith {};
if (missionNameSpace getVariable [QGVAR(checkFiles_diagnoseACE), false]) exitWith {
createHashMap // return
};
GVAR(checkFiles_diagnoseACE) = true;
private _addons = cba_common_addons select {(_x select [0,4]) == "ace_"};
private _addons = CBA_common_addons select {(_x select [0, 4]) == "ace_"};
private _cfgPatches = configFile >> "CfgPatches";
private _allMods = createHashMap;
private _getLoadedModsInfo = getLoadedModsInfo;
// Check ACE_ADDONs are in expected mod DIR
// Check if ACE_ADDONs are in expected mod DIR
{
private _cfg = (_cfgPatches >> _x);
private _cfg = _cfgPatches >> _x;
private _actualModDir = configSourceMod _cfg;
private _expectedModDir = getText (_cfg >> "ACE_expectedModDir");
if (_expectedModDir == "") then { _expectedModDir = "@ace" };
if (_expectedModDir == "") then {
_expectedModDir = "@ace";
};
private _expectedSteamID = getText (_cfg >> "ACE_expectedSteamID");
if (_expectedSteamID == "") then { _expectedSteamID = "463939057" };
if (_expectedSteamID == "") then {
_expectedSteamID = "463939057"
};
(_allMods getOrDefault [_actualModDir, [], true]) pushBackUnique _expectedSteamID;
if (_actualModDir != _expectedModDir) then {
private _errorMsg = format ["%1 loading from unexpected modDir [%2]",_x,_actualModDir];
private _errorMsg = format ["%1 loading from unexpected modDir [%2]", _x, _actualModDir];
systemChat _errorMsg;
WARNING_1("%1",_errorMsg);
};
} forEach _addons;
// Check all ACE ModDirs have expected steam WS ID
// Check if all ACE ModDirs have expected steam WS ID
{
private _modDir = _x;
if ((count _y) != 1) then { ERROR_2("Unexpected multiple steamIDs %1 - %2",_modDir,_y) };
private _expectedSteamID = _y # 0;
private _index = getLoadedModsInfo findIf {_x#1 == _modDir};
(getLoadedModsInfo param [_index, []]) params [["_modName", "$Error$"], "", "", "", "", "", "", ["_actualID", ""]];
if (count _y != 1) then {
ERROR_2("Unexpected multiple steamIDs %1 - %2",_modDir,_y);
};
private _expectedSteamID = _y select 0;
private _index = _getLoadedModsInfo findIf {_x select 1 == _modDir};
(_getLoadedModsInfo param [_index, []]) params [["_modName", "$Error$"], "", "", "", "", "", "", ["_actualID", ""]];
if (_actualID != _expectedSteamID) then {
private _errorMsg = format ["%1 [%2] unexpected workshopID [%3]",_modDir,_modName,_actualID];
private _errorMsg = format ["%1 [%2] unexpected workshopID [%3]", _modDir, _modName, _actualID];
systemChat _errorMsg;
WARNING_1("%1",_errorMsg);
};
} forEach _allMods;
_allMods
_allMods // return

View File

@ -1,6 +1,6 @@
#include "..\script_component.hpp"
/*
* Author: commy2
* Author: commy2, johnb43
* Used to execute the checkPBOs module without placing the module. Don't use this together with the module.
* Checks PBO versions and compares to the one running on server.
*
@ -9,8 +9,8 @@
* 0 = Warn once
* 1 = Warn permanently
* 2 = Kick
* 1: Check all PBOs? (default: false) <BOOL>
* 2: Whitelist (default: "") <STRING>
* 1: Check all PBOs? <BOOL> (default: false)
* 2: Whitelist <STRING> (default: "")
*
* Return Value:
* None
@ -24,7 +24,7 @@
params ["_mode", ["_checkAll", false], ["_whitelist", "", [""]]];
TRACE_3("params",_mode,_checkAll,_whitelist);
//lowercase and convert whiteList String into array of strings:
// Lowercase and convert whiteList string into array of strings
_whitelist = toLowerANSI _whitelist;
_whitelist = _whitelist splitString "[,""']";
TRACE_1("Array",_whitelist);
@ -32,75 +32,67 @@ TRACE_1("Array",_whitelist);
ACE_Version_CheckAll = _checkAll;
ACE_Version_Whitelist = _whitelist;
if (!_checkAll) exitWith {}; //ACE is checked by FUNC(checkFiles)
// ACE is checked by FUNC(checkFiles)
if (!_checkAll) exitWith {};
if (!isServer) then {
[{
if (isNil "ACE_Version_ClientErrors") exitWith {};
["ace_versioning_clientCheckDone", {
// Don't let this event get triggered again
[_thisType, _thisId] call CBA_fnc_removeEventHandler;
ACE_Version_ClientErrors params ["_missingAddon", "_missingAddonServer", "_oldVersionClient", "_oldVersionServer"];
params ["_clientErrors"];
_clientErrors params ["_missingAddonClient", "_additionalAddonClient", "_olderVersionClient", "_newerVersionClient"];
_thisArgs params ["_mode"];
(_this select 0) params ["_mode", "_checkAll", "_whitelist"];
// Display error message(s)
if (_missingAddonClient || {_additionalAddonClient} || {_olderVersionClient} || {_newerVersionClient}) then {
private _errorMsg = "[ACE] Version mismatch:<br/><br/>";
private _error = [];
// Display error message.
if (_missingAddon || {_missingAddonServer} || {_oldVersionClient} || {_oldVersionServer}) then {
private _text = "[ACE] Version mismatch:<br/><br/>";
private _error = format ["ACE version mismatch: %1: ", profileName];
if (_missingAddon) then {
_text = _text + "Detected missing addon on client<br/>";
_error = _error + "Missing file(s); ";
};
if (_missingAddonServer) then {
_text = _text + "Detected missing addon on server<br/>";
_error = _error + "Additional file(s); ";
};
if (_oldVersionClient) then {
_text = _text + "Detected old client version<br/>";
_error = _error + "Older version; ";
};
if (_oldVersionServer) then {
_text = _text + "Detected old server version<br/>";
_error = _error + "Newer version; ";
if (_missingAddonClient) then {
_errorMsg = _errorMsg + "Detected missing addon on client<br/>";
_error pushBack "Missing file(s)";
};
//[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
if (_additionalAddonClient) then {
_errorMsg = _errorMsg + "Detected additional addon on client<br/>";
_error pushBack "Additional file(s)";
};
ERROR(_error);
if (_olderVersionClient) then {
_errorMsg = _errorMsg + "Detected older client version<br/>";
_error pushBack "Older version";
};
if (_newerVersionClient) then {
_errorMsg = _errorMsg + "Detected newer client version<br/>";
_error pushBack "Newer version";
};
ERROR_2("[ACE] Version mismatch: %1: %2",profileName,_error joinString ", ");
_errorMsg = parseText format ["<t align='center'>%1</t>", _errorMsg];
// Warn
if (_mode < 2) then {
_text = composeText [lineBreak, parseText format ["<t align='center'>%1</t>", _text]];
private _rscLayer = "ACE_RscErrorHint" call BIS_fnc_rscLayer;
_rscLayer cutRsc ["ACE_RscErrorHint", "PLAIN", 0, true];
disableSerialization;
private _ctrlHint = uiNamespace getVariable "ACE_ctrlErrorHint";
_ctrlHint ctrlSetStructuredText _text;
(uiNamespace getVariable "ACE_ctrlErrorHint") ctrlSetStructuredText composeText [lineBreak, _errorMsg];
if (_mode == 0) then {
[{
params ["_rscLayer"];
TRACE_2("Hiding Error message after 10 seconds",time,_rscLayer);
_rscLayer cutFadeOut 0.2;
}, [_rscLayer], 10] call CBA_fnc_waitAndExecute;
TRACE_2("Hiding Error message after 10 seconds",time,_this);
_this cutFadeOut 0.2;
}, _rscLayer, 10] call CBA_fnc_waitAndExecute;
};
};
if (_mode == 2) then {
[{alive player}, { // To be able to show list if using checkAll
params ["_text"];
TRACE_2("Player is alive, showing msg and exiting",time,_text);
_text = composeText [parseText format ["<t align='center'>%1</t>", _text]];
["[ACE] ERROR", _text, {findDisplay 46 closeDisplay 0}] call FUNC(errorMessage);
}, [_text]] call CBA_fnc_waitUntilAndExecute;
} else {
// Kick
["[ACE] ERROR", composeText [_errorMsg]] call FUNC(errorMessage);
};
};
[_this select 1] call CBA_fnc_removePerFrameHandler;
}, 1, [_mode, _checkAll, _whitelist]] call CBA_fnc_addPerFrameHandler;
}, [_mode]] call CBA_fnc_addEventHandlerArgs;
};
if (_checkAll) then {
0 spawn COMPILE_FILE(scripts\checkVersionNumber); // @todo
};
// Check file version numbers
[_whitelist] call FUNC(checkVersionNumber);

View File

@ -0,0 +1,161 @@
#include "..\script_component.hpp"
/*
* Author: commy2, johnb43
* Compares version numbers from loaded addons.
*
* Arguments:
* 0: Lowercase addon whitelist <ARRAY> (default: missionNamespace getVariable ["ACE_Version_Whitelist", []])
*
* Return Value:
* None
*
* Example:
* call ace_common_fnc_checkVersionNumber
*
* Public: No
*/
// Don't execute in scheduled environment
if (canSuspend) exitWith {
[FUNC(checkVersionNumber), _this] call CBA_fnc_directCall;
};
params [["_whitelist", missionNamespace getVariable ["ACE_Version_Whitelist", []]]];
private _files = CBA_common_addons select {
(_x select [0, 3] != "a3_") &&
{_x select [0, 4] != "ace_"} &&
{!((toLowerANSI _x) in _whitelist)}
};
private _cfgPatches = configFile >> "CfgPatches";
private _versions = [];
{
(getText (_cfgPatches >> _x >> "version") splitString ".") params [["_major", "0"], ["_minor", "0"]];
private _version = parseNumber _major + parseNumber _minor / 100;
_versions pushBack _version;
} forEach _files;
if (isServer) exitWith {
ACE_Version_ServerVersions = [_files, _versions];
publicVariable "ACE_Version_ServerVersions";
// Raise event when done
["ace_versioning_serverCheckDone", [+ACE_Version_ServerVersions]] call CBA_fnc_localEvent;
};
// Begin client version check
ACE_Version_ClientVersions = [_files, _versions];
private _fnc_check = {
ACE_Version_ClientVersions params [["_files", []], ["_versions", []]];
ACE_Version_ServerVersions params [["_serverFiles", []], ["_serverVersions", []]];
// Compare client and server files and versions
private _client = profileName;
private _missingAddonsClient = [];
private _olderVersionsClient = [];
private _newerVersionsClient = [];
{
private _serverVersion = _serverVersions select _forEachIndex;
private _index = _files find _x;
if (_index == -1) then {
if (_x != "ace_server") then {
_missingAddonsClient pushBack _x;
};
} else {
private _clientVersion = _versions select _index;
if (_clientVersion < _serverVersion) then {
_olderVersionsClient pushBack [_x, _clientVersion, _serverVersion];
};
if (_clientVersion > _serverVersion) then {
_newerVersionsClient pushBack [_x, _clientVersion, _serverVersion];
};
};
} forEach _serverFiles;
// Find client files which the server doesn't have
private _additionalAddonsClient = _files select {!(_x in _serverFiles)};
// Check for client missing addons, server missing addons, client outdated addons and server outdated addons
private _clientErrors = [];
#define DISPLAY_NUMBER_ADDONS (10 + 1) // +1 to account for header
{
_x params ["_items", "_string"];
// Check if something is either missing or outdated
private _isMissingItems = _items isNotEqualTo [];
if (_isMissingItems) then {
// Generate error message
private _errorLog = +_items;
private _header = format ["[ACE] %1: ERROR %2 addon(s): ", _client, _string];
// Don't display all missing items, as they are logged
private _errorMsg = _header + ((_errorLog select [0, DISPLAY_NUMBER_ADDONS]) joinString ", ");
_errorLog = _header + (_errorLog joinString ", ");
private _count = count _items;
if (_count > DISPLAY_NUMBER_ADDONS) then {
_errorMsg = _errorMsg + format [", and %1 more.", _count - DISPLAY_NUMBER_ADDONS];
};
// Wait until in briefing screen
[{
getClientStateNumber >= 9 // "BRIEFING SHOWN"
}, {
params ["_errorLog", "_errorMsg"];
// Log and display error messages
diag_log text _errorLog;
[QGVAR(serverLog), _errorLog] call CBA_fnc_serverEvent;
[QGVAR(systemChatGlobal), _errorMsg] call CBA_fnc_globalEvent;
// Wait until after map screen
[{
!isNull (call BIS_fnc_displayMission)
}, {
params ["_errorMsg", "_timeOut"];
// If the briefing screen was shown for less than 5 seconds, display the error message again, but locally
if (_timeOut < CBA_missionTime) exitWith {};
// Make sure systemChat is ready by waiting a bit
[{
systemChat _this;
}, _errorMsg, 1] call CBA_fnc_waitAndExecute;
}, [_errorMsg, CBA_missionTime + 5]] call CBA_fnc_waitUntilAndExecute;
}, [_errorLog, _errorMsg]] call CBA_fnc_waitUntilAndExecute;
};
_clientErrors pushBack _isMissingItems;
} forEach [
[_missingAddonsClient, "client missing"],
[_additionalAddonsClient, "client additional"],
[_olderVersionsClient, "older client"],
[_newerVersionsClient, "newer client"]
];
TRACE_4("",_missingAddonsClient,_additionalAddonsClient,_olderVersionsClient,_newerVersionsClient);
ACE_Version_ClientErrors = _clientErrors;
// Raise event when done
["ace_versioning_clientCheckDone", [+ACE_Version_ClientErrors]] call CBA_fnc_localEvent;
};
// Wait for server to send the servers files and version numbers
if (isNil "ACE_Version_ServerVersions") then {
ACE_Version_ServerVersions addPublicVariableEventHandler _fnc_check;
} else {
call _fnc_check;
};

View File

@ -29,7 +29,7 @@ if !([_unit] call EFUNC(common,isPlayer)) then {
_unit disableConversation true;
} else {
//Sanity check to make sure we don't enable unconsious AI
if (_unit getVariable ["ace_isunconscious", false] && alive _unit) exitWith {
if (_unit getVariable ["ACE_isUnconscious", false] && alive _unit) exitWith {
ERROR("Enabling AI for unconsious unit");
};

View File

@ -1,147 +1,141 @@
#include "..\script_component.hpp"
#include "\a3\ui_f\hpp\defineResincl.inc"
#include "\a3\ui_f\hpp\defineDIKCodes.inc"
/*
* Author: commy2, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI)
* Stops simulation and opens a textbox with error message.
* Author: commy2, johnb43, based on BIS_fnc_errorMsg and BIS_fnc_guiMessage by Karel Moricky (BI)
* Opens a textbox with an error message, used for PBO checking.
*
* Arguments:
* ?
* 0: Header <STRING>
* 1: Text <STRING|TEXT>
*
* Return Value:
* None
*
* Example:
* call ace_common_fnc_errorMessage
* ["[ACE] ERROR", "Test"] call ace_common_fnc_errorMessage
*
* Public: No
*/
disableSerialization;
// Force stop any loading screens
endLoadingScreen;
// no message without player possible
// No message without interface possible
if (!hasInterface) exitWith {};
// wait for display
if (isNull (call BIS_fnc_displayMission)) exitWith {
[{
if (isNull (call BIS_fnc_displayMission)) exitWith {};
[{
!isNull (call BIS_fnc_displayMission)
}, {
params ["_textHeader", "_textMessage"];
(_this select 0) call FUNC(errorMessage);
[_this select 1] call CBA_fnc_removePerFrameHandler;
disableSerialization;
}, 1, _this] call CBA_fnc_addPerFrameHandler;
};
// Use curator display if present
private _curatorDisplay = findDisplay 312;
params ["_textHeader", "_textMessage", ["_onOK", {}], ["_onCancel", {}]];
private _mainDisplay = if (!isNull _curatorDisplay) then {
_curatorDisplay
} else {
call BIS_fnc_displayMission
};
if (_textMessage isEqualType "") then {
_textMessage = parseText _textMessage;
};
if (_textMessage isEqualType "") then {
_textMessage = parseText _textMessage;
};
ARR_SELECT(_this,4,call BIS_fnc_displayMission) createDisplay "RscDisplayCommonMessagePause";
private _display = _mainDisplay createDisplay "RscDisplayCommonMessagePause";
private _display = uiNamespace getVariable "RscDisplayCommonMessage_display";
private _ctrlRscMessageBox = _display displayCtrl 2351;
private _ctrlBcgCommonTop = _display displayCtrl 235100;
private _ctrlBcgCommon = _display displayCtrl 235101;
private _ctrlText = _display displayCtrl 235102;
private _ctrlBackgroundButtonOK = _display displayCtrl 235103;
private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104;
private _ctrlBackgroundButtonCancel = _display displayCtrl 235105;
private _ctrlButtonOK = _display displayCtrl 235106;
private _ctrlButtonCancel = _display displayCtrl 235107;
if (isNull _display) exitWith {};
_ctrlBcgCommonTop ctrlSetText _textHeader;
private _ctrlRscMessageBox = _display displayCtrl 2351;
private _ctrlBcgCommonTop = _display displayCtrl 235100;
private _ctrlBcgCommon = _display displayCtrl 235101;
private _ctrlText = _display displayCtrl 235102;
private _ctrlBackgroundButtonOK = _display displayCtrl 235103;
private _ctrlBackgroundButtonMiddle = _display displayCtrl 235104;
private _ctrlBackgroundButtonCancel = _display displayCtrl 235105;
private _ctrlButtonOK = _display displayCtrl 235106;
private _ctrlButtonCancel = _display displayCtrl 235107;
private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK;
private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon;
private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3));
_ctrlBcgCommonTop ctrlSetText _textHeader;
private _ctrlTextPos = ctrlPosition _ctrlText;
private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0);
private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1);
private _ctrlButtonOKPos = ctrlPosition _ctrlButtonOK;
private _ctrlBcgCommonPos = ctrlPosition _ctrlBcgCommon;
private _bottomSpaceY = (_ctrlButtonOKPos select 1) - ((_ctrlBcgCommonPos select 1) + (_ctrlBcgCommonPos select 3));
_ctrlText ctrlSetStructuredText _textMessage;
private _ctrlTextPosH = ctrlTextHeight _ctrlText;
private _ctrlTextPos = ctrlPosition _ctrlText;
private _marginX = (_ctrlTextPos select 0) - (_ctrlBcgCommonPos select 0);
private _marginY = (_ctrlTextPos select 1) - (_ctrlBcgCommonPos select 1);
_ctrlBcgCommon ctrlSetPosition [
_ctrlBcgCommonPos select 0,
_ctrlBcgCommonPos select 1,
_ctrlBcgCommonPos select 2,
_ctrlTextPosH + _marginY * 2
];
_ctrlBcgCommon ctrlCommit 0;
_ctrlText ctrlSetStructuredText _textMessage;
private _ctrlTextPosH = ctrlTextHeight _ctrlText;
_ctrlText ctrlSetPosition [
(_ctrlBcgCommonPos select 0) + _marginX,
(_ctrlBcgCommonPos select 1) + _marginY,
(_ctrlBcgCommonPos select 2) - _marginX * 2,
_ctrlTextPosH
];
_ctrlText ctrlCommit 0;
_ctrlBcgCommon ctrlSetPosition [
_ctrlBcgCommonPos select 0,
_ctrlBcgCommonPos select 1,
_ctrlBcgCommonPos select 2,
_ctrlTextPosH + _marginY * 2
];
_ctrlBcgCommon ctrlCommit 0;
private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY;
_ctrlText ctrlSetPosition [
(_ctrlBcgCommonPos select 0) + _marginX,
(_ctrlBcgCommonPos select 1) + _marginY,
(_ctrlBcgCommonPos select 2) - _marginX * 2,
_ctrlTextPosH
];
_ctrlText ctrlCommit 0;
{
private _xPos = ctrlPosition _x;
private _bottomPosY = (_ctrlBcgCommonPos select 1) + _ctrlTextPosH + (_marginY * 2) + _bottomSpaceY;
_xPos set [1, _bottomPosY];
_x ctrlSetPosition _xPos;
_x ctrlCommit 0;
} forEach [
_ctrlBackgroundButtonOK,
_ctrlBackgroundButtonMiddle,
_ctrlBackgroundButtonCancel,
_ctrlButtonOK,
_ctrlButtonCancel
];
{
private _xPos = ctrlPosition _x;
private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox;
private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3);
_xPos set [1, _bottomPosY];
_x ctrlSetPosition _xPos;
_x ctrlCommit 0;
} forEach [
_ctrlBackgroundButtonOK,
_ctrlBackgroundButtonMiddle,
_ctrlBackgroundButtonCancel,
_ctrlButtonOK,
_ctrlButtonCancel
];
_ctrlRscMessageBox ctrlSetPosition [
0.5 - (_ctrlBcgCommonPos select 2) / 2,
0.5 - _ctrlRscMessageBoxPosH / 2,
(_ctrlBcgCommonPos select 2) + 0.5,
_ctrlRscMessageBoxPosH
];
private _ctrlRscMessageBoxPos = ctrlPosition _ctrlRscMessageBox;
private _ctrlRscMessageBoxPosH = _bottomPosY + (_ctrlButtonOKPos select 3);
_ctrlRscMessageBox ctrlEnable true;
_ctrlRscMessageBox ctrlCommit 0;
_ctrlRscMessageBox ctrlSetPosition [
0.5 - (_ctrlBcgCommonPos select 2) / 2,
0.5 - _ctrlRscMessageBoxPosH / 2,
(_ctrlBcgCommonPos select 2) + 0.5,
_ctrlRscMessageBoxPosH
];
if (_onOK isEqualTo {}) then {
_ctrlButtonOK ctrlEnable false;
_ctrlButtonOK ctrlSetFade 0;
_ctrlButtonOK ctrlSetText "";
_ctrlButtonOK ctrlCommit 0;
} else {
_ctrlRscMessageBox ctrlEnable true;
_ctrlRscMessageBox ctrlCommit 0;
// Enable ok button
_ctrlButtonOK ctrlEnable true;
_ctrlButtonOK ctrlSetFade 0;
_ctrlButtonOK ctrlSetText localize "STR_DISP_OK";
_ctrlButtonOK ctrlCommit 0;
ctrlSetFocus _ctrlButtonOK;
};
if (_onCancel isEqualTo {}) then {
// Disable cancel button
_ctrlButtonCancel ctrlEnable false;
_ctrlButtonCancel ctrlSetFade 0;
_ctrlButtonCancel ctrlSetText "";
_ctrlButtonCancel ctrlCommit 0;
} else {
_ctrlButtonCancel ctrlEnable true;
_ctrlButtonCancel ctrlSetFade 0;
_ctrlButtonCancel ctrlSetText localize "STR_DISP_CANCEL";
_ctrlButtonCancel ctrlCommit 0;
ctrlSetFocus _ctrlButtonCancel;
};
_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay IDC_OK; true}];
_ctrlButtonOK ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 1; true}];
_ctrlButtonCancel ctrlAddEventHandler ["ButtonClick", {(ctrlParent (_this select 0)) closeDisplay 2; true}];
// Intercept all keystrokes except the enter keys
_display displayAddEventHandler ["KeyDown", {!((_this select 1) in [DIK_RETURN, DIK_NUMPADENTER])}];
GVAR(errorOnOK) = _onOK;
GVAR(errorOnCancel) = _onCancel;
_display displayAddEventHandler ["Unload", {call ([{}, GVAR(errorOnOK), GVAR(errorOnCancel)] select (_this select 1))}];
_display displayAddEventHandler ["KeyDown", {_this select 1 == 1}];
// Close curator and mission displays (because of the message display, it doesn't quit the mission yet)
findDisplay 312 closeDisplay 0;
findDisplay 46 closeDisplay 0;
}, _this] call CBA_fnc_waitUntilAndExecute;

View File

@ -1,21 +1,21 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Check if unit has item. Note: case-sensitive.
* Check if given unit has an item of given classname. Note: Case sensitive.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Item Classname <STRING>
* 1: Item classname <STRING>
*
* Return Value:
* Unit has Item <BOOL>
* Unit has item <BOOL>
*
* Example:
* [bob, "item"] call ace_common_fnc_hasItem
* [player, "ACE_Banana"] call ace_common_fnc_hasItem
*
* Public: Yes
*/
params [["_unit", objNull, [objNull]], ["_item", "", [""]]];
_item in (_unit call EFUNC(common,uniqueItems))
_item in (_unit call FUNC(uniqueItems)) // return

View File

@ -1,23 +1,21 @@
#include "..\script_component.hpp"
/*
* Author: Glowbal
* Check if given unit has a magazine of given classname
* Check if given unit has a magazine of given classname. Note: Case sensitive.
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Magazine Classname <STRING>
* 1: Magazine classname <STRING>
*
* Return Value:
* has Magazine <BOOL>
* Unit has magazine <BOOL>
*
* Example:
* [bob, "magazine"] call ace_common_fnc_hasMagazine
* [player, "30Rnd_65x39_caseless_mag"] call ace_common_fnc_hasMagazine
*
* Public: yes
*
* Note: Case sensitive
*/
params [["_unit", objNull, [objNull]], ["_magazine", "", [""]]];
_magazine in magazines _unit // return
_magazine in ([_unit, 2] call FUNC(uniqueItems)) // return

View File

@ -22,7 +22,7 @@ params ["_unit", ["_distance", 10], ["_cargoOnly", false]];
private _nearVehicles = nearestObjects [_unit, ["Car", "Air", "Tank", "Ship_F", "Pod_Heli_Transport_04_crewed_base_F"], _distance];
_nearVehicles select {
// Filter cargo seats that will eject unconscious units (e.g. quad bike)
private _canSitInCargo = (!(_unit getVariable ['ACE_isUnconscious', false])) || {(getNumber (configOf _x >> "ejectDeadCargo")) == 0};
private _canSitInCargo = (_unit call EFUNC(common,isAwake)) || {(getNumber (configOf _x >> "ejectDeadCargo")) == 0};
((fullCrew [_x, "", true]) findIf {
_x params ["_body", "_role", "_cargoIndex"];
(isNull _body) // seat empty

View File

@ -28,10 +28,12 @@ private _fnc_getItems = {
_inventoryItems append ((getItemCargo vestContainer _target) select 0);
_inventoryItems append ((getItemCargo backpackContainer _target) select 0);
_items set [0, _inventoryItems];
_items set [1, magazines _target];
private _magazines = magazines _target;
_items arrayIntersect _items
_items set [0, _inventoryItems arrayIntersect _inventoryItems];
_items set [1, _magazines arrayIntersect _magazines];
_items
};
// Cache items list if unit is ACE_player

View File

@ -1,160 +0,0 @@
// by commy2
#include "..\script_component.hpp"
private _aceWhitelist = missionNamespace getVariable ["ACE_Version_Whitelist", []];
private _files = CBA_common_addons select {
(_x select [0,3] != "a3_") &&
{_x select [0,4] != "ace_"} &&
{!((toLowerANSI _x) in _aceWhitelist)}
};
private _versions = [];
{
getText (configFile >> "CfgPatches" >> _x >> "version") splitString "." params [["_major", "0"], ["_minor", "0"]];
private _version = parseNumber _major + parseNumber _minor/100;
_versions set [_forEachIndex, _version];
} forEach _files;
if (isServer) then {
ACE_Version_ServerVersions = [_files, _versions];
publicVariable "ACE_Version_ServerVersions";
} else {
ACE_Version_ClientVersions = [_files, _versions];
};
// Begin client version check
if (!isServer) then {
// Wait for server to send the servers files and version numbers
waitUntil {
sleep 1;
!isNil "ACE_Version_ClientVersions" && {!isNil "ACE_Version_ServerVersions"}
};
private _client = profileName;
_files = ACE_Version_ClientVersions select 0;
_versions = ACE_Version_ClientVersions select 1;
private _serverFiles = ACE_Version_ServerVersions select 0;
private _serverVersions = ACE_Version_ServerVersions select 1;
// Compare client and server files and versions
private _missingAddons = [];
private _oldVersionsClient = [];
private _oldVersionsServer = [];
{
private _serverVersion = _serverVersions select _forEachIndex;
private _index = _files find _x;
if (_index == -1) then {
if (_x != "ace_server") then {_missingAddons pushBack _x;};
} else {
private _clientVersion = _versions select _index;
if (_clientVersion < _serverVersion) then {
_oldVersionsClient pushBack [_x, _clientVersion, _serverVersion];
};
if (_clientVersion > _serverVersion) then {
_oldVersionsServer pushBack [_x, _clientVersion, _serverVersion];
};
};
} forEach _serverFiles;
// find client files which the server doesn't have
private _missingAddonsServer = [];
{
private _index = _serverFiles find _x;
if (_index == -1) then {
_missingAddonsServer pushBack _x;
}
} forEach _files;
// display and log error messages
private _fnc_cutComma = {
private _string = _this;
_string = toArray _string;
private _count = count _string;
_string set [_count - 2, toArray "." select 0];
_string set [_count - 1, -1];
_string = _string - [-1];
toString _string;
};
private _missingAddon = false;
if (count _missingAddons > 0) then {
_missingAddon = true;
private _error = format ["[ACE] %1: ERROR client missing addon(s): ", _client];
{
_error = _error + format ["%1, ", _x];
if (_forEachIndex > 9) exitWith {};
} forEach _missingAddons;
_error = _error call _fnc_cutComma;
diag_log text _error;
[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
[QGVAR(serverLog), _error] call CBA_fnc_serverEvent;
};
private _missingAddonServer = false;
if (count _missingAddonsServer > 0) then {
_missingAddonServer = true;
private _error = format ["[ACE] %1: ERROR server missing addon(s): ", _client];
{
_error = _error + format ["%1, ", _x];
if (_forEachIndex > 9) exitWith {};
} forEach _missingAddonsServer;
_error = _error call _fnc_cutComma;
diag_log text _error;
[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
[QGVAR(serverLog), _error] call CBA_fnc_serverEvent;
};
private _oldVersionClient = false;
if (count _oldVersionsClient > 0) then {
_oldVersionClient = true;
private _error = format ["[ACE] %1: ERROR outdated client addon(s): ", _client];
{
_error = _error + format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2];
if (_forEachIndex > 9) exitWith {};
} forEach _oldVersionsClient;
_error = _error call _fnc_cutComma;
diag_log text _error;
[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
[QGVAR(serverLog), _error] call CBA_fnc_serverEvent;
};
private _oldVersionServer = false;
if (count _oldVersionsServer > 0) then {
_oldVersionServer = true;
private _error = format ["[ACE] %1: ERROR outdated server addon(s): ", _client];
{
_error = _error + format ["%1 (client: %2, server: %3), ", _x select 0, _x select 1, _x select 2];
if (_forEachIndex > 9) exitWith {};
} forEach _oldVersionsServer;
_error = _error call _fnc_cutComma;
diag_log text _error;
[QGVAR(systemChatGlobal), _error] call CBA_fnc_globalEvent;
[QGVAR(serverLog), _error] call CBA_fnc_serverEvent;
};
ACE_Version_ClientErrors = [_missingAddon, _missingAddonServer, _oldVersionClient, _oldVersionServer];
};

View File

@ -402,7 +402,7 @@
<Portuguese>[ACE] Itens diversos</Portuguese>
<Hungarian>[ACE] Egyéb tárgyak</Hungarian>
<Italian>[ACE] Oggetti vari</Italian>
<Japanese>[ACE] その他アイテム</Japanese>
<Japanese>[ACE] その他アイテム</Japanese>
<Korean>[ACE] 기타 물품.</Korean>
<Chinese>[ACE] 雜項</Chinese>
<Chinesesimp>[ACE] 杂项</Chinesesimp>
@ -726,7 +726,7 @@
<Key ID="STR_ACE_Common_SettingPersistentLaserDesc">
<English>Enable gunlight after weapon switch or vehicle enter/exit if it was previously enabled.</English>
<Russian>Включать ЛЦУ/тактический фонарь после смены оружия или входа/выхода из машины, если он был до этого включен.</Russian>
<Japanese>銃のライト等を点けていると武器を切り替えた後や車両を乗り降りしても、ライト等を点けたままにします。</Japanese>
<Japanese>銃のライトをつけていた場合、武器の切り替え後または車両の出入り後にライトを再度点灯します。</Japanese>
<Italian>Abilita la torcia/laser dopo il cambio dell'arma o l'entrata/uscita del veicolo se precedentemente attiva.</Italian>
<Korean>이전에 무기의 손전등/레이저를 켠 경우 무기 전환이나 차량 승하차시 켠 상태를 유지합니다.</Korean>
<German>Aktiviert Laserpointer/Taktisches Licht nach einem Waffenwechsel oder dem Auf-/Absitzen, falls es zuvor aktiv war.</German>
@ -1360,7 +1360,7 @@
<Italian>Non hai più spazio</Italian>
<Hungarian>Nincs több hely</Hungarian>
<Russian>В инвентаре нет места</Russian>
<Japanese>インベントリに空きがない</Japanese>
<Japanese>インベントリに空きがありません</Japanese>
<Korean>넣을 공간이 없습니다</Korean>
<Chinese>無可用空間</Chinese>
<Chinesesimp>无可用空间</Chinesesimp>
@ -1406,7 +1406,7 @@
<Korean>음악 끄기 허용</Korean>
<Chinese>允許調低音樂音量</Chinese>
<Chinesesimp>允许调低音乐音量</Chinesesimp>
<Japanese>音楽の音量低下を許可</Japanese>
<Japanese>音楽音量の低減を許可</Japanese>
<Italian>Permesso di abbassare la musica</Italian>
<Polish>Zezwól na przyciszanie muzyki</Polish>
<Russian>Разрешить приглушение музыки</Russian>
@ -1422,7 +1422,7 @@
<Korean>ACE 스크립트가 음악을 끌 수 있습니다.</Korean>
<Chinese>允許ACE腳本去控制音樂的音量</Chinese>
<Chinesesimp>允许 ACE 脚本去控制音乐的音量。</Chinesesimp>
<Japanese>ACEのスクリプトに音量低下を許可します。</Japanese>
<Japanese>ACEのスクリプトに音楽音量の低減を許可します。</Japanese>
<Italian>Permetti agli script di ACEdi abbassare la musica.</Italian>
<Polish>Zezwól skrypty ACE na przyciszanie muzyki.</Polish>
<Russian>Позволить скриптам ACE приглушать музыку</Russian>
@ -1435,7 +1435,7 @@
<Key ID="STR_ACE_Common_EpilepsyFriendlyMode">
<English>Epilepsy friendly mode</English>
<German>Epilepsiefreundlicher Modus</German>
<Japanese>けいれん回避モード</Japanese>
<Japanese>てんかん対応モード</Japanese>
<Polish>Tryb dla epileptyków</Polish>
<French>Mode adapté à l'épilepsie</French>
<Italian>Modalità per Epilettici</Italian>
@ -1448,7 +1448,7 @@
<Key ID="STR_ACE_Common_EpilepsyFriendlyModeTooltip">
<English>Disables some flashing light effects to reduce seizure risk.</English>
<German>Deaktiviert einige Lichtflackereffekte um das Risiko von Epilepsieanfällen zu reduzieren.</German>
<Japanese>いくつかの光点滅エフェクトを無効化し、けいれんの恐れを低下させます。</Japanese>
<Japanese>てんかん発作のリスクを軽減するために、一部の点滅する光の効果を無効にします。</Japanese>
<Polish>Wyłącz część migających efektów w celu zredukowania ryzyka napadu epilepsji</Polish>
<French>Désactive certains effets de lumière clignotante afin de réduire les risques de crise d'épilepsie.</French>
<Italian>Disattiva alcuni effetti di luci intermittenti per ridurre il rischio di crisi epilettiche.</Italian>
@ -1464,7 +1464,7 @@
<Chinesesimp>旗帜ACE-黑色):</Chinesesimp>
<Chinese>旗幟(ACE-黑色)</Chinese>
<Italian>Bandiera (ACE - Nera)</Italian>
<Japanese>旗 (ACE - 黒)</Japanese>
<Japanese>旗 (ACE - 黒)</Japanese>
<Polish>Flaga (ACE - Czarna)</Polish>
<Russian>Флаг (ACE - Черный)</Russian>
<Portuguese>Bandeira (ACE - Preto)</Portuguese>
@ -1480,7 +1480,7 @@
<Chinesesimp>旗帜ACE-白色):</Chinesesimp>
<Chinese>旗幟(ACE-白色)</Chinese>
<Italian>Bandiera (ACE - Bianca)</Italian>
<Japanese>旗 (ACE - 白)</Japanese>
<Japanese>旗 (ACE - 白)</Japanese>
<Polish>Flaga (ACE - Biała)</Polish>
<Russian>Флаг (ACE - Белый)</Russian>
<Portuguese>Bandeira (ACE - Branco)</Portuguese>
@ -1544,7 +1544,7 @@
<Chinesesimp>在自我互动菜单内显示动作</Chinesesimp>
<Polish>Pokaż akcje w menu interakcji własnej</Polish>
<Portuguese>Mostra a ação no menu de auto-interação</Portuguese>
<Japanese>セルフ インタラクションにアクションを表示</Japanese>
<Japanese>セルフインタラクションにアクションを表示します</Japanese>
<Italian>Mostra le azioni nel menu di interazione con se stessi</Italian>
<Spanish>Mostrar la acción en el menú de interacción propio</Spanish>
<Czech>Zobrazit akci v menu vlastních interakcí</Czech>
@ -1896,7 +1896,7 @@
<German>Verwacklungsfaktor, wenn aufgelegt</German>
<Italian>Fattore di Oscillazione Appoggiato</Italian>
<Japanese>静止依託時の手ぶれ係数</Japanese>
<Russian>Коэффициент колебания прицела в состоянии покоя</Russian>
<Russian>Коэф. колебания прицела в состоянии покоя</Russian>
<Spanish>Factor de oscilación apoyado</Spanish>
</Key>
<Key ID="STR_ACE_Common_RestedSwayFactor_Description">
@ -1918,7 +1918,7 @@
<German>Verwacklungsfaktor, wenn Zweibein aufgestellt ist.</German>
<Italian>Fattore di Oscillazione su Bipode</Italian>
<Japanese>接地展開時の手ぶれ係数</Japanese>
<Russian>Коэффициент колебания прицела при развертывании</Russian>
<Russian>Коэф. колебания прицела при развертывании</Russian>
<Spanish>Factor de oscilación desplegado</Spanish>
</Key>
<Key ID="STR_ACE_Common_DeployedSwayFactor_Description">

View File

@ -8,6 +8,7 @@
<Korean>[CSW] AGS-30 벨트</Korean>
<German>[CSW] AGS30 Gurt</German>
<Spanish>[CSW] Cinta de AGS30</Spanish>
<Italian>[CSW] Nastro AGS30</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_MK19_displayName">
<English>[CSW] MK19 Belt</English>
@ -16,6 +17,7 @@
<Korean>[CSW] Mk.19 벨트</Korean>
<German>[CSW] MK19 Gurt</German>
<Spanish>[CSW] Cinta de MK19</Spanish>
<Italian>[CSW] Nastro MK19</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_TOW_displayName">
<English>[CSW] TOW Tube</English>
@ -24,6 +26,7 @@
<Korean>[CSW] TOW 튜브</Korean>
<German>[CSW] TOW Rohr</German>
<Spanish>[CSW] Tubo de TOW</Spanish>
<Italian>[CSW] Tubo TOW</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_TOW2_displayName">
<English>[CSW] TOW2 Tube</English>
@ -32,6 +35,7 @@
<Korean>[CSW] TOW2 튜브</Korean>
<German>[CSW] TOW2 Rohr</German>
<Spanish>[CSW] Tubo de TOW2</Spanish>
<Italian>[CSW] Tubo TOW2</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_PG9_displayName">
<English>[CSW] PG-9 Round</English>
@ -40,6 +44,7 @@
<Korean>[CSW] PG-9 대전차고폭탄</Korean>
<German>[CSW] PG-9 Rakete</German>
<Spanish>[CSW] Carga de PG-9</Spanish>
<Italian>[CSW] Razzo PG-9</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_OG9_displayName">
<English>[CSW] OG-9 Round</English>
@ -48,6 +53,7 @@
<Korean>[CSW] OG-9 고폭파편탄</Korean>
<German>[CSW] OG-9 Rakete</German>
<Spanish>[CSW] Carga de OG-9</Spanish>
<Italian>[CSW] Razzo OG-9</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_M1HE_displayName">
<English>[CSW] M1 HE</English>
@ -57,6 +63,7 @@
<French>[CSW] M1 HE</French>
<German>[CSW] M1 HE</German>
<Spanish>[CSW] HE de M1</Spanish>
<Italian>[CSW] M1 HE</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_M84Smoke_displayName">
<English>[CSW] M84 Smoke</English>
@ -66,6 +73,7 @@
<French>[CSW] M84 Fumigène</French>
<German>[CSW] M84 Rauch</German>
<Spanish>[CSW] Humo M84</Spanish>
<Italian>[CSW] M84 Fumogeno</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_M60A2_displayName">
<English>[CSW] M60A2 WP</English>
@ -75,6 +83,7 @@
<French>[CSW] M60A2 WP</French>
<German>[CSW] M60A2 WP</German>
<Spanish>[CSW] M60A2 WP</Spanish>
<Italian>[CSW] M60A2 WP</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_M67AT_displayName">
<English>[CSW] M67 AT Laser Guided</English>
@ -84,6 +93,7 @@
<French>[CSW] M67 AT Guidé laser</French>
<German>[CSW] M67 AT Lasergelenkt</German>
<Spanish>[CSW] AT Guiado por Láser M67</Spanish>
<Italian>[CSW] M67 AT Laserguidato</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_M314Illum_displayName">
<English>[CSW] M314 Illumination</English>
@ -93,6 +103,7 @@
<French>[CSW] M314 Illumination</French>
<German>[CSW] M314 Beleuchtung</German>
<Spanish>[CSW] Iluminación M314</Spanish>
<Italian>[CSW] M314 Illuminante</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_3OF56_displayName">
<English>[CSW] 3OF56 HE</English>
@ -102,6 +113,7 @@
<French>[CSW] 3OF56 HE</French>
<German>[CSW] 3OF56 HE</German>
<Spanish>[CSW] HE de 3OF56</Spanish>
<Italian>[CSW] 3OF56 HE</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_3OF69M_displayName">
<English>[CSW] 3OF69M Laser Guided</English>
@ -111,6 +123,7 @@
<French>[CSW] 3OF69M Guidé laser</French>
<German>[CSW] 3OF69M Lasergelenkt</German>
<Spanish>[CSW] 3OF69M Guiado por Láser</Spanish>
<Italian>[CSW] 3OF69M Laserguidato</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_122mmWP_displayName">
<English>[CSW] 122mm WP</English>
@ -120,6 +133,7 @@
<French>[CSW] 122mm WP</French>
<German>[CSW] 122mm WP</German>
<Spanish>[CSW] WP de 122mm</Spanish>
<Italian>[CSW] 122mm WP</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_122mmSmoke_displayName">
<English>[CSW] D-462 Smoke</English>
@ -129,6 +143,7 @@
<French>[CSW] D-462 Fumigène</French>
<German>[CSW] D-462 Rauch</German>
<Spanish>[CSW] Humo D-462</Spanish>
<Italian>[CSW] D-462 Fumogeno</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_122mmIllum_displayName">
<English>[CSW] S-463 Illumination</English>
@ -138,6 +153,7 @@
<French>[CSW] S-463 Eclairante</French>
<German>[CSW] S-463 Beleuchtung</German>
<Spanish>[CSW] Iluminación S-463</Spanish>
<Italian>[CSW] S-463 Illuminante</Italian>
</Key>
<Key ID="STR_ACE_Compat_CUP_Weapons_CSW_mag_122mmAT_displayName">
<English>[CSW] BK-6M HEAT</English>
@ -147,6 +163,7 @@
<French>[CSW] BK-6M HEAT</French>
<German>[CSW] BK-6M HEAT</German>
<Spanish>[CSW] BK-6M HEAT</Spanish>
<Italian>[CSW] BK-6M HEAT</Italian>
</Key>
</Package>
</Project>

View File

@ -37,7 +37,7 @@
<Key ID="STR_ACE_Compat_CUP_Weapons_nightvision_CUP_NVG_PVS15_tan_WP">
<English>AN/PVS-15 (Tan, WP)</English>
<Japanese>AN/PVS-15 (タン, 白色蛍光)</Japanese>
<Italian>AN/PVS-15 (Marroncina, FB)</Italian>
<Italian>AN/PVS-15 (Marroncino, FB)</Italian>
<Polish>AN/PVS-15 (Jasnobrązowa, WP)</Polish>
<German>AN/PVS-15 (Hellbraun, WP)</German>
<Korean>AN/PVS-15 (황갈색, 백색광)</Korean>
@ -48,6 +48,7 @@
<Key ID="STR_ACE_Compat_CUP_Weapons_nightvision_CUP_NVG_PVS15_winter_WP">
<English>AN/PVS-15 (Winter, WP)</English>
<Japanese>AN/PVS-15 (冬季迷彩, WP)</Japanese>
<Italian>AN/PVS-15 (Invernale, FB)</Italian>
<Korean>AN/PVS-15 (설상, 백색광)</Korean>
<Russian>AN/PVS-15 (Белый, БФ)</Russian>
<French>AN/PVS-15 (Blanc, WP)</French>
@ -68,7 +69,7 @@
<Key ID="STR_ACE_Compat_CUP_Weapons_nightvision_CUP_NVG_GPNVG_tan_WP">
<English>GPNVG (Tan, WP)</English>
<Japanese>GPNVG (タン, 白色蛍光)</Japanese>
<Italian>GPNVG (Marroncina, FB)</Italian>
<Italian>GPNVG (Marroncino, FB)</Italian>
<Polish>GPNVG (Jasnobrązowa, WP)</Polish>
<German>GPNVG (Hellbraun, WP)</German>
<Korean>GPNVG (황갈색, 백색광)</Korean>
@ -90,6 +91,7 @@
<Key ID="STR_ACE_Compat_CUP_Weapons_nightvision_CUP_NVG_GPNVG_winter_WP">
<English>GPNVG (Winter, WP)</English>
<Japanese>GPNVG (冬季迷彩, WP)</Japanese>
<Italian>GPNVG (Invernale, FB)</Italian>
<Korean>GPNVG (설상, 백색광)</Korean>
<Russian>AN/PVS-15 (Белый, БФ)</Russian>
<French>GPNVG (Blanc, WP)</French>

View File

@ -19,36 +19,54 @@ class CfgVehicles {
displayName = SUBCSTRING(heli_light_03_unarmed_Name);
};
class Heli_EC_01A_base_RF;
class Heli_EC_01A_military_base_RF: Heli_EC_01A_base_RF {
displayName = SUBCSTRING(ec_01a_military_Name);
};
// H240 Transport, Gendarmerie/ION Transport
class Helicopter_Base_H;
class Heli_EC_01_base_RF: Helicopter_Base_H {
displayName = SUBCSTRING(ec_01_base_Name);
};
// H240C Transport, CIV Transport
class Heli_EC_01_civ_base_RF: Heli_EC_01_base_RF {
displayName = SUBCSTRING(ec_01_Name);
displayName = SUBCSTRING(ec_01_civ_base_Name);
};
// H235 Transport, CIV Transport Float-less (not used)
class Heli_EC_01A_base_RF: Heli_EC_01_base_RF {
displayName = SUBCSTRING(ec_01a_base_Name);
};
// H235C Transport, CIV Transport Float-less
class Heli_EC_01A_civ_base_RF: Heli_EC_01A_base_RF {
displayName = SUBCSTRING(ec_01a_Name);
displayName = SUBCSTRING(ec_01a_civ_base_Name);
};
// RAI-350M Cougar (Unarmed), IND/UNA Transport Float-less
class Heli_EC_01A_military_base_RF: Heli_EC_01A_base_RF {
displayName = SUBCSTRING(ec_01a_military_base_Name);
};
// RAI-360M Cougar, IND/OPF SOCAT Float-less
class Heli_EC_02_base_RF: Heli_EC_01_base_RF {
displayName = SUBCSTRING(ec_02_Name);
displayName = SUBCSTRING(ec_02_base_Name);
};
// MH-360M Cougar, NATO SOCAT (not used) Float-less
class B_Heli_EC_02_RF: Heli_EC_02_base_RF {
displayName = SUBCSTRING(ec_02_nato_Name);
};
// MH-245 Cougar, NATO Combat Type
class Heli_EC_03_base_RF: Heli_EC_01_base_RF {
displayName = SUBCSTRING(ec_03_Name);
displayName = SUBCSTRING(ec_03_base_Name);
};
// H245 SAR, CIV SAR Type
class Heli_EC_04_base_RF: Heli_EC_01_base_RF {
displayName = SUBCSTRING(ec_04_Name);
displayName = SUBCSTRING(ec_04_base_Name);
};
// MH-245 Cougar (Unarmed), NATO Transport Type (Maybe SAR?)
class Heli_EC_04_military_base_RF: Heli_EC_04_base_RF {
displayName = SUBCSTRING(ec_04_military_base_Name);
};
// HEMTT
class B_Truck_01_fuel_F;
class C_Truck_01_water_rf: B_Truck_01_fuel_F {
displayName = SUBCSTRING(truck_01_water_Name);
};
// Typhoon
class O_Truck_03_fuel_F;
class C_Truck_03_water_rf: O_Truck_03_fuel_F {

View File

@ -4,294 +4,547 @@
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_mrd_khk_Name">
<English>EOTech MRDS (Khaki)</English>
<Japanese>EOTech MRDS (カーキ)</Japanese>
<Korean>이오텍 MRDS (카키)</Korean>
<German>EOTech MRDS (Khaki)</German>
<Italian>EOTech MRDS (Cachi)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_mrd_tan_Name">
<English>EOTech MRDS (Tan)</English>
<Japanese>EOTech MRDS (タン)</Japanese>
<Korean>이오텍 MRDS (황갈)</Korean>
<German>EOTech MRDS (Hellbraun)</German>
<Italian>EOTech MRDS (Marroncino)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_aco_grn_desert_Name">
<English>C-More Railway (Green, Desert)</English>
<Japanese>C-More レイルウェイ (グリーン、砂漠迷彩)</Japanese>
<Korean>씨모어 레일웨이 (녹색, 사막)</Korean>
<German>C-More Railway (Grün, Wüste)</German>
<Italian>C-More Railway (Verde, Deserto)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_aco_grn_wood_Name">
<English>C-More Railway (Green, Woodland)</English>
<Japanese>C-More レイルウェイ (グリーン、森林迷彩)</Japanese>
<Korean>씨모어 레일웨이 (녹색, 수풀 위장)</Korean>
<German>C-More Railway (Grün, Grünes Tarnmuster)</German>
<Italian>C-More Railway (Verde, Boschivo)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_aco_desert_Name">
<English>C-More Railway (Red, Desert)</English>
<Japanese>C-More レイルウェイ (グリーン、砂漠迷彩)</Japanese>
<Korean>씨모어 레일웨이 (빨강, 사막)</Korean>
<German>C-More Railway (Rot, Wüste)</German>
<Italian>C-More Railway (Rosso, Desert)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_aco_wood_Name">
<English>C-More Railway (Red, Woodland)</English>
<Japanese>C-More レイルウェイ (グリーン、森林迷彩)</Japanese>
<Korean>씨모어 레일웨이 (빨강, 수풀)</Korean>
<German>C-More Railway (Rot, Grünes Tarnmuster)</German>
<Italian>C-More Railway (Rosso, Boschivo)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_rds_Name">
<English>Aimpoint Micro R-1</English>
<Japanese>Aimpoint マイクロ R-1</Japanese>
<Korean>에임포인트 마이크로 R-1</Korean>
<German>Aimpoint Micro R-1</German>
<Italian>Aimpoint Micro R-1</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_vrco_Name">
<English>Vortex Spitfire Prism</English>
<Japanese>Vortex スピットファイア プリズム</Japanese>
<Korean>버텍스 스핏파이어 프리즘</Korean>
<German>Vortex Spitfire Prism</German>
<Italian>Vortex Spitfire Prism</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_vrco_tan_Name">
<English>Vortex Spitfire Prism (Tan)</English>
<Japanese>Vortex スピットファイア プリズム (タン)</Japanese>
<Korean>버텍스 스핏파이어 프리즘 (황갈)</Korean>
<German>Vortex Spitfire Prism (Hellbraun)</German>
<Italian>Vortex Spitfire Prism (Marroncino)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_vrco_khk_Name">
<English>Vortex Spitfire Prism (Khaki)</English>
<Japanese>Vortex スピットファイア プリズム (カーキ)</Japanese>
<Korean>버텍스 스핏파이어 프리즘 (카키)</Korean>
<German>Vortex Spitfire Prism (Khaki)</German>
<Italian>Vortex Spitfire Prism (Cachi)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_optic_vrco_pistol_Name">
<English>Vortex Spitfire Prism (Pistol)</English>
<Japanese>Vortex スピットファイア プリズム (ピストル用)</Japanese>
<Korean>버텍스 스핏파이어 프리즘 (권총용)</Korean>
<German>Vortex Spitfire Prism (Pistole)</German>
<Italian>Vortex Spitfire Prism (Pistola)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_glock19_Name">
<English>Glock 19X</English>
<Japanese>グロック 19X</Japanese>
<Korean>글록 19X</Korean>
<German>Glock 19X</German>
<Italian>Glock 19X</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_glock19_khk_Name">
<English>Glock 19X (Khaki)</English>
<Japanese>グロック 19X (カーキ)</Japanese>
<Korean>글록 19X (카키)</Korean>
<German>Glock 19X (Khaki)</German>
<Italian>Glock 19X (Cachi)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_glock19_tan_Name">
<English>Glock 19X (Tan)</English>
<Japanese>グロック 19X (タン)</Japanese>
<Korean>글록 19X (황갈)</Korean>
<German>Glock 19X (Hellbraun)</German>
<Italian>Glock 19X (Marroncino)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_glock19_auto_Name">
<English>Glock 19X Auto</English>
<Japanese>グロック 19X オート</Japanese>
<Korean>글록 19X 기관권총</Korean>
<German>Glock 19X Auto</German>
<Italian>Glock 19X Auto</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_glock19_auto_khk_Name">
<English>Glock 19X Auto (Khaki)</English>
<Japanese>グロック 19X オート (カーキ)</Japanese>
<Korean>글록 19X 기관권총 (카키)</Korean>
<German>Glock 19X Auto (Khaki)</German>
<Italian>Glock 19X Auto (Cachi)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_glock19_auto_tan_Name">
<English>Glock 19X Auto (Tan)</English>
<Japanese>グロック 19X オート (タン)</Japanese>
<Korean>글록 19X 기관권총 (황갈)</Korean>
<German>Glock 19X Auto (Hellbraun)</German>
<Italian>Glock 19X Auto (Marroncino)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_deagle_Name">
<English>Desert Eagle Mark XIX L5</English>
<Japanese>デザートイーグル Mark XIX L5</Japanese>
<Korean>데저트 이글 마크 XIX L5</Korean>
<German>Desert Eagle Mark XIX L5</German>
<Italian>Desert Eagle Mark XIX L5</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_deagle_classic_Name">
<English>Desert Eagle Mark XIX L5 (Classic)</English>
<Japanese>デザートイーグル Mark XIX L5 (クラシック)</Japanese>
<Korean>데저트 이글 마크 XIX L5 (클래식)</Korean>
<German>Desert Eagle Mark XIX L5 (Klassisch)</German>
<Italian>Desert Eagle Mark XIX L5 (Classico)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_deagle_bronze_Name">
<English>Desert Eagle Mark XIX L5 (Bronze)</English>
<Japanese>デザートイーグル Mark XIX L5 (ブロンズ)</Japanese>
<Korean>데저트 이글 마크 XIX L5 (브론즈)</Korean>
<German>Desert Eagle Mark XIX L5 (Bronze)</German>
<Italian>Desert Eagle Mark XIX L5 (Bronzo)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_deagle_copper_Name">
<English>Desert Eagle Mark XIX L5 (Copper)</English>
<Japanese>デザートイーグル Mark XIX L5 (カッパー)</Japanese>
<Korean>데저트 이글 마크 XIX L5 (구리)</Korean>
<German>Desert Eagle Mark XIX L5 (Kupfer)</German>
<Italian>Desert Eagle Mark XIX L5 (Rame)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_deagle_gold_Name">
<English>Desert Eagle Mark XIX L5 (Gold)</English>
<Japanese>デザートイーグル Mark XIX L5 (ゴールド)</Japanese>
<Korean>데저트 이글 마크 XIX L5 (금색)</Korean>
<German>Desert Eagle Mark XIX L5 (Gold)</German>
<Italian>Desert Eagle Mark XIX L5 (Oro)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_h6_tan_Name">
<English>Hera H6 (Tan)</English>
<Japanese>ヘラ H6 (タン)</Japanese>
<English>HERA H6 (Tan)</English>
<Japanese>HERA H6 (タン)</Japanese>
<Korean>헤라 H6 (황갈)</Korean>
<German>HERA H6 (Hellbraun)</German>
<Italian>HERA H6 (Marroncino)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_h6_oli_Name">
<English>Hera H6 (Olive)</English>
<Japanese>ヘラ H6 (オリーブ)</Japanese>
<English>HERA H6 (Olive)</English>
<Japanese>HERA H6 (オリーブ)</Japanese>
<Korean>헤라 H6 (올리브)</Korean>
<German>HERA H6 (Olivgrün)</German>
<Italian>HERA H6 (Oliva)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_h6_blk_Name">
<English>Hera H6 (Black)</English>
<Japanese>ヘラ H6 (ブラック)</Japanese>
<English>HERA H6 (Black)</English>
<Japanese>HERA H6 (ブラック)</Japanese>
<Korean>헤라 H6 (검정)</Korean>
<German>HERA H6 (Schwarz)</German>
<Italian>HERA H6 (Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_h6_digi_Name">
<English>Hera H6 (Digital)</English>
<Japanese>ヘラ H6 (AAF迷彩)</Japanese>
<English>HERA H6 (Digital)</English>
<Japanese>HERA H6 (AAF迷彩)</Japanese>
<Korean>헤라 H6 (AAF 디지털)</Korean>
<German>HERA H6 (Digital)</German>
<Italian>HERA H6 (Digitale)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_h6_gold_Name">
<English>Hera H6 (Gold)</English>
<Japanese>ヘラ H6 (ゴールド)</Japanese>
<English>HERA H6 (Gold)</English>
<Japanese>HERA H6 (ゴールド)</Japanese>
<Korean>헤라 H6 (금색)</Korean>
<German>HERA H6 (Gold)</German>
<Italian>HERA H6 (Oro)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_dmr_01_black_Name">
<English>VS-121 (Black)</English>
<Japanese>VS-121 (ブラック)</Japanese>
<Korean>VS-121 (검정)</Korean>
<German>VS-121 (Schwarz)</German>
<Italian>VS-121 (Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_dmr_01_tan_Name">
<English>VS-121 (Tan)</English>
<Japanese>VS-121 (タン)</Japanese>
<Korean>VS-121 (황갈)</Korean>
<German>VS-121 (Hellbraun)</German>
<Italian>VS-121 (Marroncino)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_smg_01_black_Name">
<English>Vector SMG (Black)</English>
<Japanese>ベクター SMG (ブラック)</Japanese>
<Korean>벡터 SMG (검정)</Korean>
<German>Vector SMG (Schwarz)</German>
<Italian>Vector SMG (Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_blk_Name">
<English>ASh-12 (Black)</English>
<Japanese>ASh-12 (ブラック)</Japanese>
<Korean>ASh-12 (검정)</Korean>
<German>ASh-12 (Schwarz)</German>
<Italian>ASh-12 (Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_desert_Name">
<English>ASh-12 (Desert)</English>
<Japanese>ASh-12 (砂漠迷彩)</Japanese>
<Korean>ASh-12 (사막)</Korean>
<German>ASh-12 (Wüste)</German>
<Italian>ASh-12 (Deserto)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_urban_Name">
<English>ASh-12 (Urban)</English>
<Japanese>ASh-12 (市街地迷彩)</Japanese>
<Korean>ASh-12 (도심)</Korean>
<German>ASh-12 (Urban)</German>
<Italian>ASh-12 (Urbano)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_wood_Name">
<English>ASh-12 (Woodland)</English>
<Japanese>ASh-12 (森林迷彩)</Japanese>
<Korean>ASh-12 (수풀)</Korean>
<German>ASh-12 (Grünes Tarnmuster)</German>
<Italian>ASh-12 (Boschivo)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_gl_blk_Name">
<English>ASh-12 GL (Black)</English>
<Japanese>ASh-12 GL (ブラック)</Japanese>
<Korean>ASh-12 GL (검정)</Korean>
<German>ASh-12 GL (Schwarz)</German>
<Italian>ASh-12 GL (Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_gl_desert_Name">
<English>ASh-12 GL (Desert)</English>
<Japanese>ASh-12 GL (砂漠迷彩)</Japanese>
<Korean>ASh-12 GL (사막)</Korean>
<German>ASh-12 GL (Wüste)</German>
<Italian>ASh-12 GL (Deserto)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_gl_urban_Name">
<English>ASh-12 GL (Urban)</English>
<Japanese>ASh-12 GL (市街地迷彩)</Japanese>
<Korean>ASh-12 GL (도심)</Korean>
<German>ASh-12 GL (Urban)</German>
<Italian>ASh-12 GL (Urbano)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_gl_wood_Name">
<English>ASh-12 GL (Woodland)</English>
<Japanese>ASh-12 GL (森林迷彩)</Japanese>
<Korean>ASh-12 GL (수풀)</Korean>
<German>ASh-12 GL (Grünes Tarnmuster)</German>
<Italian>ASh-12 GL (Boschivo)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_lr_blk_Name">
<English>ASh-12 LR (Black)</English>
<Japanese>ASh-12 LR (ブラック)</Japanese>
<Korean>ASh-12 LR (검정)</Korean>
<German>ASh-12 LR (Schwarz)</German>
<Italian>ASh-12 LR (Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_lr_desert_Name">
<English>ASh-12 LR (Desert)</English>
<Japanese>ASh-12 LR (砂漠迷彩)</Japanese>
<Korean>ASh-12 LR (사막)</Korean>
<German>ASh-12 LR (Wüste)</German>
<Italian>ASh-12 LR (Deserto)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_lr_urban_Name">
<English>ASh-12 LR (Urban)</English>
<Japanese>ASh-12 LR (市街地迷彩)</Japanese>
<Korean>ASh-12 LR (도심)</Korean>
<German>ASh-12 LR (Urban)</German>
<Italian>ASh-12 LR (Urbano)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ash12_lr_wood_Name">
<English>ASh-12 LR (Woodland)</English>
<Japanese>ASh-12 LR (森林迷彩)</Japanese>
<Korean>ASh-12 LR (수풀)</Korean>
<German>ASh-12 LR (Grünes Tarnmuster)</German>
<Italian>ASh-12 LR (Boschivo)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_heli_light_03_Name">
<English>AW159 Wildcat</English>
<Japanese>AW159 ワイルドキャット</Japanese>
<English>AW159 Wildcat ASW</English>
<Japanese>AW159 ワイルドキャット ASW</Japanese>
<Korean>AW159 와일드캣 ASW</Korean>
<German>AW159 Wildcat ASW</German>
<Italian>AW159 Wildcat ASW</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_heli_light_03_unarmed_Name">
<English>AW159 Wildcat (Unarmed)</English>
<Japanese>AW159 ワイルドキャット (非武装)</Japanese>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01a_military_Name">
<English>H225M Super Cougar HADR</English>
<Japanese>H225M シュペル クーガー HADR</Japanese>
<English>AW159 Wildcat ASW (Unarmed)</English>
<Japanese>AW159 ワイルドキャット ASW (非武装)</Japanese>
<Korean>AW159 와일드캣 ASW (비무장)</Korean>
<German>AW159 Wildcat ASW (Unbewaffnet)</German>
<Italian>AW159 Wildcat ASW (Disarmato)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01_base_Name">
<English>H225M Super Cougar Transport</English>
<Japanese>H225M シュペル クーガー 輸送</Japanese>
<English>H225 Super Puma (Transport)</English>
<Japanese>H225 シュペル ピューマ (輸送型)</Japanese>
<Korean>H225 슈퍼 퓨마 (비무장)</Korean>
<German>H225 Super Puma (Transport)</German>
<Italian>H225 Super Puma (Trasporto)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01_Name">
<English>H225 Super Puma Transport</English>
<Japanese>H225 シュペル ピューマ 輸送</Japanese>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01_civ_base_Name">
<English>H225 Super Puma (Civilian)</English>
<Japanese>H225 シュペル ピューマ (民生型)</Japanese>
<Korean>H225 슈퍼 퓨마 (비무장)</Korean>
<German>H225 Super Puma (Zivil)</German>
<Italian>H225 Super Puma (Civile)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01a_Name">
<English>H225 Super Puma VIP</English>
<Japanese>H225 シュペル ピューマ VIP</Japanese>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01a_base_Name">
<English>H215 Super Puma (Transport)</English>
<Japanese>H215 シュペル ピューマ (輸送型)</Japanese>
<Korean>H215 슈퍼 퓨마 (비무장)</Korean>
<German>H215 Super Puma (Transport)</German>
<Italian>H215 Super Puma (Trasporto)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_02_Name">
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01a_civ_base_Name">
<English>H215 Super Puma (Civilian)</English>
<Japanese>H215 シュペル ピューマ (民生型)</Japanese>
<Korean>H215 슈퍼 퓨마 (비무장)</Korean>
<German>H215 Super Puma (Zivil)</German>
<Italian>H215 Super Puma (Civile)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_01a_military_base_Name">
<English>H215 Super Puma (Unarmed)</English>
<Japanese>H215 シュペル ピューマ (非武装)</Japanese>
<Korean>H215 슈퍼 퓨마 (비무장)</Korean>
<German>H215 Super Puma (Unbewaffnet)</German>
<Italian>H215 Super Puma (Disarmato)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_02_base_Name">
<English>H225M Super Cougar SOCAT</English>
<Japanese>H225M シュペル クーガー SOCAT</Japanese>
<Korean>H225M 슈퍼 쿠거 SOCAT</Korean>
<German>H225M Super Cougar SOCAT</German>
<Italian>H225M Super Cougar SOCAT</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_03_Name">
<English>H225M Super Cougar CSAR</English>
<Japanese>H225M シュペル クーガー CSAR</Japanese>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_02_nato_Name">
<English>H225M Super Cougar SOCAT</English>
<Japanese>H225M シュペル クーガー SOCAT</Japanese>
<Korean>H225M 슈퍼 쿠거 SOCAT</Korean>
<German>H225M Super Cougar SOCAT</German>
<Italian>H225M Super Cougar SOCAT</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_04_Name">
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_03_base_Name">
<English>H225M Super Cougar</English>
<Japanese>H225M シュペル クーガー</Japanese>
<Korean>H225M 슈퍼 쿠거</Korean>
<German>H225M Super Cougar</German>
<Italian>H225M Super Cougar</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_04_base_Name">
<English>H225 Super Puma SAR</English>
<Japanese>H225 シュペル ピューマ SAR</Japanese>
<Japanese>H225 シュペル ピューマ 捜索救難型</Japanese>
<Korean>H225 슈퍼 퓨마 SAR</Korean>
<German>H225 Super Puma SAR</German>
<Italian>H225 Super Puma SAR</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_ec_04_military_base_Name">
<English>H225M Super Cougar (Unarmed)</English>
<Japanese>H225M シュペル クーガー (非武装)</Japanese>
<German>H225M Super Cougar (Unbewaffnet)</German>
<Italian>H225M Super Cougar (Disarmato)</Italian>
<Korean>H225M 슈퍼 쿠거 (비무장)</Korean>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_truck_01_water_Name">
<English>HEMTT Fire Truck</English>
<French>HEMTT anti-incendie</French>
<Polish>HEMTT (wersja pożarnicza)</Polish>
<German>HEMTT-Löschfahrzeug</German>
<Spanish>HEMTT (camión de bomberos)</Spanish>
<Russian>Пожарная машина HEMTT</Russian>
<Chinesesimp>HEMTT 消防卡车</Chinesesimp>
<Portuguese>HEMTT contra incêndio</Portuguese>
<Japanese>HEMTT 消防車</Japanese>
<Italian>HEMTT Autobotte</Italian>
<Korean>HEMTT 소방트럭</Korean>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_truck_03_water_Name">
<English>Typhoon Water</English>
<Japanese>タイフーン 給水</Japanese>
<Korean>타이푼 급수</Korean>
<German>Typhoon Water</German>
<Italian>Typhoon Acqua</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_Name">
<English>Ram 1500</English>
<Japanese>ラム 1500</Japanese>
<Korean>램 1500</Korean>
<German>Ram 1500</German>
<Italian>Ram 1500</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_Fuel_Name">
<English>Ram 1500 (Fuel)</English>
<Japanese>ラム 1500 (燃料)</Japanese>
<Korean>램 1500 (연료)</Korean>
<German>Ram 1500 (Treibstoff)</German>
<Italian>Ram 1500 (Carburante)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_service_Name">
<English>Ram 1500 (Services)</English>
<Japanese>ラム 1500 (サービス)</Japanese>
<Korean>램 1500 (서비스)</Korean>
<German>Ram 1500 (Pannenhilfe)</German>
<Italian>Ram 1500 (Servizi)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_repair_Name">
<English>Ram 1500 (Repair)</English>
<Japanese>ラム 1500 (修理)</Japanese>
<Korean>램 1500 (정비)</Korean>
<German>Ram 1500 (Instandsetzung)</German>
<Italian>Ram 1500 (Riparazioni)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_comms_Name">
<English>Ram 1500 (Comms)</English>
<Japanese>ラム 1500 (通信)</Japanese>
<Korean>램 1500 (통신)</Korean>
<German>Ram 1500 (Kommunikation)</German>
<Italian>Ram 1500 (Comunicazioni)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_hmg_Name">
<English>Ram 1500 (HMG)</English>
<Japanese>ラム 1500 (HMG)</Japanese>
<Korean>램 1500 (중기관총)</Korean>
<German>Ram 1500 (HMG)</German>
<Italian>Ram 1500 (HMG)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_mmg_Name">
<English>Ram 1500 (MMG)</English>
<Japanese>ラム 1500 (MMG)</Japanese>
<Korean>램 1500 (중형기관총)</Korean>
<German>Ram 1500 (MMG)</German>
<Italian>Ram 1500 (MMG)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_mrl_Name">
<English>Ram 1500 (MRL)</English>
<Japanese>ラム 1500 (MRL)</Japanese>
<Korean>램 1500 (다연장로켓)</Korean>
<German>Ram 1500 (MRL)</German>
<Italian>Ram 1500 (MRL)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_aa_Name">
<English>Ram 1500 (AA)</English>
<Japanese>ラム 1500 (対空)</Japanese>
<Korean>램 1500 (대공)</Korean>
<German>Ram 1500 (AA)</German>
<Italian>Ram 1500 (AA)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_covered_Name">
<English>Ram 1500 (Covered)</English>
<Japanese>ラム 1500 (カバー)</Japanese>
<Korean>램 1500 (커버)</Korean>
<German>Ram 1500 (Abgedeckt)</German>
<Italian>Ram 1500 (Coperto)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_pickup_01_water_Name">
<English>Ram 1500 (Water)</English>
<Japanese>ラム 1500 (給水)</Japanese>
<Korean>램 1500 (급수)</Korean>
<German>Ram 1500 (Wasser)</German>
<Italian>Ram 1500 (Acqua)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_commando_Name">
<English>RSG60</English>
<Japanese>RSG60</Japanese>
<Korean>RSG60</Korean>
<German>RSG60</German>
<Italian>RSG60</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_twinmortar_Name">
<English>AMOS</English>
<Japanese>AMOS</Japanese>
<English>AMOS Container</English>
<Japanese>AMOS コンテナ</Japanese>
<Korean>AMOS 컨테이너</Korean>
<German>AMOS Container</German>
<Italian>AMOS Container</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_base_Name">
<English>Drone40</English>
<Japanese>ドローン40</Japanese>
<Korean>드론40</Korean>
<German>Drone40</German>
<Italian>Drone40</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_Name">
<English>Drone40 Scout</English>
<Japanese>ドローン40 偵察型</Japanese>
<Korean>드론40 정찰</Korean>
<German>Drone40 Scout</German>
<Italian>Drone40 Scout</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_he_Name">
<English>Drone40 HE</English>
<Japanese>ドローン40 榴弾</Japanese>
<Korean>드론40 고폭</Korean>
<German>Drone40 HE</German>
<Italian>Drone40 HE</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_white_Name">
<English>Drone40 Smoke (White)</English>
<Japanese>ドローン40 発煙弾 (白)</Japanese>
<Korean>드론40 연막 (백색)</Korean>
<German>Drone40 Smoke (Weiß)</German>
<Italian>Drone40 Smoke (Bianco)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_blue_Name">
<English>Drone40 Smoke (Blue)</English>
<Japanese>ドローン40 発煙弾 (青)</Japanese>
<Korean>드론40 연막 (청색)</Korean>
<German>Drone40 Smoke (Blau)</German>
<Italian>Drone40 Smoke (Blu)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_red_Name">
<English>Drone40 Smoke (Red)</English>
<Japanese>ドローン40 発煙弾 (赤)</Japanese>
<Korean>드론40 연막 (적색)</Korean>
<German>Drone40 Smoke (Rot)</German>
<Italian>Drone40 Smoke (Rosso)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_green_Name">
<English>Drone40 Smoke (Green)</English>
<Japanese>ドローン40 発煙弾 (緑)</Japanese>
<Korean>드론40 연막 (녹색)</Korean>
<German>Drone40 Smoke (Grün)</German>
<Italian>Drone40 Smoke (Verde)</Italian>
</Key>
<Key ID="STR_ACE_Compat_RF_RealisticNames_rc40_orange_Name">
<English>Drone40 Smoke (Orange)</English>
<Japanese>ドローン40 発煙弾 (橙)</Japanese>
<Korean>드론40 연막 (주황색)</Korean>
<German>Drone40 Smoke (Orange)</German>
<Italian>Drone40 Smoke (Arancione)</Italian>
</Key>
</Package>
</Project>

View File

@ -1,11 +0,0 @@
class CfgMagazineWells {
class ace_hellfire_K {
ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_k)};
};
class ace_hellfire_N {
ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_n)};
};
class ace_hellfire_L {
ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_l)};
};
};

View File

@ -38,21 +38,4 @@ class cfgMagazines {
EGVAR(overpressure,range) = 0;
EGVAR(overpressure,damage) = 0;
};
class rhs_mag_AGM114K_2;
class GVAR(pylon_mag_2rnd_hellfire_k): rhs_mag_AGM114K_2 {
displayName = "2x AGM-114K [ACE]";
pylonWeapon = "ace_hellfire_launcher";
ammo = "ACE_Hellfire_AGM114K";
};
class GVAR(pylon_mag_2rnd_hellfire_n): rhs_mag_AGM114K_2 {
displayName = "2x AGM-114N [ACE]";
pylonWeapon = "ace_hellfire_launcher_N";
ammo = "ACE_Hellfire_AGM114N";
};
class GVAR(pylon_mag_2rnd_hellfire_l): rhs_mag_AGM114K_2 {
displayName = "2x AGM-114L [ACE]";
pylonWeapon = "ace_hellfire_launcher_L";
ammo = "ACE_Hellfire_AGM114L";
};
};

View File

@ -0,0 +1,8 @@
class CfgAmmo {
// Use RHS Hellfire 3D Model on ACE Hellfires
class M_Scalpel_AT;
class ACE_Hellfire_AGM114K: M_Scalpel_AT {
model = "\rhsusf\addons\rhsusf_airweapons\proxyammo\rhsusf_m_AGM114K_fly";
proxyShape = "\rhsusf\addons\rhsusf_airweapons\proxyammo\rhsusf_m_AGM114K";
};
};

View File

@ -0,0 +1,11 @@
class CfgMagazineWells {
class ace_hellfire_K {
ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_k), QGVAR(pylon_mag_4rnd_hellfire_k)};
};
class ace_hellfire_N {
ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_n), QGVAR(pylon_mag_4rnd_hellfire_n)};
};
class ace_hellfire_L {
ADDON[] = {QGVAR(pylon_mag_2rnd_hellfire_l), QGVAR(pylon_mag_4rnd_hellfire_l)};
};
};

View File

@ -0,0 +1,37 @@
class CfgMagazines {
// 2x ACE Hellfire racks
class rhs_mag_AGM114K_2;
class GVAR(pylon_mag_2rnd_hellfire_k): rhs_mag_AGM114K_2 {
displayName = "2x AGM-114K [ACE]";
pylonWeapon = "ace_hellfire_launcher";
ammo = "ACE_Hellfire_AGM114K";
};
class GVAR(pylon_mag_2rnd_hellfire_n): rhs_mag_AGM114K_2 {
displayName = "2x AGM-114N [ACE]";
pylonWeapon = "ace_hellfire_launcher_N";
ammo = "ACE_Hellfire_AGM114N";
};
class GVAR(pylon_mag_2rnd_hellfire_l): rhs_mag_AGM114K_2 {
displayName = "2x AGM-114L [ACE]";
pylonWeapon = "ace_hellfire_launcher_L";
ammo = "ACE_Hellfire_AGM114L";
};
// 4x ACE Hellfire racks that align better on RHS Apaches and Blackhawks than the standard ACE 4x racks
class rhs_mag_AGM114K_4;
class GVAR(pylon_mag_4rnd_hellfire_k): rhs_mag_AGM114K_4 {
displayName = "4x AGM-114K [ACE]";
pylonWeapon = "ace_hellfire_launcher";
ammo = "ACE_Hellfire_AGM114K";
};
class GVAR(pylon_mag_4rnd_hellfire_n): rhs_mag_AGM114K_4 {
displayName = "4x AGM-114N [ACE]";
pylonWeapon = "ace_hellfire_launcher_N";
ammo = "ACE_Hellfire_AGM114N";
};
class GVAR(pylon_mag_4rnd_hellfire_l): rhs_mag_AGM114K_4 {
displayName = "4x AGM-114L [ACE]";
pylonWeapon = "ace_hellfire_launcher_L";
ammo = "ACE_Hellfire_AGM114L";
};
};

View File

@ -0,0 +1,25 @@
#include "script_component.hpp"
class CfgPatches {
class SUBADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {
"rhsusf_main_loadorder",
"ace_hellfire"
};
skipWhenMissingDependencies = 1;
author = ECSTRING(common,ACETeam);
authors[] = {};
url = ECSTRING(main,URL);
VERSION_CONFIG;
addonRootClass = QUOTE(ADDON);
};
};
#include "CfgAmmo.hpp"
#include "CfgMagazines.hpp"
#include "CfgMagazineWells.hpp"

View File

@ -0,0 +1,3 @@
#define SUBCOMPONENT hellfire
#define SUBCOMPONENT_BEAUTIFIED Hellfire
#include "..\script_component.hpp"

View File

@ -19,7 +19,6 @@ class CfgPatches {
#include "CfgAmmo.hpp"
#include "CfgEventHandlers.hpp"
#include "CfgMagazines.hpp"
#include "CfgMagazineWells.hpp"
#include "CfgWeapons.hpp"
#include "CfgVehicles.hpp"
#include "CfgGlasses.hpp"

View File

@ -18,8 +18,6 @@
* Public: No
*/
#define BURN_THRESHOLD 1
params ["_unit", "_damages"];
TRACE_2("woundsHandlerIncendiary",_unit,_damages);
@ -32,9 +30,7 @@ private _fireDamage = 0;
private _intensity = linearConversion [0, 20, _fireDamage, 0, 10, true];
TRACE_2("",_intensity,_fireDamage);
if (_intensity > BURN_THRESHOLD) then {
TRACE_2("Setting unit ablaze",_intensity,BURN_THRESHOLD);
["ace_fire_burn", [_unit, _intensity]] call CBA_fnc_globalEvent;
};
// Let fire handle if unit is set ablaze or not
[QEGVAR(fire,burn), [_unit, _intensity]] call CBA_fnc_localEvent;
_this // return

View File

@ -18,8 +18,6 @@
* Public: No
*/
#define BURN_THRESHOLD 1
params ["_unit", "_damages"];
TRACE_2("woundsHandlerIncendiary",_unit,_damages);
@ -32,9 +30,7 @@ private _fireDamage = 0;
private _intensity = linearConversion [0, 20, _fireDamage, 0, 10, true];
TRACE_2("",_intensity,_fireDamage);
if (_intensity > BURN_THRESHOLD) then {
TRACE_2("Setting unit ablaze",_intensity,BURN_THRESHOLD);
["ace_fire_burn", [_unit, _intensity]] call CBA_fnc_globalEvent;
};
// Let fire handle if unit is set ablaze or not
[QEGVAR(fire,burn), [_unit, _intensity]] call CBA_fnc_localEvent;
_this // return

View File

@ -259,10 +259,16 @@
<Key ID="STR_ACE_Compat_WS_RealisticNames_SLR_Para_Name">
<English>FN FAL OSW Para</English>
<Japanese>FN FAL OSW パラ</Japanese>
<Korean>FN FAL OSW 파라</Korean>
<German>FN FAL OSW Fallschirmjäger</German>
<Italian>FN FAL OSW Para</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_SLR_Para_Snake_Name">
<English>FN FAL OSW Para (Snake)</English>
<Japanese>FN FAL OSW パラ (ヘビ柄迷彩)</Japanese>
<Korean>FN FAL OSW 파라 (뱀 위장)</Korean>
<German>FN FAL OSW Fallschirmjäger (Schlange)</German>
<Italian>FN FAL OSW Para (Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_Velko_R4_Name">
<English>Vektor R4</English>
@ -459,154 +465,268 @@
<Key ID="STR_ACE_Compat_WS_RealisticNames_gm6_snake_Name">
<English>GM6 Lynx (Snake)</English>
<Japanese>GM6 リンクス (ヘビ柄迷彩)</Japanese>
<Korean>GM6 링스 (뱀 위장)</Korean>
<German>GM6 Lynx (Schlange)</German>
<Italian>GM6 Lynx (Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_rpg32_tan_Name">
<English>RPG-32 (Sand)</English>
<Japanese>RPG-32 (サンド)</Japanese>
<Korean>RPG-32 (모래)</Korean>
<German>RPG-32 (Sand)</German>
<Italian>RPG-32 (Sabbia)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_arco_hex_Name">
<English>ELCAN SpecterOS (Hex)</English>
<Japanese>ELCAN SpecterOS (六角形迷彩)</Japanese>
<Korean>엘칸 스펙터OS (육각)</Korean>
<German>ELCAN SpecterOS (Hex)</German>
<Italian>ELCAN SpecterOS (Hex)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_holosight_snake_Name">
<English>EOTech XPS3 (Snake)</English>
<Japanese>EOTech XPS3 (ヘビ柄迷彩)</Japanese>
<Korean>이오텍 XPS3 (뱀 위장)</Korean>
<German>EOTech XPS3 (Schlange)</German>
<Italian>EOTech XPS3 (Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_holosight_snake_smg_Name">
<English>EOTech XPS3 SMG (Snake)</English>
<Japanese>EOTech XPS3 SMG (ヘビ柄迷彩)</Japanese>
<Korean>이오텍 XPS3 SMG (뱀 위장)</Korean>
<German>EOTech XPS3 SMG (Schlange)</German>
<Italian>EOTech XPS3 SMG (Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_hamr_arid_Name">
<English>Leupold Mark 4 HAMR (Arid)</English>
<Japanese>Leupold Mark 4 HAMR (乾燥地帯迷彩)</Japanese>
<Korean>류폴드 마크 4 HAMR (건조)</Korean>
<German>Leupold Mark 4 HAMR (Trocken)</German>
<Italian>Leupold Mark 4 HAMR (Arido)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_hamr_lush_Name">
<English>Leupold Mark 4 HAMR (Lush)</English>
<Japanese>Leupold Mark 4 HAMR (緑地迷彩)</Japanese>
<Korean>류폴드 마크 4 HAMR (초목)</Korean>
<German>Leupold Mark 4 HAMR (Grün)</German>
<Italian>Leupold Mark 4 HAMR (Verdeggiante)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_hamr_sand_Name">
<English>Leupold Mark 4 HAMR (Sand)</English>
<Japanese>Leupold Mark 4 HAMR (サンド)</Japanese>
<Korean>류폴드 마크 4 HAMR (모래)</Korean>
<German>Leupold Mark 4 HAMR (Sand)</German>
<Italian>Leupold Mark 4 HAMR (Sabbia)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_hamr_snake_Name">
<English>Leupold Mark 4 HAMR (Snake)</English>
<Japanese>Leupold Mark 4 HAMR (ヘビ柄迷彩)</Japanese>
<Korean>류폴드 마크 4 HAMR (뱀 위장)</Korean>
<German>Leupold Mark 4 HAMR (Schlange)</German>
<Italian>Leupold Mark 4 HAMR (Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_high_black_Name">
<English>Aimpoint Micro R-1 (High, Black)</English>
<Japanese>Aimpoint マイクロ R-1 (ハイマウント、ブラック)</Japanese>
<Korean>에임포인트 마이크로 R-1 (높음, 검정)</Korean>
<German>Aimpoint Micro R-1 (Hoch, Schwarz)</German>
<Italian>Aimpoint Micro R-1 (Alto, Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_high_khaki_Name">
<English>Aimpoint Micro R-1 (High, Khaki)</English>
<Japanese>Aimpoint マイクロ R-1 (ハイマウント、カーキ)</Japanese>
<Korean>에임포인트 마이크로 R-1 (높음, 카키)</Korean>
<German>Aimpoint Micro R-1 (Hoch, Khaki)</German>
<Italian>Aimpoint Micro R-1 (Alto, Cachi)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_high_sand_Name">
<English>Aimpoint Micro R-1 (High, Sand)</English>
<Japanese>Aimpoint マイクロ R-1 (ハイマウント、サンド)</Japanese>
<Korean>에임포인트 마이크로 R-1 (높음, 모래)</Korean>
<German>Aimpoint Micro R-1 (Hoch, Sand)</German>
<Italian>Aimpoint Micro R-1 (Alto, Sabbia)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_high_snake_Name">
<English>Aimpoint Micro R-1 (High, Snake)</English>
<Japanese>Aimpoint マイクロ R-1 (ハイマウント、ヘビ柄迷彩)</Japanese>
<Korean>에임포인트 마이크로 R-1 (높음, 뱀 위장)</Korean>
<German>Aimpoint Micro R-1 (Hoch, Schlange)</German>
<Italian>Aimpoint Micro R-1 (Alto, Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_high_arid_Name">
<English>Aimpoint Micro R-1 (High, Arid)</English>
<Japanese>Aimpoint マイクロ R-1 (ハイマウント、乾燥地帯迷彩)</Japanese>
<Korean>에임포인트 마이크로 R-1 (높음, 건조)</Korean>
<German>Aimpoint Micro R-1 (Hoch, Trocken)</German>
<Italian>Aimpoint Micro R-1 (Alto, Arido)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_high_lush_Name">
<English>Aimpoint Micro R-1 (High, Lush)</English>
<Japanese>Aimpoint マイクロ R-1 (ハイマウント、緑地迷彩)</Japanese>
<Korean>에임포인트 마이크로 R-1 (높음, 초목)</Korean>
<German>Aimpoint Micro R-1 (Hoch, Grün)</German>
<Italian>Aimpoint Micro R-1 (Alto, Verdeggiante)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_high_black_sand_Name">
<English>Aimpoint Micro R-1 (High, Black/Sand)</English>
<Japanese>Aimpoint マイクロ R-1 (ハイマウント、ブラック/サンド)</Japanese>
<Korean>에임포인트 마이크로 R-1 (높음, 검정/모래)</Korean>
<German>Aimpoint Micro R-1 (Hoch, Schwarz/Sand)</German>
<Italian>Aimpoint Micro R-1 (Alto, Nero/Sabbia)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_low_black_Name">
<English>Aimpoint Micro R-1 (Low, Black)</English>
<Japanese>Aimpoint マイクロ R-1 (ローマウント、ブラック)</Japanese>
<Korean>에임포인트 마이크로 R-1 (낮음, 검정)</Korean>
<German>Aimpoint Micro R-1 (Tief, Schwarz)</German>
<Italian>Aimpoint Micro R-1 (Basso, Nero)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_low_khaki_Name">
<English>Aimpoint Micro R-1 (Low, Khaki)</English>
<Japanese>Aimpoint マイクロ R-1 (ローマウント、カーキ)</Japanese>
<Korean>에임포인트 마이크로 R-1 (낮음, 카키)</Korean>
<German>Aimpoint Micro R-1 (Tief, Khaki)</German>
<Italian>Aimpoint Micro R-1 (Basso, Cachi)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_low_sand_Name">
<English>Aimpoint Micro R-1 (Low, Sand)</English>
<Japanese>Aimpoint マイクロ R-1 (ローマウント、サンド)</Japanese>
<Korean>에임포인트 마이크로 R-1 (낮음, 모래)</Korean>
<German>Aimpoint Micro R-1 (Tief, Sand)</German>
<Italian>Aimpoint Micro R-1 (Basso, Sabbia)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_low_snake_Name">
<English>Aimpoint Micro R-1 (Low, Snake)</English>
<Japanese>Aimpoint マイクロ R-1 (ローマウント、ヘビ柄迷彩)</Japanese>
<Korean>에임포인트 마이크로 R-1 (낮음, 뱀 위장)</Korean>
<German>Aimpoint Micro R-1 (Tief, Schlange)</German>
<Italian>Aimpoint Micro R-1 (Basso, Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_low_arid_Name">
<English>Aimpoint Micro R-1 (Low, Arid)</English>
<Japanese>Aimpoint マイクロ R-1 (ローマウント、乾燥地帯迷彩)</Japanese>
<Korean>에임포인트 마이크로 R-1 (낮음, 건조)</Korean>
<German>Aimpoint Micro R-1 (Tief, Trocken)</German>
<Italian>Aimpoint Micro R-1 (Basso, Arido)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_r1_low_lush_Name">
<English>Aimpoint Micro R-1 (Low, Lush)</English>
<Japanese>Aimpoint マイクロ R-1 (ローマウント、緑地迷彩)</Japanese>
<Korean>에임포인트 마이크로 R-1 (낮음, 초목)</Korean>
<German>Aimpoint Micro R-1 (Tief, Grün)</German>
<Italian>Aimpoint Micro R-1 (Basso, Verdeggiante)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_dms_snake_Name">
<English>Burris XTR II (Snake)</English>
<Japanese>Burris XTR II (ヘビ柄迷彩)</Japanese>
<Korean>버리스 XTR II (뱀 위장)</Korean>
<German>Burris XTR II (Schlange)</German>
<Italian>Burris XTR II (Serpe)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_apc_wheeled_01_atgm_Name">
<English>Badger IFV (ATGM)</English>
<Japanese>バジャー IFV (ATGM)</Japanese>
<Korean>뱃져 보병전투차 (대전차미사일)</Korean>
<German>Badger IFV (PzAbw)</German>
<Italian>Badger IFV (ATGM)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_apc_wheeled_01_command_Name">
<English>Badger IFV (Command)</English>
<Japanese>バジャー IFV (指揮)</Japanese>
<Korean>뱃져 보병전투차 (지휘)</Korean>
<German>Badger IFV (Kommando)</German>
<Italian>Badger IFV (Comando)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_apc_wheeled_01_mortar_Name">
<English>Badger IFV (Mortar)</English>
<Japanese>バジャー IFV (迫撃砲)</Japanese>
<Korean>뱃져 보병전투차 (자주박격포)</Korean>
<German>Badger IFV (Mörser)</German>
<Italian>Badger IFV (Mortaio)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_truck_02_aa_Name">
<English>KamAZ (Zu-23-2)</English>
<Japanese>KamAZ (Zu-23-2)</Japanese>
<Korean>카마즈 (ZU-23-2)</Korean>
<German>KamAZ (Zu-23-2)</German>
<Italian>KamAZ (Zu-23-2)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_truck_02_cargo_Name">
<English>KamAZ Cargo</English>
<Japanese>KamAZ 貨物</Japanese>
<Korean>카마즈 화물</Korean>
<German>KamAZ Fracht</German>
<Italian>KamAZ Carico</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_truck_02_repair_Name">
<English>KamAZ Repair</English>
<Japanese>KamAZ 修理</Japanese>
<Korean>카마즈 정비</Korean>
<German>KamAZ Instandsetzung</German>
<Italian>KamAZ Riparazione</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_truck_02_racing_Name">
<English>KamAZ Racing</English>
<Japanese>KamAZ レース仕様</Japanese>
<Korean>카마즈 경주용</Korean>
<German>KamAZ Rennlaster</German>
<Italian>KamAZ da corsa</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_truck_02_ammo_Name">
<English>KamAZ Ammo</English>
<Japanese>KamAZ 弾薬</Japanese>
<Korean>카마즈 탄약</Korean>
<German>KamAZ Munition</German>
<Italian>KamAZ Munizioni</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_truck_02_flatbed_Name">
<English>KamAZ Flatbed</English>
<Japanese>KamAZ フラットベッド</Japanese>
<Korean>카마즈 플랫베드</Korean>
<German>KamAZ Flachbett</German>
<Italian>KamAZ Pianale</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_heli_transport_02_Name">
<English>AW101 Merlin</English>
<Japanese>AW101 マーリン</Japanese>
<Korean>AW101 멀린</Korean>
<German>AW101 Merlin</German>
<Italian>AW101 Merlin</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_apc_tracked_02_Name">
<English>BM-2T Stalker (Bumerang-BM)</English>
<Japanese>BM-2T ストーカー (ブーメランク-BM)</Japanese>
<Korean>BM-2T 스토커 (부메랑-BM)</Korean>
<German>BM-2T Stalker (Bumerang-BM)</German>
<Italian>BM-2T Stalker (Bumerang-BM)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_apc_wheeled_02_hmg_Name">
<English>Otokar ARMA (HMG)</English>
<Japanese>オトカ アルマ (HMG)</Japanese>
<Korean>오토카르 아르마 APC (중기관총)</Korean>
<German>Otokar ARMA (HMG)</German>
<Italian>Otokar ARMA (HMG)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_apc_wheeled_02_unarmed_Name">
<English>Otokar ARMA (Unarmed)</English>
<Japanese>オトカ アルマ (非武装)</Japanese>
<Korean>오토카르 아르마 APC (비무장)</Korean>
<German>Otokar ARMA (Unbewaffnet)</German>
<Italian>Otokar ARMA (Disarmato)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_heli_light_02_armed_Name">
<English>Ka-60 Kasatka (UP)</English>
<Japanese>Ka-60 カサートカ (UP)</Japanese>
<Korean>Ka-60 카사트카 (UP)</Korean>
<German>Ka-60 Kasatka (UP)</German>
<Italian>Ka-60 Kasatka (UP)</Italian>
</Key>
<Key ID="STR_ACE_Compat_WS_RealisticNames_heli_light_02_unarmed_Name">
<English>Ka-60 Kasatka (UP, Unarmed)</English>
<Japanese>Ka-60 カサートカ (UP、非武装)</Japanese>
<Korean>Ka-60 카사트카 (UP, 비무장))</Korean>
<German>Ka-60 Kasatka (UP, Unbewaffnet)</German>
<Italian>Ka-60 Kasatka (UP, Disarmato)</Italian>
</Key>
</Package>
</Project>

View File

@ -30,7 +30,7 @@
<Hungarian>Concertina wire coil</Hungarian>
<Portuguese>Bobina de arame farpado</Portuguese>
<Japanese>鉄条網コイル</Japanese>
<Korean>코일형 철조망</Korean>
<Korean>윤형철조망</Korean>
<Chinese>鐵絲網捲</Chinese>
<Chinesesimp>铁丝网卷</Chinesesimp>
<Turkish>Bıçaklı Tel Rulo</Turkish>

View File

@ -45,7 +45,7 @@ class CfgSounds {
class GVAR(shotsubmunitions_close_3): GVAR(shotbullet_close_3) {
sound[] = {QPATHTOF(sounds\shotbullet\close_3.wss), VOLUME, PITCH, 1600};
};
class GVAR(shotsubmunitions_mid_1): GVAR(shotbullet_far_1) {
class GVAR(shotsubmunitions_mid_1): GVAR(shotbullet_mid_1) {
sound[] = {QPATHTOF(sounds\shotbullet\mid_1.wss), VOLUME, PITCH, 1600};
};
class GVAR(shotsubmunitions_mid_2): GVAR(shotbullet_mid_2) {

View File

@ -175,7 +175,7 @@ if (_delayBetweenSmokeAndFire) then {
if (["ace_fire"] call EFUNC(common,isModLoaded)) then {
// Use current intensity, in case GVAR(cookoffDuration) is very large and only 1 flameout stage happens
{
[QEGVAR(fire,burn), [_x, _intensity * 1.5, _instigator]] call CBA_fnc_globalEvent;
[QEGVAR(fire,burn), [_x, _intensity * 1.5, _instigator], _x] call CBA_fnc_targetEvent;
} forEach (crew _vehicle);
};

View File

@ -4,11 +4,11 @@
<Key ID="STR_ACE_CookOff_category_displayName">
<English>ACE Cook-off</English>
<Spanish>ACE Detonación inducida por calor</Spanish>
<Italian>ACE Detonazione Munizioni</Italian>
<Italian>ACE Esplosioni di Munizioni</Italian>
<Chinese>ACE 殉爆效果</Chinese>
<Chinesesimp>ACE 殉爆效果</Chinesesimp>
<Japanese>ACE 誘爆</Japanese>
<Korean>ACE 쿡오프</Korean>
<Korean>ACE 유폭</Korean>
<German>ACE Durchzündung</German>
<French>ACE Auto-inflammation</French>
<Polish>ACE Samozapłon</Polish>
@ -20,35 +20,53 @@
<English>Enable vehicle cook-off fire</English>
<Japanese>車両の誘爆火災を有効化</Japanese>
<Russian>Вкл. возгорание техники</Russian>
<Korean>차량 유폭 화재를 활성화합니다</Korean>
<Italian>Abilita incendio dei veicoli</Italian>
<German>Aktiviert Fahrzeug Munitionsbrand</German>
</Key>
<Key ID="STR_ACE_CookOff_enableFire_tooltip">
<English>Enables vehicle cook-off fire effects.\nThis doesn't include ammunition detonations.</English>
<Japanese>車両の誘爆火災エフェクトを有効化します。\nこれには弾薬の爆発は含まれません。</Japanese>
<Russian>Вкл. эффект горения техники. \nНе включает детонацию боекомплекта</Russian>
<Korean>차량 유폭 효과를 활성화합니다.\n여기엔 탄약 유폭이 포함되지 않습니다.</Korean>
<Italian>Abilita effetti di incendio del veicolo dovuto all'esplosione delle munizioni.\nQuesto non include gli effetti di esplosione.</Italian>
<German>Aktiviert Fahrzeug Brandeffekte durch Durchzündung.\nExplosionseffekte sind nicht mit einbegriffen.</German>
</Key>
<Key ID="STR_ACE_CookOff_cookoffDuration_name">
<English>Vehicle cook-off fire duration multiplier</English>
<Japanese>車両の誘爆火災の持続時間倍率</Japanese>
<Russian>Увел. продолжительности горения техники</Russian>
<Korean>차량 유폭 화재 지속 시간 계수</Korean>
<Italian>Coefficiente di durata incendio dei veicoli</Italian>
<German>Fahrzeugbrand Dauer-Multiplikator</German>
</Key>
<Key ID="STR_ACE_CookOff_cookoffDuration_tooltip">
<English>Multiplier for how long vehicle cook-off fire lasts.\nSetting to 0 will disable vehicle cook-off fire.</English>
<Japanese>車両の誘爆火災の持続時間をどのくらいの長さにするかの倍率。\n0に設定すると車両の誘爆火災が無効化されます。</Japanese>
<Russian>Увел. продолжительности горения техники. \nУстановка значения на 0 выключает возгорание техники.</Russian>
<Korean>차량 유폭 화재가 지속되는 시간에 대한 계수입니다.\n0으로 설정하면 차량 쿸오프 화재가 비활성화됩니다.</Korean>
<Italian>Coefficiente di durata degli incendi dei veicoli.\nImpostarlo su 0 disabilita incendi dei veicoli.</Italian>
<German>Multiplikator der Fahrzeugbrand Dauer.\nIhn auf 0 zu setzen wird Munitionsbrände deaktivieren.</German>
</Key>
<Key ID="STR_ACE_CookOff_probabilityCoef_name">
<English>Vehicle cook-off fire probability multiplier</English>
<Japanese>車両の誘爆火災の可能性倍率</Japanese>
<Russian>Возможность усиления пожара при детонации техники</Russian>
<Korean>차량 유폭 화재 확률 계수</Korean>
<Italian>Probabilità di incendio dei veicoli</Italian>
<German>Fahrzeug Munitionsbrand Wahrscheinlichkeit-Multiplikator</German>
</Key>
<Key ID="STR_ACE_CookOff_probabilityCoef_tooltip">
<English>Multiplier for vehicle cook-off fire probability. Higher value results in higher cook-off probability.\nSetting to 0 will disable vehicle cook-off fire.</English>
<Japanese>車両の誘爆火災がどのくらいの可能性で発生するかの倍率。高い数値は高い誘爆の可能性につながります。\n0に設定すると車両の誘爆火災が無効化されます。</Japanese>
<Russian>Увел. вероятности возникновения возгорания техники. Большое значение указывает на высокую вероятность детонации. \nУстановка значения 0 предотвращает возгорание техники.</Russian>
<Korean>차량 유폭 화재 확률에 대한 계수입니다. 값이 높을 수록 유폭 확률이 높아집니다.\n0으로 설정하면 차량 유폭 화재가 비활성화됩니다.</Korean>
<Italian>Coefficiente di probabilità degli incendi dei veicoli.\nValori maggiori aumentano la probabilità di incendi.\nImpostarlo su 0 disabilita incendi dei veicoli.</Italian>
<German>Multiplikator der Fahrzeugbrand Wahrscheinlichkeit.\nHöhere Werte erhöhen die Wahrscheinlichkeit.\nEin Null-Wert wird Munitionsbrände deaktivieren.</German>
</Key>
<Key ID="STR_ACE_CookOff_destroyVehicleAfterCookoff_name">
<English>Destroy vehicles after cook-off</English>
<Korean>쿡오프 후 차량 파괴</Korean>
<Korean>유폭 후 차량 파괴</Korean>
<Chinesesimp>殉爆发生后摧毁载具</Chinesesimp>
<Russian>Уничтожать технику после детонации</Russian>
<Spanish>Destruir vehículos tras la detonación inducida por calor</Spanish>
@ -65,7 +83,7 @@
<Polish>Kontroluje, czy pojazdy będą zawsze niszczone po samozapłonie.</Polish>
<German>Steuert, ob Fahrzeuge nach dem Durchzünden immer zerstört werden.</German>
<Italian>Determina se veicoli saranno sempre distrutti dall'esplosione delle munizioni.</Italian>
<Korean>쿡오프 후 차량이 항상 파괴되는지 여부를 조정합니다.</Korean>
<Korean>유폭 후 차량이 항상 파괴되는지 여부를 조정합니다.</Korean>
<French>Contrôle si les véhicules seront toujours détruits après l'auto-inflammation.</French>
<Portuguese>Define se os veículos serão sempre destruídos após cozinhamento.</Portuguese>
<Russian>Определяет, всегда ли транспортные средства будут уничтожаться после детонации.</Russian>
@ -75,18 +93,24 @@
<English>Enable vehicle ammo cook-off</English>
<Japanese>車両弾薬の誘爆を有効化</Japanese>
<Russian>Вкл. детонацию боеприпасов в технике.</Russian>
<Korean>차량 내 탄약 유폭 활성화</Korean>
<Italian>Abilita esplosioni delle munizioni dei veicoli</Italian>
<German>Aktiviert Fahrzeug Munitionsdurchzündung</German>
</Key>
<Key ID="STR_ACE_CookOff_enableAmmoCookoff_tooltip">
<English>Enables cooking off of vehicle ammunition. Fires ammunition projectiles while vehicle has ammunition remaining.\nThis doesn't include fire effects.</English>
<Japanese>車両弾薬の誘爆を有効化します。車両に積載されたままの弾薬と弾頭が発射されます。\nこれには火災エフェクトは含まれません。</Japanese>
<Russian>Вкл. детонацию боеприпасов на технике. Боеприпасы и боеголовки, которые остаются заряженными на транспортном средстве, будут приведены в действие. \nЭто не включает эффекты пожара.</Russian>
<Korean>차량 내 탄약 유폭을 활성화합니다. 차량에 탄약이 남아 있는 동안 탄약 발사체를 발사합니다.\n여기엔 화재 효과가 포함되지 않습니다.</Korean>
<Italian>Abilita l'esplosione delle munizioni dei veicoli. Spara via pezzi di munizioni se il veicolo ha ancora munizioni rimanenti.\nNon include gli effetti di fuoco.</Italian>
<German>Aktiviert Durchzündung von Fahrzeugmunition. Schleudert Munitionsfragmente umher wenn das Fahrzeug noch Munition an Bord hat.\nBrandeffekte sind nicht mit einbegriffen.</German>
</Key>
<Key ID="STR_ACE_CookOff_enableBoxCookoff_name">
<English>Enable ammo box cook-off</English>
<Spanish>Habilitar detonación inducida por calor en las cajas de munición</Spanish>
<Japanese>弾薬箱の誘爆を有効化</Japanese>
<German>Durchzündung für Munitionskisten ermöglichen</German>
<Korean>탄약 상자 쿡오프 현상 활성화</Korean>
<Korean>탄약 상자 유폭 현상 활성화</Korean>
<Polish>Aktywuj samozapłon skrzyń z amunicją</Polish>
<French>Auto-inflammation des caisses de munitions</French>
<Italian>Abilita esplosione casse munizioni</Italian>
@ -100,16 +124,25 @@
<English>Enables cooking off of ammo boxes.\nThis doesn't include fire effects.</English>
<Japanese>弾薬箱の誘爆を有効化します。\nこれには火災エフェクトは含まれません。</Japanese>
<Russian>Вкл. детонацию ящика с боеприпасами. \nЭто не включает эффекты огня.</Russian>
<Korean>탄약 상자 유폭을 활성화합니다.\n여기엔 화재 효과가 포함되지 않습니다.</Korean>
<Italian>Abilita esplosioni delle casse di munizioni.\nNon include effetti di fuoco.</Italian>
<German>Aktiviert Munitionskisten Durchzündung.\nBrandeffekte sind nicht mit einbegriffen.</German>
</Key>
<Key ID="STR_ACE_CookOff_ammoCookoffDuration_name">
<English>Ammo cook-off duration multiplier</English>
<Japanese>弾薬の誘爆の持続時間倍率</Japanese>
<Russian>Увеличение продолжительности детонации боеприпасов.</Russian>
<Korean>탄약 유폭 시간 계수</Korean>
<Italian>Coefficiente di durata esplisioni di munizioni</Italian>
<German>Fahrzeug Munitionsdurchzündung Dauer-Multiplikator</German>
</Key>
<Key ID="STR_ACE_CookOff_ammoCookoffDuration_tooltip">
<English>Multiplier for how long ammunition cook-off lasts, for both vehicles and ammo boxes.\nSetting to 0 will disable ammo cook-off for both vehicles and ammo boxes.</English>
<Japanese>弾薬の誘爆の持続時間をどのくらいの長さにするかの倍率。車両弾薬と弾薬箱どちらにも影響します。\n0に設定すると弾薬の誘爆が無効化されます。</Japanese>
<Russian>Увеличение продолжительности детонации боеприпасов. Это влияет как на боеприпасы в технике, так и на ящики с боеприпасами. \nУстановка значения 0 отключает детонацию боеприпасов.</Russian>
<Korean>차량과 탄약 상자 모두에 대해 탄약 유폭이 지속되는 시간에 대한 계수입니다.\n0으로 설정하면 차량과 탄약 상자 모두에 대해 탄약 유폭이 비활성화됩니다.</Korean>
<Italian>Coefficiente della durata di esplosioni delle munizioni, sia per veicoli che casse.\nImpostarlo su 0 disabilita esplosioni di veicoli e casse.</Italian>
<German>Multiplikator der Munitionsdurchzündungs-Dauer, gilt für Fahrzeuge und Munitionskisten.\nIhn auf 0 zu setzen wird Durchzünden deaktivieren.</German>
</Key>
<Key ID="STR_ACE_CookOff_removeAmmoDuringCookoff_name">
<English>Enable ammo removal during cook-off</English>
@ -119,7 +152,7 @@
<Italian>Abilita rimozione munizioni dopo l'esplosione</Italian>
<Polish>Włącz/Wyłącz usuwanie amunicji podczas samozapłonu</Polish>
<Chinesesimp>启用/禁用殉爆过程中的弹药移除功能</Chinesesimp>
<Korean>쿡오프시 탄약 제거 활성화/비활성화</Korean>
<Korean>유폭 시 탄약 제거 활성화/비활성화</Korean>
<Russian>Вкл. удаление боеприпасов из-за детонации</Russian>
<Spanish>Habilita/Deshabilita ka eliminación de munición durante la detonación inducida por calor</Spanish>
</Key>
@ -129,6 +162,8 @@
<German>Entfernt Munition während dem Durchzünden der Munition eines Fahrzeuges.</German>
<Japanese>誘爆によって全ての弾薬を除去します。</Japanese>
<Russian>Все боеприпасы уничтожаются путем подрыва.</Russian>
<Korean>유폭 중 모든 탄약을 제거합니다.</Korean>
<Italian>Rimuovi le munizioni dal veicolo durante le esplosioni.</Italian>
</Key>
</Package>
</Project>

View File

@ -5,7 +5,7 @@
*
* Arguments:
* 0: Target Tripod <OBJECT>
* 0: Player <OBJECT>
* 1: Player <OBJECT>
*
* Return Value:
* Wether or not you can deploy the weapon <BOOL>
@ -16,9 +16,8 @@
* Public: No
*/
params ["_target", "_player", "", "_carryWeaponClassname"];
if (isNil "_carryWeaponClassname") then { _carryWeaponClassname = secondaryWeapon _player };
params ["_target", "_player"];
// If the current launcher has a config-value that defines the tripod, it is a CSW
(alive _target) &&
{(getText(configFile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON) >> "assembleTo" >> (typeOf _target))) != ""}
{(getText (configFile >> "CfgWeapons" >> secondaryWeapon _player >> QUOTE(ADDON) >> "assembleTo" >> typeOf _target)) != ""}

View File

@ -19,7 +19,5 @@ params ["_staticWeapon"];
// Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default]
private _assemblyMode = [false, true, true, GVAR(defaultAssemblyMode)] select (_staticWeapon getVariable [QGVAR(assemblyMode), 3]);
private _notCrewed = (crew _staticWeapon) isEqualTo [];
private _deadCrew = !(alive (gunner _staticWeapon)); // need to eject body???
_assemblyMode && {alive _staticWeapon} && {_notCrewed || _deadCrew}
_assemblyMode && {alive _staticWeapon} && {((crew _staticWeapon) findIf {alive _x && {!unitIsUAV _x}}) == -1} // return

View File

@ -19,16 +19,20 @@
params ["_player"];
TRACE_1("assemble_deployTripod",_player);
// Save magazines and attachments (handle loaded launchers which can become csw like CUP Metis)
private _secondaryWeaponInfo = (getUnitLoadout _player) select 1;
private _secondaryWeaponClassname = _secondaryWeaponInfo deleteAt 0;
// Remove empty entries
_secondaryWeaponInfo = _secondaryWeaponInfo select {_x isNotEqualTo "" && {_x isNotEqualTo []}};
// Remove the tripod from the launcher slot
private _secondaryWeaponClassname = secondaryWeapon _player;
// handle loaded launchers which can become csw like CUP Metis
private _secondaryWeaponMagazine = secondaryWeaponMagazine _player param [0, ""];
_player removeWeaponGlobal _secondaryWeaponClassname;
private _onFinish = {
params ["_args"];
_args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponMagazine"];
TRACE_3("deployTripod finish",_player,_secondaryWeaponClassname,_secondaryWeaponMagazine);
_args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponInfo"];
TRACE_3("deployTripod finish",_player,_secondaryWeaponClassname,_secondaryWeaponInfo);
private _tripodClassname = getText(configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deploy");
@ -36,9 +40,24 @@
private _cswTripod = createVehicle [_tripodClassname, [0, 0, 0], [], 0, "NONE"];
// Because the tripod can be a "full weapon" we disable any data that will allow it to be loaded
_cswTripod setVariable [QGVAR(assemblyMode), 2, true]; // Explicitly set enabled&unload assembly mode and broadcast
if (_secondaryWeaponMagazine isNotEqualTo "") then {
_cswTripod setVariable [QGVAR(secondaryWeaponMagazine), _secondaryWeaponMagazine];
private _secondaryWeaponMagazines = [];
{
// Magazines
if (_x isEqualType []) then {
_secondaryWeaponMagazines pushBack _x;
} else {
// Items
[_player, _x, true] call CBA_fnc_addItem;
};
} forEach _secondaryWeaponInfo;
// Only add magazines once the weapon is fully ready
if (_secondaryWeaponMagazines isNotEqualTo []) then {
_cswTripod setVariable [QGVAR(secondaryWeaponMagazines), _secondaryWeaponMagazines, true];
};
if (!GVAR(defaultAssemblyMode)) then {
[_cswTripod, "disableWeaponAssembly", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
};
@ -65,15 +84,18 @@
private _onFailure = {
params ["_args"];
_args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponMagazine"];
TRACE_3("deployTripod failure",_player,_secondaryWeaponClassname,_secondaryWeaponMagazine);
_args params ["_player", "_secondaryWeaponClassname", "_secondaryWeaponInfo"];
TRACE_3("deployTripod failure",_player,_secondaryWeaponClassname,_secondaryWeaponInfo);
_player addWeaponGlobal _secondaryWeaponClassname;
if (_secondaryWeaponMagazine isNotEqualTo "") then {
_player addWeaponItem [_secondaryWeaponClassname, _secondaryWeaponMagazine, true];
};
// Add tripod back
[_player, _secondaryWeaponClassname] call CBA_fnc_addWeaponWithoutItems;
// Add all attachments back
{
_player addWeaponItem [_secondaryWeaponClassname, _x, true];
} forEach _secondaryWeaponInfo;
};
private _deployTime = getNumber(configFile >> "CfgWeapons" >> _secondaryWeaponClassname >> QUOTE(ADDON) >> "deployTime");
[TIME_PROGRESSBAR(_deployTime), [_player, _secondaryWeaponClassname, _secondaryWeaponMagazine], _onFinish, _onFailure, LLSTRING(PlaceTripod_progressBar)] call EFUNC(common,progressBar);
[TIME_PROGRESSBAR(_deployTime), [_player, _secondaryWeaponClassname, _secondaryWeaponInfo], _onFinish, _onFailure, LLSTRING(PlaceTripod_progressBar)] call EFUNC(common,progressBar);
}, _this] call CBA_fnc_execNextFrame;

View File

@ -4,39 +4,51 @@
* Deploys the current CSW
*
* Arguments:
* 0: Unit <OBJECT>
* 0: Target <OBJECT>
* 1: Unit <OBJECT>
* 2: Args <ANY>
* 3: Action Data <ARRAY>
*
* Return Value:
* None
*
* Example:
* [player] call ace_csw_fnc_assemble_deployWeapon
* [cursorObject, player] call ace_csw_fnc_assemble_deployWeapon
*
* Public: No
*/
[{
params ["_tripod", "_player", "", "_carryWeaponClassname"];
if (isNil "_carryWeaponClassname") then { _carryWeaponClassname = secondaryWeapon _player };
params ["_tripod", "_player"];
// Save magazines and attachments (handle loaded launchers which can become csw like CUP Metis)
private _carryWeaponInfo = (getUnitLoadout _player) select 1;
private _carryWeaponClassname = _carryWeaponInfo deleteAt 0;
// Remove empty entries
_carryWeaponInfo = _carryWeaponInfo select {_x isNotEqualTo "" && {_x isNotEqualTo []}};
TRACE_3("assemble_deployWeapon_carryWeaponClassname",_tripod,_player,_carryWeaponClassname);
private _tripodClassname = typeOf _tripod;
_player removeWeaponGlobal _carryWeaponClassname;
private _weaponConfig = configfile >> "CfgWeapons" >> _carryWeaponClassname >> QUOTE(ADDON);
private _assembledClassname = getText (_weaponConfig >> "assembleTo" >> _tripodClassname);
if (!isClass (configFile >> "CfgVehicles" >> _assembledClassname)) exitWith {ERROR_1("bad static classname [%1]",_assembledClassname);};
_player removeWeaponGlobal _carryWeaponClassname;
private _deployTime = getNumber (_weaponConfig >> "deployTime");
TRACE_4("",_carryWeaponClassname,_tripodClassname,_assembledClassname,_deployTime);
private _onFinish = {
params ["_args"];
_args params ["_tripod", "_player", "_assembledClassname"];
_args params ["_tripod", "_player", "_assembledClassname", "", "_carryWeaponInfo"];
TRACE_3("deployWeapon finish",_tripod,_player,_assembledClassname);
private _secondaryWeaponMagazines = _tripod getVariable [QGVAR(secondaryWeaponMagazines), []];
private _tripodPos = getPosATL _tripod;
private _tripodDir = getDir _tripod;
deleteVehicle _tripod;
@ -44,10 +56,26 @@
_tripodPos set [2, (_tripodPos select 2) + 0.1];
// Delay a frame so tripod has a chance to be deleted
[{
params ["_assembledClassname", "_tripodDir", "_tripodPos"];
params ["_assembledClassname", "_tripodDir", "_tripodPos", "_player", "_carryWeaponInfo", "_secondaryWeaponMagazines"];
private _csw = createVehicle [_assembledClassname, [0, 0, 0], [], 0, "NONE"];
// Assembly mode: [0=disabled, 1=enabled, 2=enabled&unload, 3=default]
_csw setVariable [QGVAR(assemblyMode), 2, true]; // Explicitly set advanced assembly mode + unload, and broadcast
{
// Magazines
if (_x isEqualType []) then {
_secondaryWeaponMagazines pushBack _x;
} else {
// Items
[_player, _x, true] call CBA_fnc_addItem;
};
} forEach _carryWeaponInfo;
// Only add magazines once the weapon is fully ready
if (_secondaryWeaponMagazines isNotEqualTo []) then {
_csw setVariable [QGVAR(secondaryWeaponMagazines), _secondaryWeaponMagazines, true];
};
if (!GVAR(defaultAssemblyMode)) then {
[_csw, "disableWeaponAssembly", QUOTE(ADDON), true] call EFUNC(common,statusEffect_set);
};
@ -58,23 +86,29 @@
};
[QGVAR(deployWeaponSucceeded), [_csw]] call CBA_fnc_localEvent;
TRACE_2("csw placed",_csw,_assembledClassname);
}, [_assembledClassname, _tripodDir, _tripodPos]] call CBA_fnc_execNextFrame;
}, [_assembledClassname, _tripodDir, _tripodPos, _player, _carryWeaponInfo, _secondaryWeaponMagazines]] call CBA_fnc_execNextFrame;
};
private _onFailure = {
params ["_args"];
_args params ["", "_player", "", "_carryWeaponClassname"];
_args params ["", "_player", "", "_carryWeaponClassname", "_carryWeaponInfo"];
TRACE_2("deployWeapon failure",_player,_carryWeaponClassname);
_player addWeaponGlobal _carryWeaponClassname;
// Add weapon back
[_player, _carryWeaponClassname] call CBA_fnc_addWeaponWithoutItems;
// Add all attachments back
{
_player addWeaponItem [_carryWeaponClassname, _x, true];
} forEach _carryWeaponInfo;
};
private _codeCheck = {
private _condition = {
params ["_args"];
_args params ["_tripod"];
alive _tripod
};
[TIME_PROGRESSBAR(_deployTime), [_tripod, _player, _assembledClassname, _carryWeaponClassname], _onFinish, _onFailure, LLSTRING(AssembleCSW_progressBar), _codeCheck] call EFUNC(common,progressBar);
[TIME_PROGRESSBAR(_deployTime), [_tripod, _player, _assembledClassname, _carryWeaponClassname, _carryWeaponInfo], _onFinish, _onFailure, LLSTRING(AssembleCSW_progressBar), _condition] call EFUNC(common,progressBar);
}, _this] call CBA_fnc_execNextFrame;

View File

@ -11,7 +11,7 @@
* None
*
* Example:
* [tripod, player] call ace_csw_fnc_assemble_pickupTripod
* [cursorObject, player] call ace_csw_fnc_assemble_pickupTripod
*
* Public: No
*/
@ -28,16 +28,45 @@
_args params ["_tripod", "_player", "_tripodClassname"];
TRACE_3("assemble_pickupTripod finish",_tripod,_player,_tripodClassname);
// Save tripod position before it's deleted
private _tripodPos = getPosATL _tripod;
// Eject dead units (all crew are dead at this point, otherwise condition would have failed), but ignore UAV units
{
if (unitIsUAV _x) then {
_tripod deleteVehicleCrew _x;
} else {
moveOut _x;
};
} forEach (crew _tripod);
deleteVehicle _tripod;
_player addWeaponGlobal _tripodClassname;
[_player, "PutDown"] call EFUNC(common,doGesture);
// If the player has space, give it to him
if ((alive _player) && {(secondaryWeapon _player) == ""}) exitWith {
[_player, _tripodClassname] call CBA_fnc_addWeaponWithoutItems;
};
// Try to find existing weapon holders
private _weaponHolder = nearestObject [_tripodPos, "WeaponHolder"];
// If there are none or too far away, make a new one
if (isNull _weaponHolder || {_tripodPos distance _weaponHolder > 2}) then {
_weaponHolder = createVehicle ["GroundWeaponHolder", [0, 0, 0], [], 0, "CAN_COLLIDE"];
_weaponHolder setDir random [0, 180, 360];
_weaponHolder setVehiclePosition [_tripodPos, [], 0, "CAN_COLLIDE"]; // places object on surface below
};
_weaponHolder addWeaponCargoGlobal [_tripodClassname, 1];
};
private _condition = {
params ["_args"];
_args params ["_tripod", "_player"];
_args params ["_tripod"];
(alive _tripod) && {secondaryWeapon _player == ""}
_tripod call FUNC(canPickupTripod)
};
TRACE_3("",_pickupTime,typeOf _tripod,_tripodClassname);

View File

@ -5,12 +5,13 @@
*
* Arguments:
* 0: Static Weapon <OBJECT>
* 1: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* [weapon] call ace_csw_fnc_assemble_pickupWeapon
* [cursorObject, player] call ace_csw_fnc_assemble_pickupWeapon
*
* Public: No
*/
@ -43,11 +44,10 @@
_args params ["_staticWeapon", "_player", "_carryWeaponClassname", "_turretClassname", "_onDisassembleFunc"];
TRACE_4("disassemble finish",_staticWeapon,_player,_carryWeaponClassname,_turretClassname);
private _weaponPos = getPosATL _staticWeapon;
_weaponPos set [2, (_weaponPos select 2) + 0.1];
private _weaponPos = (getPosATL _staticWeapon) vectorAdd [0, 0, 0.1];
private _weaponDir = getDir _staticWeapon;
private _carryWeaponMag = "";
private _carryWeaponMag = [];
private _carryWeaponMags = compatibleMagazines _carryWeaponClassname;
LOG("remove ammo");
{
@ -55,9 +55,9 @@
if (_xAmmo == 0) then {continue};
private _carryMag = _xMag call FUNC(getCarryMagazine);
if (_carryWeaponMag == "" && {_carryMag in _carryWeaponMags}) then {
if (_carryWeaponMag isEqualTo [] && {_carryMag in _carryWeaponMags}) then {
TRACE_3("Adding mag to secondary weapon",_xMag,_xAmmo,_carryMag);
_carryWeaponMag = _carryMag;
_carryWeaponMag = [_carryMag, _xAmmo];
DEC(_xAmmo);
};
if ((_xAmmo > 0) && {_carryMag != ""}) then {
@ -80,25 +80,40 @@
};
[{
params ["_player", "_weaponPos", "_carryWeaponClassname", "_carryWeaponMag"];
params ["_player", "_weaponPos", "_carryWeaponClassname", "_carryWeaponMag", "_turretClassname"];
// Give the weapon to the player if possible
if ((alive _player) && {(secondaryWeapon _player) == ""}) exitWith {
_player addWeapon _carryWeaponClassname;
if (_carryWeaponMag isNotEqualTo "") then {
[_player, _carryWeaponClassname] call CBA_fnc_addWeaponWithoutItems;
if (_carryWeaponMag isNotEqualTo []) then {
_player addWeaponItem [_carryWeaponClassname, _carryWeaponMag, true];
};
};
private _weaponRelPos = _weaponPos getPos RELATIVE_DIRECTION(90);
private _weaponHolder = createVehicle ["groundWeaponHolder", [0, 0, 0], [], 0, "NONE"];
_weaponHolder setDir random [0, 180, 360];
_weaponHolder setPosATL [_weaponRelPos select 0, _weaponRelPos select 1, _weaponPos select 2];
if (_carryWeaponMag isEqualTo "") then {
_weaponHolder addWeaponCargoGlobal [_carryWeaponClassname, 1];
} else {
_weaponHolder addWeaponWithAttachmentsCargoGlobal [[_carryWeaponClassname, "", "", "", [_carryWeaponMag, 1], [], ""], 1];
// If there is no turret, place the ground holder where the turret was
if (_turretClassname != "") then {
_weaponPos = _weaponPos getPos RELATIVE_DIRECTION(90);
};
}, [_player, _weaponPos, _carryWeaponClassname, _carryWeaponMag]] call CBA_fnc_execNextFrame;
// Create a new weapon holder (don't try to get an existing one, as no guarantee where it could be)
private _weaponHolder = createVehicle ["GroundWeaponHolder", [0, 0, 0], [], 0, "CAN_COLLIDE"];
_weaponHolder setDir random [0, 180, 360];
_weaponHolder setVehiclePosition [_weaponPos, [], 0, "CAN_COLLIDE"]; // places object on surface below
_weaponHolder addWeaponWithAttachmentsCargoGlobal [[_carryWeaponClassname, "", "", "", _carryWeaponMag, [], ""], 1];
}, [_player, _weaponPos, _carryWeaponClassname, _carryWeaponMag, _turretClassname]] call CBA_fnc_execNextFrame;
LOG("delete weapon");
// Eject dead units (all crew are dead or UAV at this point, otherwise condition would have failed), but ignore UAV units
{
if (unitIsUAV _x) then {
_staticWeapon deleteVehicleCrew _x;
} else {
moveOut _x;
};
} forEach (crew _staticWeapon);
deleteVehicle _staticWeapon;
LOG("end");
@ -107,7 +122,8 @@
private _condition = {
params ["_args"];
_args params ["_staticWeapon"];
((crew _staticWeapon) isEqualTo []) && (alive _staticWeapon)
_staticWeapon call FUNC(assemble_canPickupWeapon)
};
[TIME_PROGRESSBAR(_pickupTime), [_staticWeapon, _player, _carryWeaponClassname, _turretClassname, _onDisassembleFunc], _onFinish, {}, LLSTRING(DisassembleCSW_progressBar), _condition] call EFUNC(common,progressBar);

View File

@ -5,7 +5,7 @@
*
* Arguments:
* 0: Tripod <OBJECT>
* 1: Unit <OBJECT>
* 1: Unit (not used) <OBJECT>
*
* Return Value:
* Can pickup <BOOL>
@ -16,6 +16,6 @@
* Public: No
*/
params ["_tripod", "_unit"];
params ["_tripod"];
((secondaryWeapon _unit) == "") && {alive _tripod} // return
alive _tripod && {((crew _tripod) findIf {alive _x && {!unitIsUAV _x}}) == -1} // return

View File

@ -68,14 +68,38 @@ TRACE_1("Remove all loaded magazines",_magsToRemove);
};
} forEach _magsToRemove;
if (_staticWeapon getVariable [QGVAR(secondaryWeaponMagazine), ""] isNotEqualTo "") then {
private _secondaryWeaponMagazine = _staticWeapon getVariable QGVAR(secondaryWeaponMagazine);
private _turret = allTurrets _staticWeapon param [0, []];
private _vehicleMag = [_staticWeapon, _turret, _secondaryWeaponMagazine] call FUNC(reload_getVehicleMagazine);
TRACE_3("Re-add previous mag",_secondaryWeaponMagazine,_turret,_vehicleMag);
if (!isClass (configFile >> "CfgMagazines" >> _vehicleMag)) exitWith {};
_staticWeapon addMagazineTurret [_vehicleMag, _turret, 1];
_staticWeapon setVariable [QGVAR(secondaryWeaponMagazine), nil];
private _secondaryWeaponMagazines = _staticWeapon getVariable [QGVAR(secondaryWeaponMagazines), []];
if (_secondaryWeaponMagazines isNotEqualTo []) then {
// Check if the static weapon can take magazines
private _turret = (allTurrets _staticWeapon) param [0, []];
private _compatibleMagazinesTurret = flatten ((_staticWeapon weaponsTurret _turret) apply {compatibleMagazines _x});
private _container = objNull;
{
private _vehicleMag = [_staticWeapon, _turret, _x select 0] call FUNC(reload_getVehicleMagazine);
TRACE_3("Re-add previous mag",_x select 0,_turret,_vehicleMag);
// If the magazine can be added to the static weapon, do it now
if (_vehicleMag in _compatibleMagazinesTurret) then {
_staticWeapon addMagazineTurret [_vehicleMag, _turret, _x select 1];
} else {
// Find a suitable container to place items in if necessary
if (isNull _container) then {
_container = (nearestObjects [_staticWeapon, ["GroundWeaponHolder"], 10]) param [0, objNull];
// Create ammo storage container
if (isNull _container) then {
_container = createVehicle ["GroundWeaponHolder", getPosATL _staticWeapon, [], 0, "NONE"];
};
};
// If the mag can't be added to the static weapon, add it to the ground holder
_container addMagazineAmmoCargo [_x select 0, 1, _x select 1];
};
} forEach _secondaryWeaponMagazines;
_staticWeapon setVariable [QGVAR(secondaryWeaponMagazines), nil, true];
};
if (_storeExtraMagazines) then {

View File

@ -263,7 +263,7 @@
<Japanese>インタラクションの所要時間係数</Japanese>
<Chinese>互動時間係數</Chinese>
<Chinesesimp>交互时间系数</Chinesesimp>
<Italian>Coefficente per il tempo di interazione</Italian>
<Italian>Coefficiente per il tempo di interazione</Italian>
<Czech>Koeficient času interakce</Czech>
<Polish>Współczynnik czasu interakcji</Polish>
<Spanish>Coeficiente de tiempo de interacción</Spanish>

View File

@ -5,10 +5,8 @@ PREP(bloodType);
PREP(canCheckDogtag);
PREP(canTakeDogtag);
PREP(checkDogtag);
PREP(checkDogtagItem);
PREP(getDogtagData);
PREP(getDogtagItem);
PREP(sendDogtagData);
PREP(showDogtag);
PREP(ssn);
PREP(takeDogtag);

View File

@ -1,10 +1,29 @@
#include "script_component.hpp"
[QGVAR(showDogtag), LINKFUNC(showDogtag)] call CBA_fnc_addEventHandler;
[QGVAR(sendDogtagData), LINKFUNC(sendDogtagData)] call CBA_fnc_addEventHandler;
[QGVAR(getDogtagItem), LINKFUNC(getDogtagItem)] call CBA_fnc_addEventHandler;
[QGVAR(addDogtagItem), LINKFUNC(addDogtagItem)] call CBA_fnc_addEventHandler;
if (hasInterface || isServer) then {
[QGVAR(broadcastDogtagInfo), {
GVAR(dogtagsData) set _this;
}] call CBA_fnc_addEventHandler;
if (isServer) then {
// Sync dogtag data from server to client
[QGVAR(requestSyncDogtagDataJIP), {
params ["_clientOwner"];
{
[QGVAR(broadcastDogtagInfo), [_x, _y], _clientOwner] call CBA_fnc_ownerEvent;
} forEach GVAR(dogtagsData);
}] call CBA_fnc_addEventHandler;
} else {
// To be here, hasInterface must be true
[QGVAR(requestSyncDogtagDataJIP), clientOwner] call CBA_fnc_serverEvent;
};
};
// Add actions and event handlers only if ace_medical is enabled
// - Adding actions via config would create a dependency
["CBA_settingsInitialized", {
@ -56,8 +75,6 @@ if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then {
if (_leftPanelIDC in [2010, 2012, 2014] && {_rightPanelIDC == 38}) then {
LOG("passed");
private _rightPanel = _display displayCtrl 15;
private _allDogtags = missionNamespace getVariable [QGVAR(allDogtags), []];
private _allDogtagsData = missionNamespace getVariable [QGVAR(allDogtagDatas), []];
private _cfgWeapons = configFile >> "CfgWeapons";
private _item = "";
private _dogtagData = [];
@ -66,15 +83,37 @@ if (["ace_arsenal"] call EFUNC(common,isModLoaded)) then {
_item = _rightPanel lnbData [_i, 0];
if (_item isKindOf ["ACE_dogtag", _cfgWeapons]) then {
_dogtagData = _allDogtagsData param [_allDogtags find _item, []];
private _name = (GVAR(dogtagsData) getOrDefault [_item, []]) param [0, ""];
// If data doesn't exist, put name as "unknown"
_rightPanel lnbSetText [[_i, 1], [LLSTRING(itemName), ": ", _dogtagData param [0, LELSTRING(common,unknown)]] joinString ""];
// If data doesn't exist or body has no name, set name as "unknown"
if (_name == "") then {
_name = LELSTRING(common,unknown);
};
_rightPanel lnbSetText [[_i, 1], [LLSTRING(itemName), ": ", _name] joinString ""];
};
};
};
}] call CBA_fnc_addEventHandler;
};
// Add context menu option
[
"ACE_dogtag",
["GROUND", "CARGO", "CONTAINER"],
LLSTRING(checkItem),
nil,
QPATHTOF(data\dogtag_icon_ca.paa),
[
{true},
{true}
],
{
[GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag);
false
}
] call CBA_fnc_addItemContextMenuOption;
// Disable dogtags for civilians
"CIV_F" call FUNC(disableFactionDogtags);

View File

@ -8,4 +8,12 @@ PREP_RECOMPILE_END;
GVAR(disabledFactions) = createHashMap;
if (hasInterface || isServer) then {
GVAR(dogtagsData) = createHashMap;
if (!isServer) exitWith {};
GVAR(idCounter) = 0;
};
ADDON = true;

View File

@ -27,7 +27,9 @@ private _fnc_getActions = {
private _displayName = getText (_config >> "displayName");
private _picture = getText (_config >> "picture");
private _action = [_x, _displayName, _picture, FUNC(checkDogtagItem), {true}, {}, _x] call EFUNC(interact_menu,createAction);
private _action = [_x, _displayName, _picture, {
[GVAR(dogtagsData) getOrDefault [_this select 2, []]] call FUNC(showDogtag);
}, {true}, {}, _x] call EFUNC(interact_menu,createAction);
_actions pushBack [_action, [], _player];
};
} forEach (_player call EFUNC(common,uniqueItems));

View File

@ -20,10 +20,17 @@ params ["_item", "_dogtagData"];
if (_item == "") exitWith {};
[ace_player, _item] call CBA_fnc_addItem;
// Verify that the unit has inventory space, otherwise drop the dogtag on the ground
[ace_player, _item, true] call CBA_fnc_addItem;
_dogtagData params ["_nickName"];
private _displayText = format [localize LSTRING(takeDogtagSuccess), _nickName];
_dogtagData params ["_name"];
// If data doesn't exist or body has no name, set name as "unknown"
if (_name == "") then {
_name = LELSTRING(common,unknown);
};
private _displayText = format [localize LSTRING(takeDogtagSuccess), _name];
// display message
[{

View File

@ -23,4 +23,4 @@ if (isNull _target) exitWith {false};
// check if disabled for faction
if ((faction _target) in GVAR(disabledFactions)) exitWith {false};
(!alive _target) || {_target getVariable ["ACE_isUnconscious", false]}
!(_target call EFUNC(common,isAwake))

View File

@ -23,4 +23,4 @@ if (isNull _target) exitWith {false};
// check if disabled for faction
if ((faction _target) in GVAR(disabledFactions)) exitWith {false};
(!alive _target) || {_target getVariable ["ACE_isUnconscious", false]}
!(_target call EFUNC(common,isAwake)) && {_player canAdd ["ACE_dogtag_1", 1/*, true*/]} // Todo: Uncomment in 2.18

View File

@ -1,22 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: SzwedzikPL
* Check dogtag self menu action.
*
* Arguments:
* 0: Player <OBJECT>
* 1: Target <OBJECT>
* 2: Item class <STRING>
*
* Return Value:
* None
*
* Example:
* [player, unit, "itemClass"] call ace_dogtags_fnc_checkDogtagItem
*
* Public: No
*/
params ["_player", "_target", "_item"];
[QGVAR(sendDogtagData), [_player, _item]] call CBA_fnc_serverEvent;

View File

@ -21,19 +21,14 @@ if(!isServer) exitWith {};
params ["_player", "_target"];
TRACE_2("getDogtagItem",_player,_target);
private _allDogtags = missionNamespace getVariable [QGVAR(allDogtags), []];
private _allDogtagDatas = missionNamespace getVariable [QGVAR(allDogtagDatas), []];
GVAR(idCounter) = GVAR(idCounter) + 1;
private _nextID = count _allDogtags + 1;
if (_nextID > 999) exitWith {ERROR("Ran out of IDs");};
if (GVAR(idCounter) > 999) exitWith {ERROR("Ran out of IDs");};
private _dogTagData = [_target] call FUNC(getDogTagData);
private _item = format ["ACE_dogtag_%1", _nextID];
_allDogtags pushBack _item;
_allDogtagDatas pushBack _dogTagData;
missionNamespace setVariable [QGVAR(allDogtags), _allDogtags];
missionNamespace setVariable [QGVAR(allDogtagDatas), _allDogtagDatas];
private _item = format ["ACE_dogtag_%1", GVAR(idCounter)];
[QGVAR(addDogtagItem), [_item, _dogTagData], [_player]] call CBA_fnc_targetEvent;
// Broadcast data globally, so that clients can use it where needed
[QGVAR(broadcastDogtagInfo), [_item, _dogTagData]] call CBA_fnc_globalEvent;

View File

@ -1,33 +0,0 @@
#include "..\script_component.hpp"
/*
* Author: SzwedzikPL
* Server: returns to client data on given dogtag.
*
* Arguments:
* 0: Player <OBJECT>
* 1: Target <OBJECT>
*
* Return Value:
* None
*
* Example:
* [player, unit] call ace_dogtags_fnc_sendDogtagData
*
* Public: No
*/
if (!isServer) exitWith {};
params ["_target", "_item"];
TRACE_2("sendDogtagData",_target,_item);
private _allDogtags = missionNameSpace getVariable [QGVAR(allDogtags), []];
private _allDogtagDatas = missionNameSpace getVariable [QGVAR(allDogtagDatas), []];
private _dogtagData = [];
private _index = _allDogtags find _item;
if (_index >= 0) then {
_dogtagData = _allDogtagDatas select _index;
};
[QGVAR(showDogtag), [_dogtagData], [_target]] call CBA_fnc_targetEvent;

View File

@ -31,5 +31,11 @@ private _display = uiNamespace getvariable [QGVAR(tag), displayNull];
if(isNull _display) exitWith {};
private _control = _display displayCtrl 1001;
_dogtagData params ["_nickName", "_code", "_bloodType"];
_control ctrlSetStructuredText parseText format ["%1<br/>%2<br/>%3", toUpper _nickName, _code, _bloodType];
_dogtagData params ["_name", "_code", "_bloodType"];
// If data doesn't exist or body has no name, set name as "unknown"
if (_name == "") then {
_name = LELSTRING(common,unknown);
};
_control ctrlSetStructuredText parseText format ["%1<br/>%2<br/>%3", toUpper _name, _code, _bloodType];

View File

@ -66,7 +66,7 @@
<Turkish>Al</Turkish>
</Key>
<Key ID="STR_ACE_Dogtags_takeDogtagSuccess">
<English>Dogtag taken from %1...</English>
<English>Dog Tag taken from %1...</English>
<Polish>Zabrałeś nieśmiertelnik %1...</Polish>
<Russian>Жетон снят с %1...</Russian>
<Czech>Sebral jsem známku od %1...</Czech>
@ -82,7 +82,7 @@
<Turkish>Künye %1 kişisinden alındı</Turkish>
</Key>
<Key ID="STR_ACE_Dogtags_dogtagAlreadyTaken">
<English>Somebody else has already taken the dogtag...</English>
<English>Somebody else has already taken the Dog Tag...</English>
<Polish>Ktoś już zabrał ten nieśmiertelnik...</Polish>
<Russian>Кто-то уже забрал жетон...</Russian>
<Czech>Někdo jiný už vzal identifikační známku...</Czech>
@ -98,7 +98,7 @@
<Turkish>Başka biri zaten künyeyi almış</Turkish>
</Key>
<Key ID="STR_ACE_Dogtags_IGUI_Description">
<English>Onscreen display for checking dogtags</English>
<English>Onscreen display for checking Dog Tags</English>
<German>Anzeige um Erkennungsmarke zu überprüfen</German>
<Chinese>在畫面中顯示檢查兵籍牌</Chinese>
<Chinesesimp>在画面中显示检查兵籍牌</Chinesesimp>

View File

@ -33,7 +33,7 @@ if (!GVAR(dragAndFire)) then {
private _inBuilding = _unit call FUNC(isObjectOnObject);
// Play release animation
if !(_unit getVariable ["ACE_isUnconscious", false]) then {
if (_unit call EFUNC(common,isAwake)) then {
[_unit, "released"] call EFUNC(common,doGesture);
};

View File

@ -44,7 +44,7 @@ if (_tryLoad && {!(_target isKindOf "CAManBase")} && {["ace_cargo"] call EFUNC(c
// Fix anim when aborting carrying persons
if (_target isKindOf "CAManBase" || {animationState _unit in CARRY_ANIMATIONS}) then {
if (isNull objectParent _unit && {!(_unit getVariable ["ACE_isUnconscious", false])}) then {
if (isNull objectParent _unit && {_unit call EFUNC(common,isAwake)}) then {
[_unit, "", 2] call EFUNC(common,doAnimation);
};

View File

@ -312,7 +312,7 @@
<Korean>%3의료 메뉴%4는 %3의료%4를 용이하게 사용하기 위한 전용 %3인터페이스%4입니다. %3우%4 및 %3좌%4 문자는 치료 중인 환자의 신체 측면을 나타냅니다.&lt;br/&gt;&lt;br/&gt;%3사용 방법:%4&lt;br/&gt;%2환자를 보고 [%3%13%4]를 사용하여 의료 메뉴를 여십시오. 환자 없이 메뉴를 열면 자가 치료가 됩니다.&lt;br/&gt;%2아니면 [%3%12%4] 또는 [%3%13%4]를 사용하고 %3의료 메뉴%4를 선택하십시오.&lt;br/&gt;&lt;br/&gt;%3키 설정%4&lt;br/&gt;%2[%3W, A, S, D, X와 Z%4]를 사용하여 신체 부위를 선택하십시오.&lt;br/&gt;%2%3번호판 키%4를 사용하여 치료 카테고리를 선택하십시오.</Korean>
<Portuguese>O %3Menu Médico%4 é uma %3interface%4 dedicada a facilitar o %3tratamento médico%4. As letras %3R%4 e %3L%4 indicam o lado do corpo do paciente que está recebendo o tratamento.&lt;br/&gt;&lt;br/&gt;%3Uso:%4&lt;br/&gt;%2Utilize [%3%14%4] enquanto olha o paciente para abrir o Menu Médico. Se não houver paciente, o menu será de auto-tratamento.&lt;br/&gt;%2Alternativamente, utilize [%3%12%4] ou [%3%13%4] e selecione %3Menu Médico%4.&lt;br/&gt;&lt;br/&gt;%3Atalhos de teclado:%4&lt;br/&gt;%2Utilize [%3W, A, S, D, X, e Z%4] para selecionar partes do corpo.&lt;br/&gt;%2Utilize as %3teclas numéricas%4 para selecionar as categorias de tratamento.</Portuguese>
<Italian>Il %3Menù Medico%4 è un'%3interfaccia%4 dedicata a facilitare %3trattamenti medici%4. Le lettere %3Dx%4 e %3Sx%4 contrassegnano i lati del corpo del paziente che si stanno medicando.&lt;br/&gt;&lt;br/&gt;%3Utilizzo:%4&lt;br/&gt;%2Usa [%3%14%4] guardando il paziente per aprire il Menù Medico. Aprire il menù senza paziente di fronte permette l'automedicazione.&lt;br/&gt;%2In alternativa, usa [%3%12%4] o [%3%13%4] e seleziona %3Menù Medico%4.&lt;br/&gt;&lt;br/&gt;%3Comandi:%4&lt;br/&gt;%2Usa [%3W, A, S, D, X, and Z%4] per selezionare parti del corpo.&lt;br/&gt;%2Usa %3tasti numerici%4 per selezionare categorie di cure.</Italian>
<Japanese>%3医療メニュー%4は%3治療%4をしやすくするための専用%3インタフェース%4です。%3右%4と%3左%4の文字は治療を受ける患者の向きを表しています。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2[%3%14%4] を患者に視点を合わせながら押すことで患者の医療メニューを開けます。視点を合わせないで押すと、自分の医療メニューを開くことが出来ます。&lt;br/&gt;%2もしくは [%3%12%4] または [%3%13%4] を使って%3医療メニュー%4を選択します。&lt;br/&gt;&lt;br/&gt;%3キーバインド:%4&lt;br/&gt;%2[%3W, A, S, D, X, と Zキー%4] を使って身体の部位を選択できます。&lt;br/&gt;%2%3数字キー%4を使って治療項目を選択できます。</Japanese>
<Japanese>%3医療メニュー%4は%3治療%4をしやすくするための専用%3インタフェース%4です。%3右%4と%3左%4の文字は治療を受ける患者の向きを表しています。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2[%3%14%4] を患者に視点を合わせながら押すことで患者の医療メニューを開けます。視点を合わせないで押すと、自分の医療メニューを開くことが出来ます。&lt;br/&gt;%2もしくは [%3%12%4] または [%3%13%4] を使って%3医療メニュー%4を選択します。&lt;br/&gt;&lt;br/&gt;%3キーバインド:%4&lt;br/&gt;%2[%3W, A, S, D, X, と Zキー%4] を使って身体の部位を選択できます。&lt;br/&gt;%2%3数字キー%4を使って治療項目を選択できます。</Japanese>
<Spanish>El %3Menú Médico%4 es una %3interfaz%4 dedicada para facilitar el %3tratamiento médico%4. Las letras %3R%4 and %3L%4 indican el lado del paciente siendo tratado.&lt;br/&gt;&lt;br/&gt;%3Uso:%4&lt;br/&gt;%2Usar [%3%14%4] mientras se mira al paciente para abrir el Menú Médico. Abrir el menú sin mirar a un paciente permite el tratamiento a uno mismo. &lt;br/&gt;%2Alternativamente, usar [%3%12%4] o [%3%13%4] y seleccionar %3Menú Médico%4.&lt;br/&gt;&lt;br/&gt;%3Teclas asociadas:%4&lt;br/&gt;%2Usar [%3W, A, S, D, X, and Z%4] para seleccionar las partes del cuerpo.&lt;br/&gt;%2Usar las %3teclas numéricas%4 para seleccionar las categorías de tratamiento.</Spanish>
</Key>
<Key ID="STR_ACE_FieldManual_Items_ATragMX_ShortName">
@ -388,7 +388,7 @@
<Korean>%3휴대전화%4는 기능적으로는 %3격발기%4입니다. 폭발물 장치를 연결하여 폭발물을 터뜨릴 때 사용합니다. 여러 장치를 휴대전화와 연결하여 전화번호부 내에서 호출할 수 있습니다.&lt;br/&gt;&lt;br/&gt;%3사용 방법:%4&lt;br/&gt;%2폭발물을 놓으십시오.&lt;br/&gt;%2[%3%13%4]를 사용하고, %3폭발물%4을 선택하고, %3휴대전화%4를 선택하십시오.&lt;br/%2[%3%12%4]로 휴대전화 인터페이스를 여십시오.&lt;br/&gt;%2기폭시킬 전화번호를 선택하십시오.</Korean>
<Portuguese>O %3Celular%4 serve como dispositivo de detonação ao explosivo. Utilize-o para conectar e detonar dispositivos explosivos. Múltiplos dispositivos podem estar conectados ao celular e aparecerão na lista telefônica.&lt;br/&gt;&lt;br/&gt;%3Uso:%4&lt;br/&gt;%2Plante o explosivo.&lt;br/&gt;%2Utilize [%3%13%4], selecione %3Explosivos%4, e selecione %3Celular%4.&lt;br/&gt;%2Abra a interface do celular com [%3%12%4].&lt;br/&gt;%2Navegue pela lista telefônica utilizando as setas e selecione o número desejado.&lt;br/&gt;%2Ligue para o número para detonar.</Portuguese>
<Italian>Il %3Cellulare%4 è essenzialmente una %3spoletta%4. Usalo per collegare e detonare esplosivi. Molteplici esplosivi possono essere collegati ad un cellulare e detonati chiamando numeri nella rubrica.&lt;br/&gt;&lt;br/&gt;%3Utilizzo:%4&lt;br/&gt;%2Piazza un esplosivo.&lt;br/&gt;%2Usa [%3%13%4], seleziona %3Esplosivi%4, seleziona %3Cellulare%4.&lt;br/&gt;%2Apri l'interfaccia del telefono con [%3%12%4].&lt;br/&gt;%2Naviga la rubrica con le freccette e seleziona il numero da chiamare.&lt;br/&gt;%2Chiama il numero del dispositivo da detonare.</Italian>
<Japanese>%3携帯電話%4は%3点火装置%4として機能します。爆破装置を接続して起爆するために使用します。複数のデバイスを携帯電話に繋ぎ、電話帳から呼び出すことができます。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2爆発物を設置。&lt;br/&gt;%2[%3%13%4] を使い、%3爆発物%4を選択して、%3携帯電話%4を選択します。&lt;br/&gt;%2[%3%12%4] を使って携帯電話インタフェースを開きます。&lt;br/&gt;%2矢印ボタンで電話帳に移動し、発信番号を選択します。&lt;br/&gt;%2電話を掛けることで起爆します。</Japanese>
<Japanese>%3携帯電話%4は%3点火装置%4として機能します。爆破装置を接続して起爆するために使用します。複数のデバイスを携帯電話に繋ぎ、電話帳から呼び出すことができます。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2爆発物を設置。&lt;br/&gt;%2[%3%13%4] を使い、%3爆発物%4を選択して、%3携帯電話%4を選択します。&lt;br/&gt;%2[%3%12%4] を使って携帯電話インタフェースを開きます。&lt;br/&gt;%2矢印ボタンで電話帳に移動し、発信番号を選択します。&lt;br/&gt;%2電話を掛けることで起爆します。</Japanese>
<Spanish>El %3Teléfono%4 es funcionalmente un %3Detonador%4. Úsalo para conectarlo y detonar un dispositivo explosivo. Múltiples dispositivos pueden ser conectados al teléfono y llamados desde la agenda de contactos.&lt;br/&gt;&lt;br/&gt;%3Uso:%4&lt;br/&gt;%2Colocar un explosivo.&lt;br/&gt;%2Usar [%3%13%4], seleccionar %3Explosivos%4, y seleccionar %3Teléfono%4.&lt;br/&gt;%2Abrir la interfaz del teléfono con [%3%12%4].&lt;br/&gt;%2Navegar por la agenda de contactos con las flechas y selecciona el número a llamar.&lt;br/&gt;%2Llamar al número para detonarlo.</Spanish>
</Key>
<Key ID="STR_ACE_FieldManual_Items_Chemlight_Shield_ShortName">
@ -425,7 +425,7 @@
<Polish>Użyj%3Detonatora%4 do podłączenia i wysadzenia ładunku. Do jednego ładunku może być podłączonych wiele ładunków na różnych kanałach.&lt;br/&gt;&lt;br/&gt;%3Użycie:%4&lt;br/&gt;%2Połóż ładunek wybuchowy.&lt;br/&gt;%2Użyj [%3%13%4], wybierz%3Mat. Wybuchowe%4, i wybierz %3Detonator%4, do którego chcesz go podłączyć.&lt;br/&gt;%2Otwórz menu interakcji ACE [%3%12%4].&lt;br/&gt;%2Wybierz %3Mat. Wybuchowe%4 i wybierz %3Detonator%4.&lt;br/&gt;%2Wybierz %3Ładunek%4 który chcesz wysadzić.</Polish>
<Korean>%3격발기%4를 사용하여 폭발물을 연결하고 폭발시킬 수 있습니다. 여러 폭발물을 다른 채널에 연결하여 폭발시킬 수도 있습니다.&lt;br/&gt;&lt;br/&gt;%3사용 방법:%4&lt;br/&gt;%2폭발물을 설치합니다.&lt;br/&gt;%2[%3%13%4]를 사용하여 %3폭발물%4을 선택하고 연결할 %3격발기%4를 선택하십시오.&lt;br/&gt;%2[%3%12%4] 키로 ACE 인터페이스를 여십시오.&lt;br/&gt;%2%3폭발물%4을 선택하고 %3격발기%4를 선택하십시오.&lt;br/&gt;%2%3폭발물%4을 선택하면 폭발합니다.</Korean>
<Italian>Usa %3Spolette%4 per collegare e detonare dispositivi esplosivi. Molteplici dispositivi possono essere collagati a una spoletta e detonati individualmente come vari canali.&lt;br/&gt;&lt;br/&gt;%3Utilizzo:%4&lt;br/&gt;%2Piazza esplosivo.&lt;br/&gt;%2Usa [%3%13%4], seleziona %3Esplosivo%4, seleziona la %3Spoletta%4 a cui intendi collegarlo.&lt;br/&gt;%2Apri l'interfaccia ACE con [%3%12%4].&lt;br/&gt;%2Seleziona %3Esplosivi%4 e scegli una %3Spoletta%4.&lt;br/&gt;%2Seleziona un %3Explosivo%4 da detonare.</Italian>
<Japanese>%3点火装置%4を爆破装置に接続し使用することで起爆することが出来ます。複数の爆破装置を接続しそれぞれ違うチャンネルから起爆することもできます。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2爆発物を設置。&lt;br/&gt;%2[%3%13%4] を使い、%3爆発物%4を選択して、接続したい%3点火装置%4を選択します。&lt;br/&gt;%2ACEインタフェースを [%3%12%4] で開きます。&lt;br/&gt;%2%3爆発物%4を選択し、%3点火装置%4を選びます。&lt;br/&gt;%2起爆したい%3爆破装置%4を選択します。</Japanese>
<Japanese>%3点火装置%4を爆破装置に接続し使用することで起爆することが出来ます。複数の爆破装置を接続しそれぞれ違うチャンネルから起爆することもできます。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2爆発物を設置。&lt;br/&gt;%2[%3%13%4] を使い、%3爆発物%4を選択して、接続したい%3点火装置%4を選択します。&lt;br/&gt;%2ACEインタフェースを [%3%12%4] で開きます。&lt;br/&gt;%2%3爆発物%4を選択し、%3点火装置%4を選びます。&lt;br/&gt;%2起爆したい%3爆破装置%4を選択します。</Japanese>
<Spanish>Utiliza los %3Detonadores%4 para conectar y detonar un explosivo. Múltiple dispositivos pueden ser conectados a un detonador y detonados en diferentes canales.&lt;br/&gt;&lt;br/&gt;%3Uso:%4&lt;br/&gt;%2 Coloca un explosivo.&lt;br/&gt;%2Usar [%3%13%4], seleccionar %3Explosivos%4, y selecciona el %3Detonador%4 al que quieres conectarlo.&lt;br/&gt;%2Abre la interfaz de ACE con [%3%12%4].&lt;br/&gt;%2Selecciona %3Explosivos%4 y selecciona un %3Detonador%4.&lt;br/&gt;%2Selecciona el %3Explosivo%4 que quieres detonar.</Spanish>
</Key>
<Key ID="STR_ACE_FieldManual_Items_DAGR_ShortName">
@ -860,7 +860,7 @@
<Polish>%3Narzędzie do fortyfikowania%4 pozwala żołnierzom budować fortyfikacje wybrane przez twórcę misji.&lt;br/&gt;&lt;br/&gt;%3Użycie:%4&lt;br/&gt;%2Podnieś %3Narzędzie do fortyfikowania%4.&lt;br/&gt;%2Użyj [%3%12%4] i wybierz %3Fortyfikuj%4.&lt;br/&gt;%2Wybierz dostępną fortyfikację i postępuj zgodnie ze wskazówkami na ekranie.</Polish>
<Italian>L'%3Attrezzo di Fortificazione%4 permette ai soldati di costruire fortificazioni permesse dal creatore della missione.&lt;br/&gt;&lt;br/&gt;%3Utilizzo:%4&lt;br/&gt;%2Raccogli un %3Attrezzo di Fortificazione%4.&lt;br/&gt;%2Usa [%3%12%4] e seleziona %3Fortifica%4.&lt;br/&gt;%2Seleziona una fortificazione disponibile e segui le indicazioni di piazzamento sullo schermo.</Italian>
<Korean>%3요새화 도구%4를 사용하면 병사들이 임무 생성자가 제공한 요새를 구축할 수 있습니다.&lt;br/&gt;&lt;br/&gt;%3사용 방법:%4&lt;br/&gt;%2%3요새화 도구%4를 가지십시오.&lt;br/&gt;%2[%3%12%4]를 사용하고 %3요새화%4를 선택하십시오.&lt;br/&gt;%2사용 가능한 요새를 선택하고 화면의 지시에 따라 배치하십시오.</Korean>
<Japanese>%3要塞ツール%4を使用すると、兵士はミッション作成者が提供した要塞を構築できます。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2%3要塞ツール%4を持つ。&lt;br/&gt;%2[%3%12%4] を使って%3要塞%4を選択します。&lt;br/&gt;%2利用可能な構造物を選択し、画面上の指示に従って配置します。</Japanese>
<Japanese>%3築城ツール%4を使用すると、兵士はミッション作成者が提供した要塞を構築できます。&lt;br/&gt;&lt;br/&gt;%3使用方法:%4&lt;br/&gt;%2%3築城ツール%4を持つ。&lt;br/&gt;%2[%3%12%4] を使って%3野戦築城%4を選択します。&lt;br/&gt;%2利用可能な構造物を選択し、画面上の指示に従って配置します。</Japanese>
<Spanish>La %3Herramienta de Fortificación%4 permite a los soldados construir fortificaciones provistas por su creador de mision.&lt;br/&gt;&lt;br/&gt;%3Uso:%4&lt;br/&gt;%2Coge una %3Herramienta de Fortificación%4.&lt;br/&gt;%2Usar [%3%12%4] y seleccionar %3Fortificar%4.&lt;br/&gt;%2Selecciona una fortificación disponible y sigue las instrucciones en pantalla para su colocación.</Spanish>
</Key>
<Key ID="STR_ACE_FieldManual_Items_Lockpick_ShortName">

View File

@ -1,10 +1,10 @@
// weird ass concatenation syntax. PBO Project complains otherwise...
#define CONCAT(a,b) a####b
#define CREATE_SCREAM(no)\
class GVAR(DOUBLES(scream,no)) { \
name = QUOTE(GVAR(CONCAT(scream,no)));\
sound[] = {QUOTE(PATHTOF(CONCAT(sounds\scream,no).ogg)), QUOTE(db+8), 1};\
titles[] = {}; \
class GVAR(DOUBLES(scream,no)) {\
name = QGVAR(CONCAT(scream,no));\
sound[] = {QPATHTOF(CONCAT(sounds\scream,no).ogg), QUOTE(db+8), 1};\
titles[] = {};\
}
class CfgSounds {

View File

@ -0,0 +1,7 @@
class CfgVehicles {
class Static;
class GVAR(logic): Static {
scope = 1;
displayName = "";
};
};

View File

@ -1,9 +1,10 @@
PREP(burn);
PREP(isBurning);
PREP(burnEffects);
PREP(burnIndicator);
PREP(burnReaction);
PREP(burnSimulation);
PREP(fireManagerPFH);
PREP(isBurning);
PREP(medical_canPatDown);
PREP(medical_progress);
PREP(medical_success);
PREP(medical_canPatDown);

View File

@ -1,37 +1,89 @@
#include "script_component.hpp"
[QGVAR(burn), LINKFUNC(burn)] call CBA_fnc_addEventHandler;
[QGVAR(burnEffects), LINKFUNC(burnEffects)] call CBA_fnc_addEventHandler;
[QGVAR(burnSimulation), LINKFUNC(burnSimulation)] call CBA_fnc_addEventHandler;
[QGVAR(playScream), {
params ["_scream", "_source"];
// only play sound if enabled in settings and enabled for the unit
// Only play sound if enabled in settings and enabled for the unit
if (GVAR(enableScreams) && {_source getVariable [QGVAR(enableScreams), true]}) then {
_source say3D _scream;
};
}] call CBA_fnc_addEventHandler;
["ace_settingsInitialized", {
if (!isServer) exitWith {};
["CBA_settingsInitialized", {
TRACE_1("settingsInit",GVAR(enabled));
if (!GVAR(enabled)) exitWith {};
if (isServer) then {
[QGVAR(addFireSource), {
params ["_source", "_radius", "_intensity", "_key", ["_condition", { true }], ["_conditionArgs", []]];
private _fireLogic = createVehicle ["ACE_LogicDummy", [0, 0, 0], [], 0, "NONE"];
if (_source isEqualType objNull) then {
_fireLogic attachTo [_source];
} else {
_fireLogic setPosASL _source;
};
GVAR(fireSources) = createHashMap;
[GVAR(fireSources), _key, [_fireLogic, _radius, _intensity, _condition, _conditionArgs]] call CBA_fnc_hashSet;
}] call CBA_fnc_addEventHandler;
[QGVAR(addFireSource), {
params [
["_source", objNull, [objNull, []]],
["_radius", 0, [0]],
["_intensity", 0, [0]],
["_key", ""],
["_condition", {true}, [{}]],
["_conditionArgs", []]
];
[QGVAR(removeFireSource), {
params ["_key"];
[GVAR(fireSources), _key] call CBA_fnc_hashRem;
}] call CBA_fnc_addEventHandler;
private _isObject = _source isEqualType objNull;
[LINKFUNC(fireManagerPFH), FIRE_MANAGER_PFH_DELAY, []] call CBA_fnc_addPerFrameHandler;
GVAR(fireSources) = [[], nil] call CBA_fnc_hashCreate;
};
// Check if the source is valid
if !(_isObject || {_source isEqualTypeParams [0, 0, 0]}) exitWith {};
if (_isObject && {isNull _source}) exitWith {};
if (_radius == 0 || _intensity == 0) exitWith {};
if (_key isEqualTo "") exitWith {}; // key can be many types
// hashValue supports more types than hashmaps do by default, but not all (e.g. locations)
private _hashedKey = hashValue _key;
if (isNil "_hashedKey") exitWith {
ERROR_2("Unsupported key type used: %1 - %2",_key,typeName _key);
};
// If a position is passed, create a static object at said position
private _sourcePos = if (_isObject) then {
getPosATL _source
} else {
ASLToATL _source
};
private _fireLogic = createVehicle [QGVAR(logic), _sourcePos, [], 0, "CAN_COLLIDE"];
// If an object was passed, attach logic to the object
if (_isObject) then {
_fireLogic attachTo [_source];
};
// To avoid issues, remove existing entries first before overwriting
if (_hashedKey in GVAR(fireSources)) then {
[QGVAR(removeFireSource), _key] call CBA_fnc_localEvent;
};
GVAR(fireSources) set [_hashedKey, [_fireLogic, _radius, _intensity, _condition, _conditionArgs]];
}] call CBA_fnc_addEventHandler;
[QGVAR(removeFireSource), {
params ["_key"];
private _hashedKey = hashValue _key;
if (isNil "_hashedKey") exitWith {
ERROR_2("Unsupported key type used: %1 - %2",_key,typeName _key);
};
(GVAR(fireSources) deleteAt _hashedKey) params [["_fireLogic", objNull]];
detach _fireLogic;
deleteVehicle _fireLogic;
}] call CBA_fnc_addEventHandler;
[LINKFUNC(fireManagerPFH), FIRE_MANAGER_PFH_DELAY, []] call CBA_fnc_addPerFrameHandler;
}] call CBA_fnc_addEventHandler;

View File

@ -24,6 +24,7 @@ class CfgPatches {
#include "CfgEventHandlers.hpp"
#include "CfgSounds.hpp"
#include "CfgVehicles.hpp"
#include "ACE_Medical_Treatment_Actions.hpp"
#include "RscTitles.hpp"

View File

@ -1,13 +1,12 @@
#include "..\script_component.hpp"
/*
* Author: tcvm
* Makes object catch fire. Only call from events. Local effects only.
* Arbitrary values to ignite people. Assumed maximum is "10".
* Author: johnb43
* Makes a unit catch fire. Only call from targeted events, is applied globally.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Intensity of fire <NUMBER>
* 2: Instigator of fire <OBJECT> (default: objNull)
* 0: Unit <OBJECT>
* 1: Fire intensity <NUMBER>
* 2: Fire instigator <OBJECT> (default: objNull)
*
* Return Value:
* None
@ -18,322 +17,62 @@
* Public: No
*/
#define INTENSITY_LOSS 0.03
#define INTENSITY_UPDATE 3
#define BURN_PROPOGATE_UPDATE 1
#define BURN_PROPOGATE_DISTANCE 2
#define BURN_PROPOGATE_COUNTER_MAX 5
params ["_unit", "_intensity", ["_instigator", objNull]];
if (!EGVAR(common,settingsInitFinished)) exitWith {
EGVAR(common,runAtSettingsInitialized) pushBack [LINKFUNC(burn), _this];
};
if (!GVAR(enabled)) exitWith {};
private _isBurning = [_unit] call FUNC(isBurning);
if (_isBurning) exitWith {};
params ["_unit", "_intensity", ["_instigator", objNull]];
TRACE_3("burn",_unit,_intensity,_instigator);
[{
// looped function
(_this getVariable "params") params ["_unit", "", "_instigator"];
private _unitPos = getPosASL _unit;
if (BURN_MIN_INTENSITY > _intensity) exitWith {
TRACE_3("intensity is too low",_unit,_intensity,BURN_MIN_INTENSITY);
};
_intensity = _unit getVariable [QGVAR(intensity), 0];
// Check if unit is remote (objNull is remote)
if (!local _unit) exitWith {
TRACE_1("unit is null or not local",_unit);
};
if (surfaceIsWater _unitPos && {(_unitPos#2) < 1}) then {
_intensity = 0;
// Check if the unit can burn (takes care of spectators and curators)
if (getNumber (configOf _unit >> "isPlayableLogic") == 1 || {!(_unit isKindOf "CAManBase")}) exitWith {
TRACE_1("unit is virtual or not a man",_unit);
};
// If unit is invulnerable, don't burn the unit
if !(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]}) exitWith {
TRACE_1("unit is invulnerable",_unit);
};
private _eyePos = eyePos _unit;
// Check if unit is mostly submerged in water
if (surfaceIsWater _eyePos && {(_eyePos select 2) < 0.1}) exitWith {
TRACE_1("unit is in water",_unit);
};
// If unit is already burning, update intensity, but don't add another PFH
if (_unit call FUNC(isBurning)) exitWith {
// Only allow intensity to be increased
if (_intensity <= (_unit getVariable [QGVAR(intensity), 0])) exitWith {
TRACE_2("unit already burning, no intensity update",_unit,_intensity);
};
_fireParticle setDropInterval (0.01 max linearConversion [BURN_MAX_INTENSITY, BURN_MIN_INTENSITY, _intensity, 0.03, 0.1, false]);
_fireParticle setParticleParams [
["\A3\data_f\ParticleEffects\Universal\Universal", 16, 10, 32], // sprite sheet values
"", // animation name
"Billboard", // particle type
1, // timer period
0.7, // lifetime
"destructionEffect2", // position
[0, 0, 1], // move velocity
0, // rotation velocity
10, // weight
7.9, // volume
1, // rubbing
[0.3, 0.3], // size
[
[1, 1, 1, -0],
[1, 1, 1, -1],
[1, 1, 1, -1],
[1, 1, 1, -1],
[1, 1, 1, -0]
], // colour
[0.5, 1], // animation speed
1, // random dir period
0, // random dir intensity
"", // on timer script
"", // before destroy script
_unit, // particle source
0,
false,
0,
[[0.8, 0.6, 0.2, 1]] // emissive color
];
_fireParticle setParticleRandom [
0.04 * _intensity, // life time
[0.05, 0.05, 2], // position
[0.05 * _intensity, 0.05 * _intensity, 0.05 * _intensity], // move velocity
0, // rotation velocity
0.06 * _intensity, // size
[0, 0, 0, 0], // color
0, // random direction period
0 // random direction intensity
];
TRACE_2("unit already burning, updating intensity",_unit,_intensity);
_smokeParticle setParticleCircle [0, [0, 0, 0]];
_smokeParticle setParticleRandom [
0, // life time
[0.25, 0.25, 0], // position
[0.2, 0.2, 0], // move velocity
0, // rotation velocity
0.25, // size
[0, 0, 0, 0.1], // color
0, // random direction period
0 // random direction intensity
];
_smokeParticle setParticleParams [
["\A3\data_f\ParticleEffects\Universal\Universal", 16, 7, 48], // sprite sheet values
"", // animation name
"Billboard", // particle type
1, // timer period
8, // lifetime
[0, 0, 1.1], // position
[0, 0, 1], // move velocity
0, // rotation velocity
10, // weight
7.9, // volume
0.066, // rubbing
[1, 3, 6], // size
[
[0.5, 0.5, 0.5, 0.15],
[0.75, 0.75, 0.75, 0.075],
[1, 1, 1, 0]
], // colour
[0.125], // animation speed
1, // random dir period
0, // random dir intensity
"", // on timer script
"", // before destroy script
_unit // particle source
];
_smokeParticle setDropInterval 0.15;
_unit setVariable [QGVAR(intensity), _intensity, true];
};
_fireLight setLightBrightness ((_intensity * 3) / 10);
_lightFlare setLightBrightness (_intensity / 30);
TRACE_2("setting unit ablaze",_unit,_intensity);
private _distanceToUnit = (_unit distance ace_player);
_fireLight setLightAttenuation [1, 10 max (5 min (10 - _intensity)), 0, 15];
_lightFlare setLightFlareSize (_intensity * (3 / 4)) * FLARE_SIZE_MODIFIER;
_unit setVariable [QGVAR(intensity), _intensity, true];
if (!GVAR(enableFlare)) then {
_lightFlare setLightFlareSize 0;
};
// Fire simulation (fire sources are handled differently)
[QGVAR(burnSimulation), [_unit, _instigator], _unit] call CBA_fnc_targetEvent;
// always keep flare visible to perceiving unit as long as it isnt the player
if (_unit isNotEqualTo ace_player) then {
private _relativeAttachPoint = [0, 0, 0.3];
if (_distanceToUnit > 1.5) then {
_relativeAttachPoint = (vectorNormalized (_unit worldToModelVisual (getPos ace_player))) vectorMultiply linearConversion [5, 30, _distanceToUnit, 0.5, 1.5];
_relativeAttachPoint set [2, 0.3 + ((_unit selectionPosition "pelvis") select 2)];
};
_lightFlare attachTo [_unit, _relativeAttachPoint];
};
// Spawn effects for unit
private _burnEffectsJipID = [QGVAR(burnEffects), _unit] call CBA_fnc_globalEventJIP;
[_burnEffectsJipID, _unit] call CBA_fnc_removeGlobalEventJIP;
if (!isGamePaused) then {
// If the unit goes to spectator alive _unit == true and they will be on fire and still take damage
// Only workaround I could think of, kinda clunky
if (_isThisUnitAlive) then {
_isThisUnitAlive = (alive _unit) && { getNumber ((configOf _unit) >> "isPlayableLogic") != 1 };
};
// propagate fire
if ((CBA_missionTime - _lastPropogateUpdate) >= BURN_PROPOGATE_UPDATE) then {
_lastPropogateUpdate = CBA_missionTime;
if !([ace_player] call FUNC(isBurning)) then {
if ((vehicle _unit) isEqualTo (vehicle ace_player)) then {
if (0.5 > random 1) then {
[QGVAR(burn), [ace_player, _intensity * (7 / 8), _instigator]] call CBA_fnc_globalEvent;
};
} else {
if ((ace_player isKindOf "Man") && {_unit isNotEqualTo ace_player} && {isDamageAllowed ace_player && {ace_player getVariable [QEGVAR(medical,allowDamage), true]}}) then {
private _burnCounter = _unit getVariable [QGVAR(burnCounter), 0];
if (_distanceToUnit < BURN_PROPOGATE_DISTANCE) then {
if (_burnCounter < BURN_PROPOGATE_COUNTER_MAX) then {
_burnCounter = _burnCounter + 1;
} else {
[QGVAR(burn), [ace_player, _intensity * (3 / 4), _instigator]] call CBA_fnc_globalEvent;
};
} else {
_burnCounter = 0;
};
_unit setVariable [QGVAR(burnCounter), _burnCounter];
};
};
};
};
// update intensity/fire reactions
if ((CBA_missionTime - _lastIntensityUpdate) >= INTENSITY_UPDATE) then {
_lastIntensityUpdate = CBA_missionTime;
_intensity = _intensity - INTENSITY_LOSS - (rain / 10);
if (local _unit) then {
if (_isThisUnitAlive) then {
if !(IS_UNCONSCIOUS(_unit)) then {
if !(isPlayer _unit) then {
private _sdr = _unit getVariable [QGVAR(stopDropRoll), false];
if ((_unit isEqualTo vehicle _unit) && (_sdr || ({ 0.05 > random 1 }))) then {
_unit setVariable [QGVAR(stopDropRoll), true];
if !(_sdr) then {
TRACE_1("stop,drop,roll!",_unit);
_unit setUnitPos "DOWN";
doStop _unit;
};
// queue up a bunch of animations
for "_i" from 0 to 2 do {
[_unit, selectRandom ["amovppnemstpsnonwnondnon_amovppnemevasnonwnondl", "amovppnemstpsnonwnondnon_amovppnemevasnonwnondr"], 0] call EFUNC(common,doAnimation);
};
_intensity = _intensity - (1 / _intensity);
} else {
private _group = (group _unit);
private _vehicle = vehicle _unit;
if (_vehicle != _unit) then {
TRACE_1("Ejecting",_unit);
_unit leaveVehicle _vehicle;
unassignVehicle _unit;
_unit action ["eject",_vehicle];
};
_unit disableAI "TARGET";
_unit disableAI "AUTOTARGET";
// Run away
if (leader _group != _unit) then {
[_unit] join grpNull;
};
_unit doMove ((getPosATL _unit) getPos [20 + random 35, floor (random 360)]);
_unit setSpeedMode "FULL";
_unit setSuppression 1;
};
} else {
if ((animationState _unit) in PRONE_ROLLING_ANIMS) then {
// decrease intensity of burn
_intensity = _intensity * INTENSITY_DECREASE_MULT_ROLLING;
};
};
[_unit] call FUNC(burnReaction);
};
// Common burn areas are the hands and face https://www.ncbi.nlm.nih.gov/pubmed/16899341/
private _woundSelection = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.77, 0.5, 0.8, 0.8, 0.3, 0.3];
if (GET_PAIN_PERCEIVED(_unit) < (PAIN_UNCONSCIOUS + random 0.2)) then {
// keep pain around unconciousness limit to allow for more fun interactions
[_unit, _intensity / BURN_MAX_INTENSITY, _woundSelection, "burn", _instigator] call EFUNC(medical,addDamageToUnit);
} else {
[_unit, 0.15, _woundSelection, "burn", _instigator] call EFUNC(medical,addDamageToUnit);
};
};
_unit setVariable [QGVAR(intensity), _intensity, true]; // globally sync intensity across all clients to make sure simulation is deterministic
};
};
private _burnIndicatorPFH = _unit getVariable [QGVAR(burnUIPFH), -1];
if (_unit isEqualTo ace_player && { _isThisUnitAlive } && { _burnIndicatorPFH < 0 }) then {
_burnIndicatorPFH = [LINKFUNC(burnIndicator), 1, _unit] call CBA_fnc_addPerFrameHandler;
_unit setVariable [QGVAR(burnUIPFH), _burnIndicatorPFH];
};
};
}, 0, [_unit, _intensity, _instigator], {
TRACE_1("burn init",GVAR(enableFlare));
// init function
private _params = _this getVariable "params";
_params params ["_unit", "_startingIntensity"];
_intensity = _startingIntensity;
private _unitPos = getPos _unit;
_fireParticle = "#particlesource" createVehicleLocal _unitPos;
_fireParticle attachTo [_unit, [0, 0, 0]];
_fireParticle setDropInterval 0.03;
_smokeParticle = "#particlesource" createVehicleLocal _unitPos;
_fireLight = "#lightpoint" createVehicleLocal _unitPos;
_fireLight setLightIntensity 0;
_fireLight setLightAmbient [0.8, 0.6, 0.2];
_fireLight setLightColor [1, 0.5, 0.4];
_fireLight attachTo [_unit, [0, 0, 0]];
_fireLight setLightDayLight false;
_lightFlare = "#lightpoint" createVehicleLocal _unitPos;
_lightFlare setLightIntensity 0;
_lightFlare setLightColor [1, 0.8, 0.8];
_lightFlare setLightUseFlare true;
_lightFlare setLightFlareMaxDistance 100;
_lightFlare setLightFlareSize 0;
if (_unit isNotEqualTo ace_player) then {
private _relativeAttachPoint = (vectorNormalized (_unit worldToModelVisual (getPos ace_player))) vectorMultiply 1;
_relativeAttachPoint set [2, 0.5];
_lightFlare attachTo [_unit, _relativeAttachPoint];
} else {
_lightFlare attachTo [_unit, [0, 0, 0.3]];
};
if (isServer) then {
_fireSound = createSoundSource ["Sound_Fire", _unitPos, [], 0];
_fireSound attachTo [_unit, [0, 0, 0], "Head"];
};
_unit setVariable [QGVAR(burning), true];
_unit setVariable [QGVAR(intensity), _intensity];
_unit setVariable [QGVAR(burnUIPFH), -1];
if (local _unit) then {
if (_unit isEqualTo ace_player) then {
private _burnIndicatorPFH = [LINKFUNC(burnIndicator), 1, _unit] call CBA_fnc_addPerFrameHandler;
_unit setVariable [QGVAR(burnUIPFH), _burnIndicatorPFH];
};
[_unit, false] call FUNC(burnReaction);
};
_lastIntensityUpdate = 0;
_lastPropogateUpdate = 0;
_isThisUnitAlive = true;
}, {
(_this getVariable "params") params ["_unit"];
// deinit function
deleteVehicle _fireParticle;
deleteVehicle _smokeParticle;
deleteVehicle _fireLight;
deleteVehicle _lightFlare;
deleteVehicle _fireSound;
if (local _unit) then {
if (!isPlayer _unit) then {
_unit setUnitPos "AUTO";
_unit setVariable [QGVAR(stopDropRoll), false];
};
};
_unit setVariable [QGVAR(burning), false];
_unit setVariable [QGVAR(burnCounter), 0];
}, {
// run condition
true
}, {
// exit condition
(_this getVariable "params") params ["_unit"];
private _unitAlive = (alive _unit) && { getNumber ((configOf _unit) >> "isPlayableLogic") != 1 };
private _unitIsUnit = { (_unit != vehicle _unit) && { isNull vehicle _unit } };
!_unitAlive || _unitIsUnit || { _intensity <= BURN_MIN_INTENSITY } || { !([_unit] call FUNC(isBurning)) }
}, ["_intensity", "_fireParticle", "_smokeParticle", "_fireLight", "_fireSound", "_lightFlare", "_lastIntensityUpdate", "_lastPropogateUpdate", "_isThisUnitAlive"]] call CBA_fnc_createPerFrameHandlerObject;
_unit setVariable [QGVAR(jipID), _burnEffectsJipID, true];

View File

@ -0,0 +1,191 @@
#include "..\script_component.hpp"
/*
* Author: tcvm, johnb43
* Spawns particle effects for a burning unit.
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* None
*
* Example:
* player call ace_fire_fnc_burnEffects
*
* Public: No
*/
params ["_unit"];
// Spawn particles
private _unitPos = getPos _unit;
private _fireParticle = objNull;
private _smokeParticle = objNull;
private _fireLight = objNull;
private _lightFlare = objNull;
if (hasInterface) then {
_fireParticle = createVehicleLocal ["#particlesource", _unitPos, [], 0, "CAN_COLLIDE"];
_fireParticle attachTo [_unit];
_fireParticle setDropInterval 0.03;
_smokeParticle = createVehicleLocal ["#particlesource", _unitPos, [], 0, "CAN_COLLIDE"];
_fireLight = createVehicleLocal ["#lightpoint", _unitPos, [], 0, "CAN_COLLIDE"];
_fireLight setLightIntensity 0;
_fireLight setLightAmbient [0.8, 0.6, 0.2];
_fireLight setLightColor [1, 0.5, 0.4];
_fireLight attachTo [_unit];
_fireLight setLightDayLight false;
_lightFlare = createVehicleLocal ["#lightpoint", _unitPos, [], 0, "CAN_COLLIDE"];
_lightFlare setLightIntensity 0;
_lightFlare setLightColor [1, 0.8, 0.8];
_lightFlare setLightUseFlare true;
_lightFlare setLightFlareMaxDistance 100;
_lightFlare setLightFlareSize 0;
if (_unit != ACE_player) then {
private _relativeAttachPoint = vectorNormalized (_unit worldToModelVisual (getPos ACE_player));
_relativeAttachPoint set [2, 0.5];
_lightFlare attachTo [_unit, _relativeAttachPoint];
} else {
_lightFlare attachTo [_unit, [0, 0, 0.3]];
};
};
private _fireSound = objNull;
if (isServer) then {
_fireSound = createSoundSource ["Sound_Fire", _unitPos, [], 0];
_fireSound attachTo [_unit, [0, 0, 0], "Head"];
};
[{
params ["_args", "_pfhID"];
_args params ["_unit", "_fireParticle", "_smokeParticle", "_fireLight", "_lightFlare", "_fireSound"];
if (isNull _unit || {!(_unit call FUNC(isBurning))}) exitWith {
_pfhID call CBA_fnc_removePerFrameHandler;
deleteVehicle _fireParticle;
deleteVehicle _smokeParticle;
deleteVehicle _fireLight;
deleteVehicle _lightFlare;
deleteVehicle _fireSound;
};
// Display burn indicators
if (_unit == ACE_player && {alive _unit} && {isNil {_unit getVariable QGVAR(burnUIPFH)}}) then { // This accounts for player remote controlled a new unit
private _burnIndicatorPFH = [LINKFUNC(burnIndicator), 1, _unit] call CBA_fnc_addPerFrameHandler;
_unit setVariable [QGVAR(burnUIPFH), _burnIndicatorPFH];
};
if (!hasInterface) exitWith {};
private _intensity = _unit getVariable [QGVAR(intensity), 0];
_fireParticle setDropInterval (0.01 max linearConversion [BURN_MAX_INTENSITY, BURN_MIN_INTENSITY, _intensity, 0.03, 0.1, false]);
_fireParticle setParticleParams [
["\A3\data_f\ParticleEffects\Universal\Universal", 16, 10, 32], // sprite sheet values
"", // animation name
"Billboard", // particle type
1, // timer period
0.7, // lifetime
"destructionEffect2", // position
[0, 0, 1], // move velocity
0, // rotation velocity
10, // weight
7.9, // volume
1, // rubbing
[0.3, 0.3], // size
[
[1, 1, 1, -0],
[1, 1, 1, -1],
[1, 1, 1, -1],
[1, 1, 1, -1],
[1, 1, 1, -0]
], // colour
[0.5, 1], // animation speed
1, // random dir period
0, // random dir intensity
"", // on timer script
"", // before destroy script
_unit, // particle source
0,
false,
0,
[[0.8, 0.6, 0.2, 1]] // emissive color
];
_fireParticle setParticleRandom [
0.04 * _intensity, // life time
[0.05, 0.05, 2], // position
[0.05, 0.05, 0.05] vectorMultiply _intensity, // move velocity
0, // rotation velocity
0.06 * _intensity, // size
[0, 0, 0, 0], // color
0, // random direction period
0 // random direction intensity
];
_smokeParticle setDropInterval 0.15;
_smokeParticle setParticleCircle [0, [0, 0, 0]];
_smokeParticle setParticleParams [
["\A3\data_f\ParticleEffects\Universal\Universal", 16, 7, 48], // sprite sheet values
"", // animation name
"Billboard", // particle type
1, // timer period
8, // lifetime
[0, 0, 1.1], // position
[0, 0, 1], // move velocity
0, // rotation velocity
10, // weight
7.9, // volume
0.066, // rubbing
[1, 3, 6], // size
[
[0.5, 0.5, 0.5, 0.15],
[0.75, 0.75, 0.75, 0.075],
[1, 1, 1, 0]
], // colour
[0.125], // animation speed
1, // random dir period
0, // random dir intensity
"", // on timer script
"", // before destroy script
_unit // particle source
];
_smokeParticle setParticleRandom [
0, // life time
[0.25, 0.25, 0], // position
[0.2, 0.2, 0], // move velocity
0, // rotation velocity
0.25, // size
[0, 0, 0, 0.1], // color
0, // random direction period
0 // random direction intensity
];
_fireLight setLightBrightness ((_intensity * 3) / 10);
_fireLight setLightAttenuation [1, 10 max (5 min (10 - _intensity)), 0, 15];
_lightFlare setLightBrightness (_intensity / 30);
_lightFlare setLightFlareSize (_intensity * (3 / 4)) * FLARE_SIZE_MODIFIER;
if (!GVAR(enableFlare)) then {
_lightFlare setLightFlareSize 0;
};
// Always keep flare visible to perceiving unit as long as it isn't the player
if (_unit != ACE_player) then {
private _distanceToUnit = _unit distance ACE_player;
private _relativeAttachPoint = [0, 0, 0.3];
if (_distanceToUnit > 1.5) then {
_relativeAttachPoint = (vectorNormalized (_unit worldToModelVisual (getPos ACE_player))) vectorMultiply linearConversion [5, 30, _distanceToUnit, 0.5, 1.5];
_relativeAttachPoint set [2, 0.3 + ((_unit selectionPosition "pelvis") select 2)];
};
_lightFlare attachTo [_unit, _relativeAttachPoint];
};
}, 0, [_unit, _fireParticle, _smokeParticle, _fireLight, _lightFlare, _fireSound]] call CBA_fnc_addPerFrameHandler;

View File

@ -11,26 +11,30 @@
* None
*
* Example:
* [player, 4] call ace_fire_fnc_burnIndicator
* [player, _pfhID] call ace_fire_fnc_burnIndicator
*
* Public: No
*/
params ["_unit", "_pfhHandle"];
params ["_unit", "_pfhID"];
if !(IS_UNCONSCIOUS(_unit)) then {
private _iteration = _unit getVariable [QGVAR(indicatorIteration), 0];
if (_iteration == 0) then {
QGVAR(indicatorLayer) cutRsc [QGVAR(onFire1), "PLAIN"];
_iteration = 1;
} else {
QGVAR(indicatorLayer) cutRsc [QGVAR(onFire2), "PLAIN"];
_iteration = 0;
};
_unit setVariable [QGVAR(indicatorIteration), _iteration];
if (!alive _unit || {!(_unit call FUNC(isBurning))}) exitWith {
_pfhID call CBA_fnc_removePerFrameHandler;
_unit setVariable [QGVAR(burnUIPFH), nil];
};
if (!([_unit] call FUNC(isBurning)) || {!alive _unit}) then {
[_pfhHandle] call CBA_fnc_removePerFrameHandler;
_unit setVariable [QGVAR(burnUIPFH), -1];
// Don't show burn overlay if unconscious or dead
if !(_unit call EFUNC(common,isAwake)) exitWith {};
private _iteration = _unit getVariable [QGVAR(indicatorIteration), 0];
if (_iteration == 0) then {
QGVAR(indicatorLayer) cutRsc [QGVAR(onFire1), "PLAIN"];
_iteration = 1;
} else {
QGVAR(indicatorLayer) cutRsc [QGVAR(onFire2), "PLAIN"];
_iteration = 0;
};
_unit setVariable [QGVAR(indicatorIteration), _iteration];

View File

@ -5,7 +5,6 @@
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Should unit throw its current weapon <BOOL>
*
* Return Value:
* None
@ -13,19 +12,15 @@
* Public: No
*/
params ["_unit", ["_throwWeapon", true]];
params ["_unit"];
if (
_throwWeapon
&& {GVAR(dropWeapon) > 0}
&& {_unit in _unit && {(currentWeapon _unit) isNotEqualTo ""}}
&& {!isPlayer _unit || GVAR(dropWeapon) >= 2}
GVAR(dropWeapon) > 0 &&
{isNull objectParent _unit} &&
{(currentWeapon _unit) != ""} &&
{!isPlayer _unit || GVAR(dropWeapon) == 2}
) then {
[_unit] call EFUNC(common,throwWeapon);
_unit call EFUNC(common,throwWeapon);
};
if (_unit isKindOf "CAManBase") then {
private _soundID = floor (1 + random 15);
private _sound = format [QGVAR(scream_%1), _soundID];
[QGVAR(playScream), [_sound, _unit]] call CBA_fnc_globalEvent;
};
[QGVAR(playScream), [format [QGVAR(scream_%1), floor (1 + random 15)], _unit]] call CBA_fnc_globalEvent;

View File

@ -0,0 +1,167 @@
#include "..\script_component.hpp"
/*
* Author: tcvm, johnb43
* Simulates fire intensity over time on burning units.
* Arbitrary values to ignite people. Assumed maximum is "10".
*
* Arguments:
* 0: Unit <OBJECT>
* 1: Instigator <OBJECT>
*
* Return Value:
* None
*
* Example:
* [player, player] call ace_fire_fnc_burnSimulation
*
* Public: No
*/
params ["_unit", "_instigator"];
[{
params ["_args", "_pfhID"];
_args params ["_unit", "_instigator"];
if (isNull _unit) exitWith {
TRACE_1("unit is null",_unit);
_pfhID call CBA_fnc_removePerFrameHandler;
};
// Locality has changed
if (!local _unit) exitWith {
TRACE_1("unit is no longer local",_unit);
_pfhID call CBA_fnc_removePerFrameHandler;
[QGVAR(burnSimulation), [_unit, _instigator], _unit] call CBA_fnc_targetEvent;
};
// If the unit is invulnerable, in water or if the fire has died out, stop burning the unit
if (
!(_unit call FUNC(isBurning)) ||
{!(isDamageAllowed _unit && {_unit getVariable [QEGVAR(medical,allowDamage), true]})} ||
{private _eyePos = eyePos _unit; surfaceIsWater _eyePos && {(_eyePos select 2) < 0.1}}
) exitWith {
TRACE_3("unit is no longer burning, invulnerable or in water",_unit,_unit call FUNC(isBurning),isDamageAllowed _unit && {_unit getVariable [ARR_2(QEGVAR(medical,allowDamage),true)]});
// Remove global effects
(_unit getVariable [QGVAR(jipID), ""]) call CBA_fnc_removeGlobalEventJIP;
// Update globally that the unit isn't burning anymore
_unit setVariable [QGVAR(intensity), nil, true];
_pfhID call CBA_fnc_removePerFrameHandler;
if (!isNil {_unit getVariable QGVAR(stopDropRoll)} && {!isPlayer _unit}) then {
_unit setUnitPos "AUTO";
_unit setVariable [QGVAR(stopDropRoll), nil, true];
};
};
if (isGamePaused) exitWith {};
private _intensity = _unit getVariable [QGVAR(intensity), 0];
// Propagate fire to other units (alive or dead) if it's intense
if (_intensity >= BURN_THRESHOLD_INTENSE) then {
TRACE_2("check for other units",_unit,_intensity);
{
private _distancePercent = 1 - ((_unit distance _x) / BURN_PROPAGATE_DISTANCE);
private _adjustedIntensity = _intensity * _distancePercent;
// Don't burn if intensity is too low or already burning with higher intensity
if (BURN_MIN_INTENSITY > _adjustedIntensity || {(_x getVariable [QGVAR(intensity), 0]) > _adjustedIntensity}) then {
continue;
};
[QGVAR(burn), [_x, _adjustedIntensity, _instigator], _x] call CBA_fnc_targetEvent;
TRACE_3("propagate fire",_x,_intensity,_adjustedIntensity);
} forEach nearestObjects [_unit, ["CAManBase"], BURN_PROPAGATE_DISTANCE];
};
// Update intensity/fire reactions
if (CBA_missionTime >= _unit getVariable [QGVAR(intensityUpdate), 0]) then {
TRACE_2("update intensity",_unit,_intensity);
_unit setVariable [QGVAR(intensityUpdate), CBA_missionTime + INTENSITY_UPDATE];
_intensity = _intensity - INTENSITY_LOSS - (rain / 10);
if (_unit call EFUNC(common,isAwake)) then {
if (_unit call EFUNC(common,isPlayer)) then {
// Decrease intensity of burn if rolling around
if ((animationState _unit) in PRONE_ROLLING_ANIMS) then {
_intensity = _intensity * INTENSITY_DECREASE_MULT_ROLLING;
};
} else {
private _sdr = _unit getVariable [QGVAR(stopDropRoll), false];
private _vehicle = objectParent _unit;
if (isNull _vehicle && {_sdr || {0.05 > random 1}}) then {
_unit setVariable [QGVAR(stopDropRoll), true, true];
if (!_sdr) then {
TRACE_1("stop, drop, roll!",_unit);
_unit setUnitPos "DOWN";
doStop _unit;
};
// Queue up a bunch of animations
for "_i" from 0 to 2 do {
[_unit, selectRandom ["amovppnemstpsnonwnondnon_amovppnemevasnonwnondl", "amovppnemstpsnonwnondnon_amovppnemevasnonwnondr"], 0] call EFUNC(common,doAnimation);
};
_intensity = _intensity - (1 / _intensity);
} else {
// Make the unit leave the vehicle
if (_vehicle != _unit) then {
TRACE_1("Ejecting",_unit);
_unit leaveVehicle _vehicle;
unassignVehicle _unit;
_unit action ["Eject", _vehicle];
};
_unit disableAI "TARGET";
_unit disableAI "AUTOTARGET";
// Run away, erraticly
if (leader group _unit != _unit) then {
[_unit] join grpNull;
};
_unit doMove ((getPosATL _unit) getPos [20 + random 35, floor (random 360)]);
_unit setSpeedMode "FULL";
_unit setSuppression 1;
};
};
// Play screams and throw weapon (if enabled)
_unit call FUNC(burnReaction);
};
if (!isNull _instigator) then {
_unit setVariable [QEGVAR(medical,lastDamageSource), _instigator];
_unit setVariable [QEGVAR(medical,lastInstigator), _instigator];
};
// Common burn areas are the hands and face https://www.ncbi.nlm.nih.gov/pubmed/16899341/
private _bodyPart = ["Head", "Body", "LeftArm", "RightArm", "LeftLeg", "RightLeg"] selectRandomWeighted [0.77, 0.5, 0.8, 0.8, 0.3, 0.3];
// Keep pain around unconciousness limit to allow for more fun interactions
private _damageToAdd = [0.15, _intensity / BURN_MAX_INTENSITY] select (!alive _unit || {GET_PAIN_PERCEIVED(_unit) < (PAIN_UNCONSCIOUS + random 0.2)});
// Use event directly, as ace_medical_fnc_addDamageToUnit requires unit to be alive
[QEGVAR(medical,woundReceived), [_unit, [[_damageToAdd, _bodyPart, _damageToAdd]], _instigator, "burn"]] call CBA_fnc_localEvent;
_unit setVariable [QGVAR(intensity), _intensity, true]; // Globally sync intensity across all clients to make sure simulation is deterministic
};
}, BURN_PROPAGATE_UPDATE, [_unit, _instigator]] call CBA_fnc_addPerFrameHandler;

View File

@ -1,43 +1,48 @@
#include "..\script_component.hpp"
/*
* Author: tcvm
* Handles various fire objects and determines if local units deserves to get burned.
* Used to handle external burning objects, not used internally because internal methods are more performant.
* Author: tcvm, johnb43
* Handles various objects on fire and determines if units close to objects deserve to get burned.
*
* Arguments:
* 0: Unit on fire <OBJECT>
* 1: PFH Handle <NUMBER>
* None
*
* Return Value:
* None
*
* Example:
* [ace_fire_fnc_fireManagerPFH, 0.25, [_unit]] call CBA_fnc_addPerFrameHandler
* ace_fire_fnc_fireManagerPFH call CBA_fnc_addPerFrameHandler
*
* Public: No
*/
params ["_args", "_handle"];
{
_y params ["_fireLogic", "_radius", "_intensity", "_condition", "_conditionArgs"];
TRACE_2("fireManagerPFH loop",_x,_y);
[GVAR(fireSources), {
_value params ["", "", "", "_condition", "_conditionArgs"];
_conditionArgs call _condition;
}] call CBA_fnc_hashFilter;
// Remove when condition is no longer valid
if !(_conditionArgs call _condition) then {
TRACE_2("condition no longer valid, deleting",_x,_y);
[GVAR(fireSources), {
_value params ["_source", "_radius", "_intensity"];
private _attachedObject = attachedTo _source;
private _sourcePos = getPosATL _source;
if (_attachedObject isNotEqualTo objNull) then {
_sourcePos = getPosATL _attachedObject;
detach _fireLogic;
deleteVehicle _fireLogic;
GVAR(fireSources) deleteAt _x;
continue;
};
private _nearEntities = _sourcePos nearEntities ["Man", _radius];
// Burn units (alive or dead) close to the fire
{
private _burning = [_x] call FUNC(isBurning);
if !(_burning) then {
private _distancePercent = 1 - ((_sourcePos distance _x) / _radius);
[QGVAR(burn), [_x, _intensity * _distancePercent]] call CBA_fnc_globalEvent;
private _distancePercent = 1 - ((_fireLogic distance _x) / _radius);
private _adjustedIntensity = _intensity * _distancePercent;
// Don't burn if intensity is too low or already burning with higher intensity
if (BURN_MIN_INTENSITY > _adjustedIntensity || {(_x getVariable [QGVAR(intensity), 0]) > _adjustedIntensity}) then {
continue;
};
} forEach _nearEntities;
}] call CBA_fnc_hashEachPair;
[QGVAR(burn), [_x, _adjustedIntensity], _x] call CBA_fnc_targetEvent;
TRACE_3("propagate fire",_x,_intensity,_adjustedIntensity);
} forEach nearestObjects [_fireLogic, ["CAManBase"], _radius];
} forEach GVAR(fireSources);

View File

@ -1,10 +1,10 @@
#include "..\script_component.hpp"
/*
* Author: commy2
* Check if object is burning.
* Check if an object is burning.
*
* Arguments:
* 0: Vehicle <OBJECT>
* 0: Object <OBJECT>
*
* Return Value:
* None
@ -15,6 +15,6 @@
* Public: Yes
*/
params [["_unit", objNull, [objNull]]];
params [["_object", objNull, [objNull]]];
_unit getVariable [QGVAR(burning), false]
(_object getVariable [QGVAR(intensity), 0]) > BURN_MIN_INTENSITY

View File

@ -18,4 +18,4 @@
params ["", "_patient"];
[_patient] call FUNC(isBurning)
_patient call FUNC(isBurning)

View File

@ -5,8 +5,8 @@
*
* Arguments:
* 0: Arguments <ARRAY>
* 0: Medic <OBJECT>
* 1: Patient <OBJECT>
* - 0: Medic (not used) <OBJECT>
* - 1: Patient <OBJECT>
*
* Return Value:
* Continue pat down <BOOL>
@ -18,6 +18,6 @@
*/
params ["_args"];
_args params ["_medic", "_patient"];
_args params ["", "_patient"];
[_patient] call FUNC(isBurning)
_patient call FUNC(isBurning)

View File

@ -2,10 +2,13 @@
/*
* Author: tcvm
* Decreases burning intensity on successful medical action.
* The medical action is looped until the user stops the interaction or the unit is no longer burning.
*
* Arguments:
* 0: Medic <OBJECT>
* 1: Patient <OBJECT>
* 2: Body Part <STRING>
* 3: Treatment <STRING>
*
* Return Value:
* None
@ -20,17 +23,21 @@ params ["_medic", "_patient", "_bodyPart", "_classname"];
private _intensity = _patient getVariable [QGVAR(intensity), 0];
_intensity = _intensity * INTENSITY_DECREASE_MULT_PAT_DOWN;
_patient setVariable [QGVAR(intensity), _intensity, true];
if (_intensity > BURN_MIN_INTENSITY) then {
TRACE_1("patient still burning, looping",_this);
if (EGVAR(medical_gui,pendingReopen)) then {
LOG("temporarily blocking medical menu reopen");
EGVAR(medical_gui,pendingReopen) = false;
[{EGVAR(medical_gui,pendingReopen) = true}] call CBA_fnc_execNextFrame;
};
[_medic, _patient, _bodyPart, _classname] call EFUNC(medical_treatment,treatment);
// If the unit is still burning, loop the medical action
if !(_patient call FUNC(isBurning)) exitWith {
TRACE_1("patient no longer burning, quitting",_this);
};
TRACE_1("patient still burning, looping",_this);
if (EGVAR(medical_gui,pendingReopen)) then {
TRACE_1("temporarily blocking medical menu reopen",_this);
EGVAR(medical_gui,pendingReopen) = false;
[{EGVAR(medical_gui,pendingReopen) = true}] call CBA_fnc_execNextFrame;
};
[_medic, _patient, _bodyPart, _classname] call EFUNC(medical_treatment,treatment);

Some files were not shown because too many files have changed in this diff Show More