mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Vehicle damage - Code cleanup (#9831)
* Cook-off improvements * More changes * Update fnc_getVehicleAmmo.sqf * Better engine fire placement * Update fnc_detonateAmmunition.sqf * Update XEH_postInit.sqf * Update fnc_getVehicleAmmo.sqf * Update events-framework.md * Various improvements * Separate effect handling * Tweaks * Update XEH_postInit.sqf * Prevent double ammo detonation * Fixed objects not being able to cook-off again * Added incendiary rounds as source of box cookoff * Converted enable setting to bool * Fixed brackets * Update fnc_cookOff.sqf * Update CfgEden.hpp * Removed GVAR(enable), added GVAR(enableFire) back * Vehicle damage fixes * Made hitpoint hash common * Update fnc_addEventHandler.sqf * Update fnc_medicalDamage.sqf * Update fnc_handleBail.sqf * Changed API * Remove `CBA_fnc_getConfigEntry` as much as possible, as it's 2x slower * More cleanup * More cleanup * Fix merging issues, remove turret tossing * Update translations * More cleanup * Reverted some logic back to original, minor tweaks & fixes * Fix undefined variable * Cleanup * Fixed bad logic * Update addons/vehicle_damage/script_macros.hpp Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update addons/vehicle_damage/functions/fnc_handleDamage.sqf * Update addons/vehicle_damage/stringtable.xml Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update addons/vehicle_damage/stringtable.xml Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> * Update addons/vehicle_damage/XEH_postInit.sqf Co-authored-by: PabstMirror <pabstmirror@gmail.com> --------- Co-authored-by: Grim <69561145+LinkIsGrim@users.noreply.github.com> Co-authored-by: PabstMirror <pabstmirror@gmail.com>
This commit is contained in:
parent
2682778499
commit
80b2fa9a05
@ -21,9 +21,6 @@ class CfgAmmo {
|
|||||||
class M_Vorona_HEAT;
|
class M_Vorona_HEAT;
|
||||||
class M_SPG9_HEAT;
|
class M_SPG9_HEAT;
|
||||||
class R_MRAAWS_HEAT_F;
|
class R_MRAAWS_HEAT_F;
|
||||||
class B_338_Ball;
|
|
||||||
|
|
||||||
class ACE_G_40mm_HE;
|
|
||||||
|
|
||||||
CREATE_INCENDIARY_AMMO(BulletBase, BulletCore, 0.1);
|
CREATE_INCENDIARY_AMMO(BulletBase, BulletCore, 0.1);
|
||||||
CREATE_INCENDIARY_AMMO(ShellBase, ShellCore, 1.0);
|
CREATE_INCENDIARY_AMMO(ShellBase, ShellCore, 1.0);
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
|
|
||||||
class Extended_PreStart_EventHandlers {
|
class Extended_PreStart_EventHandlers {
|
||||||
class ADDON {
|
class ADDON {
|
||||||
init = QUOTE(call COMPILE_SCRIPT(XEH_preStart));
|
init = QUOTE(call COMPILE_SCRIPT(XEH_preStart));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Extended_PostInit_EventHandlers {
|
|
||||||
class ADDON {
|
|
||||||
init = QUOTE(call COMPILE_SCRIPT(XEH_postInit));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Extended_PreInit_EventHandlers {
|
class Extended_PreInit_EventHandlers {
|
||||||
class ADDON {
|
class ADDON {
|
||||||
init = QUOTE(call COMPILE_SCRIPT(XEH_preInit));
|
init = QUOTE(call COMPILE_SCRIPT(XEH_preInit));
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Extended_PostInit_EventHandlers {
|
||||||
|
class ADDON {
|
||||||
|
init = QUOTE(call COMPILE_SCRIPT(XEH_postInit));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -28,6 +28,7 @@ class CfgVehicles {
|
|||||||
GVAR(engineFireProb) = 0.5;
|
GVAR(engineFireProb) = 0.5;
|
||||||
GVAR(detonationDuringFireProb) = 0.2;
|
GVAR(detonationDuringFireProb) = 0.2;
|
||||||
GVAR(canHaveFireRing) = 0;
|
GVAR(canHaveFireRing) = 0;
|
||||||
|
EGVAR(cookoff,canHaveFireJet) = 1;
|
||||||
};
|
};
|
||||||
class Wheeled_APC_F: Car_F {
|
class Wheeled_APC_F: Car_F {
|
||||||
GVAR(hullDetonationProb) = 0.2;
|
GVAR(hullDetonationProb) = 0.2;
|
||||||
@ -38,6 +39,7 @@ class CfgVehicles {
|
|||||||
GVAR(engineFireProb) = 0.5;
|
GVAR(engineFireProb) = 0.5;
|
||||||
GVAR(detonationDuringFireProb) = 0.2;
|
GVAR(detonationDuringFireProb) = 0.2;
|
||||||
GVAR(canHaveFireRing) = 0;
|
GVAR(canHaveFireRing) = 0;
|
||||||
|
EGVAR(cookoff,canHaveFireJet) = 1;
|
||||||
};
|
};
|
||||||
class APC_Tracked_01_base_F: Tank_F {};
|
class APC_Tracked_01_base_F: Tank_F {};
|
||||||
class B_APC_Tracked_01_base_F: APC_Tracked_01_base_F {};
|
class B_APC_Tracked_01_base_F: APC_Tracked_01_base_F {};
|
||||||
@ -288,4 +290,3 @@ class CfgVehicles {
|
|||||||
GVAR(canHaveFireRing) = 1;
|
GVAR(canHaveFireRing) = 1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
PREP(abandon);
|
PREP(abandon);
|
||||||
PREP(addEventHandler);
|
PREP(addEventHandler);
|
||||||
PREP(handleBail);
|
|
||||||
PREP(handleVehicleDamage);
|
|
||||||
PREP(handleCookoff);
|
|
||||||
PREP(detonate);
|
|
||||||
PREP(processHit);
|
|
||||||
PREP(handleDetonation);
|
|
||||||
PREP(handleDamage);
|
|
||||||
PREP(knockOut);
|
|
||||||
PREP(addDamage);
|
|
||||||
PREP(handleDamageEjectIfDestroyed);
|
|
||||||
PREP(blowOffTurret);
|
PREP(blowOffTurret);
|
||||||
|
PREP(handleBail);
|
||||||
|
PREP(handleCookoff);
|
||||||
|
PREP(handleDamage);
|
||||||
|
PREP(handleDamageEjectIfDestroyed);
|
||||||
|
PREP(handleDetonation);
|
||||||
|
PREP(handleVehicleDamage);
|
||||||
|
PREP(knockOut);
|
||||||
PREP(medicalDamage);
|
PREP(medicalDamage);
|
||||||
|
PREP(processHit);
|
||||||
|
PREP(setDamage);
|
||||||
|
@ -1,53 +1,65 @@
|
|||||||
#include "script_component.hpp"
|
#include "script_component.hpp"
|
||||||
|
|
||||||
["ace_settingsInitialized", {
|
// Init eject from destroyed vehicles
|
||||||
|
// See https://github.com/acemod/ACE3/pull/6330
|
||||||
|
// Still valid for Arma 2.16
|
||||||
|
{
|
||||||
|
[_x, "Init", {
|
||||||
|
params ["_vehicle"];
|
||||||
|
|
||||||
|
if (!alive _vehicle) exitWith {};
|
||||||
|
|
||||||
|
TRACE_2("ejectIfDestroyed init",_vehicle,typeOf _vehicle);
|
||||||
|
|
||||||
|
_vehicle addEventHandler ["HandleDamage", {call FUNC(handleDamageEjectIfDestroyed)}];
|
||||||
|
}, true, [], true] call CBA_fnc_addClassEventHandler;
|
||||||
|
} forEach EJECT_IF_DESTROYED_VEHICLES;
|
||||||
|
|
||||||
|
["CBA_settingsInitialized", {
|
||||||
TRACE_1("settings init",GVAR(enabled));
|
TRACE_1("settings init",GVAR(enabled));
|
||||||
if (GVAR(enabled)) then {
|
|
||||||
[QGVAR(medicalDamage), LINKFUNC(medicalDamage)] call CBA_fnc_addEventHandler;
|
|
||||||
|
|
||||||
[QGVAR(bailOut), {
|
if (!GVAR(enabled)) exitWith {};
|
||||||
params ["_center", "_crewman", "_vehicle"];
|
|
||||||
TRACE_3("bailOut",_center,_crewman,_vehicle);
|
|
||||||
|
|
||||||
if (isPlayer _crewman) exitWith {};
|
[QGVAR(medicalDamage), LINKFUNC(medicalDamage)] call CBA_fnc_addEventHandler;
|
||||||
if (!alive _crewman || {!([_crewman] call EFUNC(common,isAwake))}) exitWith {};
|
|
||||||
|
|
||||||
unassignVehicle _crewman;
|
if (isServer) then {
|
||||||
_crewman leaveVehicle _vehicle;
|
// To set source and instigator, setDamage must be executed on the server
|
||||||
doGetOut _crewman;
|
[QGVAR(setDamage), {(_this select 0) setDamage (_this select 1)}] call CBA_fnc_addEventHandler;
|
||||||
|
|
||||||
private _angle = floor (random 360);
|
|
||||||
private _dist = (30 + (random 10));
|
|
||||||
private _escape = _center getPos [_dist, _angle];
|
|
||||||
|
|
||||||
_crewman doMove _escape;
|
|
||||||
_crewman setSpeedMode "FULL";
|
|
||||||
}] call CBA_fnc_addEventHandler;
|
|
||||||
|
|
||||||
["Tank", "init", LINKFUNC(addEventHandler), true, [], true] call CBA_fnc_addClassEventHandler;
|
|
||||||
["Wheeled_APC_F", "init", LINKFUNC(addEventHandler), true, [], true] call CBA_fnc_addClassEventHandler;
|
|
||||||
|
|
||||||
if (GVAR(enableCarDamage)) then {
|
|
||||||
["Car", "init", LINKFUNC(addEventHandler), true, [], true] call CBA_fnc_addClassEventHandler;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Blow off turret effect
|
|
||||||
// TODO: Add blowing-off-turret effect to vehicles that cook-off but aren't destroyed (no catastrophic explosion)
|
|
||||||
// The problem is that vehicles are repairable if they haven't been destroyed. So if the turret is gone and vehicle is repaired, how do we handle that?
|
|
||||||
["Tank", "Killed", {
|
|
||||||
if (_this select 3 && random 1 < 0.15) then {
|
|
||||||
(_this select 0) call FUNC(blowOffTurret);
|
|
||||||
};
|
|
||||||
}, true, [], true] call CBA_fnc_addClassEventHandler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// init eject from destroyed vehicle
|
[QGVAR(bailOut), {
|
||||||
{
|
params ["_vehicle", "_unit"];
|
||||||
[_x, "init", {
|
|
||||||
params ["_vehicle"];
|
TRACE_2("bailOut",_vehicle,_unit);
|
||||||
if (!alive _vehicle) exitWith {};
|
|
||||||
TRACE_2("ejectIfDestroyed init",_vehicle,typeOf _vehicle);
|
// Ignore players and the dead
|
||||||
_vehicle addEventHandler ["HandleDamage", {call FUNC(handleDamageEjectIfDestroyed)}];
|
if (_unit call EFUNC(common,isPlayer) || {!(_unit call EFUNC(common,isAwake))}) exitWith {};
|
||||||
}, true, [], true] call CBA_fnc_addClassEventHandler;
|
|
||||||
} forEach EJECT_IF_DESTROYED_VEHICLES;
|
unassignVehicle _unit;
|
||||||
|
_unit leaveVehicle _vehicle;
|
||||||
|
doGetOut _unit;
|
||||||
|
|
||||||
|
private _angle = floor (random 360);
|
||||||
|
private _dist = 30 + (random 10);
|
||||||
|
private _escape = _vehicle getPos [_dist, _angle];
|
||||||
|
|
||||||
|
_unit doMove _escape;
|
||||||
|
_unit setSpeedMode "FULL";
|
||||||
|
}] call CBA_fnc_addEventHandler;
|
||||||
|
|
||||||
|
GVAR(vehicleClassesHitPointHash) = createHashMap;
|
||||||
|
|
||||||
|
["Tank", "Init", LINKFUNC(addEventHandler), true, [], true] call CBA_fnc_addClassEventHandler;
|
||||||
|
|
||||||
|
// Wheeled_APC_F inherits from Car
|
||||||
|
[["Wheeled_Apc_F", "Car"] select GVAR(enableCarDamage), "Init", LINKFUNC(addEventHandler), true, [], true] call CBA_fnc_addClassEventHandler;
|
||||||
|
|
||||||
|
// Blow off turret effect
|
||||||
|
// TODO: Add blowing-off-turret effect to vehicles that cook-off but aren't destroyed (no catastrophic explosion)
|
||||||
|
// The problem is that vehicles are repairable if they haven't been destroyed. So if the turret is gone and vehicle is repaired, how do we handle that?
|
||||||
|
["Tank", "Killed", {
|
||||||
|
if (_this select 3 && random 1 < 0.15) then {
|
||||||
|
(_this select 0) call FUNC(blowOffTurret);
|
||||||
|
};
|
||||||
|
}] call CBA_fnc_addClassEventHandler;
|
||||||
}] call CBA_fnc_addEventHandler;
|
}] call CBA_fnc_addEventHandler;
|
||||||
|
@ -7,7 +7,7 @@ class CfgPatches {
|
|||||||
weapons[] = {};
|
weapons[] = {};
|
||||||
requiredVersion = REQUIRED_VERSION;
|
requiredVersion = REQUIRED_VERSION;
|
||||||
// ammo/vehicle config defines touch all of these
|
// ammo/vehicle config defines touch all of these
|
||||||
requiredAddons[] = { "ace_common", "ace_cookoff" };
|
requiredAddons[] = {"ace_common", "ace_cookoff"};
|
||||||
author = ECSTRING(common,ACETeam);
|
author = ECSTRING(common,ACETeam);
|
||||||
authors[] = {"tcvm"};
|
authors[] = {"tcvm"};
|
||||||
url = ECSTRING(main,URL);
|
url = ECSTRING(main,URL);
|
||||||
|
@ -4,29 +4,34 @@
|
|||||||
* Forces the AI currently in a vehicle to bail out.
|
* Forces the AI currently in a vehicle to bail out.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle in which to bail out <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [tank2] call ace_vehicle_damage_fnc_abandon;
|
* cursorObject call ace_vehicle_damage_fnc_abandon
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle"];
|
params ["_vehicle"];
|
||||||
TRACE_2("abandon",_vehicle,(crew _vehicle) select {alive _x});
|
|
||||||
|
|
||||||
if (_vehicle getVariable [QGVAR(allowCrewInImmobile), false]) exitWith {}; // check for API
|
// Check for API
|
||||||
|
if (_vehicle getVariable [QGVAR(allowCrewInImmobile), false]) exitWith {
|
||||||
|
TRACE_1("API prevented crew from dismounting",_vehicle);
|
||||||
|
};
|
||||||
|
|
||||||
|
TRACE_1("abandon",_vehicle);
|
||||||
|
|
||||||
[{
|
[{
|
||||||
params ["_vehicle"];
|
params ["_vehicle"];
|
||||||
|
|
||||||
_vehicle allowCrewInImmobile false;
|
_vehicle allowCrewInImmobile false;
|
||||||
|
|
||||||
private _center = getPosASL _vehicle;
|
TRACE_2("bailing out crew after delay",_vehicle,crew _vehicle);
|
||||||
TRACE_2("bailing out crew after delay",_vehicle,_center);
|
|
||||||
{
|
{
|
||||||
[QGVAR(bailOut), [_center, _x, _vehicle], _x] call CBA_fnc_targetEvent;
|
[QGVAR(bailOut), [_vehicle, _x], _x] call CBA_fnc_targetEvent;
|
||||||
} forEach crew _vehicle;
|
} forEach (crew _vehicle);
|
||||||
}, _this, random MAX_CREW_BAILOUT_TIME] call CBA_fnc_waitAndExecute;
|
}, _vehicle, random MAX_CREW_BAILOUT_TIME] call CBA_fnc_waitAndExecute;
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
#include "..\script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: tcvm
|
|
||||||
* Sets vehicle damage based on HitIndex. Failing that it falls back to HitPoint name.
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: The vehicle <OBJECT>
|
|
||||||
* 1: Hit Index <NUMBER>
|
|
||||||
* 2: Hit Point <STRING>
|
|
||||||
* 3: Damage <NUMBER>
|
|
||||||
* 4: Whether or not to cap the damage to maximum part damage <BOOL> (default: True)
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [vehicle player, 234, "HitHull"] call ace_vehicle_damage_fnc_addDamage
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
params ["_vehicle", "_hitIndex", "_hitPoint", "_damage", ["_capDamageAtCurret", true]];
|
|
||||||
|
|
||||||
private _currentDamage = _vehicle getHitPointDamage _hitPoint;
|
|
||||||
if (_capDamageAtCurret && { _damage < _currentDamage }) exitWith {
|
|
||||||
TRACE_4("capping damage at current",_capDamageAtCurret,_damage,_currentDamage,_hitPoint);
|
|
||||||
};
|
|
||||||
|
|
||||||
TRACE_4("adding damage to vehicle",_vehicle,_hitIndex,_hitPoint,_damage);
|
|
||||||
if (_hitPoint isEqualTo "#structural") then {
|
|
||||||
_hitPoint = "hithull";
|
|
||||||
_hitIndex = -1;
|
|
||||||
};
|
|
||||||
if (_hitIndex >= 0) then {
|
|
||||||
_vehicle setHitIndex [_hitIndex, _damage, true];
|
|
||||||
} else {
|
|
||||||
_vehicle setHitPointDamage [_hitPoint, _damage, true];
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_hitPoint == "hitengine" && {_damage > 0.9}) then {
|
|
||||||
[QEGVAR(cookoff,engineFireServer), _vehicle] call CBA_fnc_serverEvent;
|
|
||||||
};
|
|
@ -1,110 +1,137 @@
|
|||||||
#include "..\script_component.hpp"
|
#include "..\script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: tcvm
|
* Author: tcvm, johnb43
|
||||||
* Adds the event handler to a vehicle.
|
* Adds the event handler to a vehicle.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle in which to add the event handler to <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [tank2] call ace_vehicle_damage_fnc_addEventHandler;
|
* cursorObject call ace_vehicle_damage_fnc_addEventHandler
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params["_vehicle"];
|
params ["_vehicle"];
|
||||||
TRACE_2("addEventHandler",_vehicle,GVAR(enabled));
|
TRACE_2("addEventHandler",_vehicle,GVAR(enabled));
|
||||||
|
|
||||||
if !(GVAR(enabled)) exitWith {
|
if (!GVAR(enabled)) exitWith {
|
||||||
#ifdef DEBUG_MODE_FULL
|
#ifdef DEBUG_MODE_FULL
|
||||||
[{ ["Warning: Vehicle Damage not enabled...", 2] call CBA_fnc_notify; }, [], 5] call CBA_fnc_waitAndExecute;
|
[CBA_fnc_notify, ["Warning: Vehicle Damage not enabled", 2], 5] call CBA_fnc_waitAndExecute;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
private _hitpointHash = [[], nil] call CBA_fnc_hashCreate;
|
if (!isNil {_vehicle getVariable QGVAR(handleDamage)}) exitWith {};
|
||||||
|
|
||||||
|
_vehicle allowCrewInImmobile true;
|
||||||
|
|
||||||
|
// No clue why, but for some reason this needs to be exec'd next frame or else it isn't the last event handler in the system.
|
||||||
|
// Maybe its overridden somewhere else, but this makes sure it is the last one
|
||||||
|
[{
|
||||||
|
params ["_vehicle"];
|
||||||
|
|
||||||
|
if (!isNil {_vehicle getVariable QGVAR(handleDamage)}) exitWith {};
|
||||||
|
|
||||||
|
TRACE_1("added eh",_vehicle);
|
||||||
|
|
||||||
|
_vehicle setVariable [QGVAR(hitHash), createHashMap];
|
||||||
|
_vehicle setVariable [QGVAR(handleDamage), _vehicle addEventHandler ["HandleDamage", {_this call FUNC(handleDamage)}]];
|
||||||
|
}, _vehicle] call CBA_fnc_execNextFrame;
|
||||||
|
|
||||||
|
private _typeOf = typeOf _vehicle;
|
||||||
|
|
||||||
|
if (_typeOf in GVAR(vehicleClassesHitPointHash)) exitWith {};
|
||||||
|
|
||||||
|
private _hitPointHash = createHashMap;
|
||||||
private _vehicleConfig = configOf _vehicle;
|
private _vehicleConfig = configOf _vehicle;
|
||||||
private _hitpointsConfig = _vehicleConfig >> "HitPoints";
|
private _hitPointsConfig = _vehicleConfig >> "HitPoints";
|
||||||
private _turretConfig = _vehicleConfig >> "Turrets";
|
|
||||||
private _eraHitpoints = ([_vehicleConfig >> QGVAR(eraHitpoints), "ARRAY", []] call CBA_fnc_getConfigEntry) apply {toLowerANSI _x};
|
|
||||||
private _slatHitpoints = ([_vehicleConfig >> QGVAR(slatHitpoints), "ARRAY", []] call CBA_fnc_getConfigEntry) apply {toLowerANSI _x};
|
|
||||||
|
|
||||||
// Add hitpoint names to config for quick lookup
|
// Add hitpoint names to config for quick lookup
|
||||||
{
|
{
|
||||||
_x params ["_hitpoints", "_type"];
|
_x params ["_hitPoints", "_hitArea"];
|
||||||
|
|
||||||
{
|
{
|
||||||
[_hitpointHash, toLowerANSI _x, [_type, _hitpointsConfig >> _x, toLowerANSI _x]] call CBA_fnc_hashSet;
|
_hitPointHash set [toLowerANSI _x, [_hitArea, abs getNumber (_hitPointsConfig >> _x >> "minimalHit")]];
|
||||||
} forEach _hitpoints;
|
} forEach _hitPoints;
|
||||||
} forEach ALL_HITPOINTS;
|
} forEach ALL_HITPOINTS;
|
||||||
|
|
||||||
_vehicle setVariable [QGVAR(hitpointHash), _hitpointHash];
|
// Gun and turret hitpoints aren't hardcoded anymore - dig through config to find correct names
|
||||||
|
private _fnc_iterateThroughConfig = {
|
||||||
// gun and turret hitpoints arent hardcoded anymore - dig through config to find correct names
|
params ["_config"];
|
||||||
private _iterateThroughConfig = {
|
|
||||||
params ["_vehicle", "_config", "_iterateThroughConfig", "_hitpointAliases"];
|
|
||||||
TRACE_1("checking config",_config);
|
TRACE_1("checking config",_config);
|
||||||
|
|
||||||
private _configName = toLowerANSI configName _config;
|
private _configName = toLowerANSI configName _config;
|
||||||
private _isGun = ([_config >> "isGun", "NUMBER", 0] call CBA_fnc_getConfigEntry) == 1;
|
private _isGun = getNumber (_config >> "isGun") == 1;
|
||||||
private _isTurret = ([_config >> "isTurret", "NUMBER", 0] call CBA_fnc_getConfigEntry) == 1;
|
private _isTurret = getNumber (_config >> "isTurret") == 1;
|
||||||
private _isEra = _configName in _eraHitpoints;
|
private _isEra = _configName in _eraHitpoints;
|
||||||
private _isSlat = _configName in _slatHitpoints;
|
private _isSlat = _configName in _slatHitpoints;
|
||||||
private _isMisc = false;
|
private _isMisc = false;
|
||||||
|
|
||||||
// prevent incompatibilites with old mods
|
// Prevent incompatibilites with old mods
|
||||||
if (_configName isEqualTo "hitturret") then {
|
if (_configName == "hitturret") then {
|
||||||
_isTurret = true;
|
_isTurret = true;
|
||||||
};
|
};
|
||||||
if (_configName isEqualTo "hitgun") then {
|
|
||||||
|
if (_configName == "hitgun") then {
|
||||||
_isGun = true;
|
_isGun = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
private _hash = _vehicle getVariable QGVAR(hitpointHash);
|
|
||||||
{
|
{
|
||||||
_x params ["_hitType", "_hitPoints"];
|
_x params ["_hitArea", "_hitPoints"];
|
||||||
|
|
||||||
if (_configName in _hitPoints) then {
|
if (_configName in _hitPoints) then {
|
||||||
[_hash, _configName, [_hitType, _config, _configName]] call CBA_fnc_hashSet;
|
_hitPointHash set [_configName, [_hitArea, abs getNumber (_config >> "minimalHit")]];
|
||||||
_isMisc = true;
|
_isMisc = true;
|
||||||
};
|
};
|
||||||
} forEach _hitpointAliases;
|
} forEach _hitPointAliases;
|
||||||
|
|
||||||
if (_isGun || _isTurret || _isEra || _isSlat || _isMisc) then {
|
if (_isGun || _isTurret || _isEra || _isSlat || _isMisc) then {
|
||||||
TRACE_6("found gun/turret/era/slat/misc",_isGun,_isTurret,_isEra,_isSlat,_isMisc,_hash);
|
|
||||||
if (_isGun) then {
|
if (_isGun) then {
|
||||||
[_hash, _configName, ["gun", _config, _configName]] call CBA_fnc_hashSet;
|
_hitPointHash set [_configName, ["gun", abs getNumber (_config >> "minimalHit")]];
|
||||||
};
|
};
|
||||||
if (_isTurret) then {
|
if (_isTurret) then {
|
||||||
[_hash, _configName, ["turret", _config, _configName]] call CBA_fnc_hashSet;
|
_hitPointHash set [_configName, ["turret", abs getNumber (_config >> "minimalHit")]];
|
||||||
};
|
};
|
||||||
if (_isEra) then {
|
if (_isEra) then {
|
||||||
[_hash, _configName, ["era", _config, _configName]] call CBA_fnc_hashSet;
|
_hitPointHash set [_configName, ["era", abs getNumber (_config >> "minimalHit")]];
|
||||||
};
|
};
|
||||||
if (_isSlat) then {
|
if (_isSlat) then {
|
||||||
[_hash, _configName, ["slat", _config, _configName]] call CBA_fnc_hashSet;
|
_hitPointHash set [_configName, ["slat", abs getNumber (_config >> "minimalHit")]];
|
||||||
};
|
};
|
||||||
_vehicle setVariable [QGVAR(hitpointHash), _hash];
|
|
||||||
|
TRACE_6("found gun/turret/era/slat/misc",_isGun,_isTurret,_isEra,_isSlat,_isMisc,_hash);
|
||||||
} else {
|
} else {
|
||||||
{
|
{
|
||||||
[_vehicle, _x, _iterateThroughConfig, _hitpointAliases] call _iterateThroughConfig;
|
_x call _fnc_iterateThroughConfig;
|
||||||
} forEach configProperties [_config, "isClass _x", true];
|
} forEach configProperties [_config, "isClass _x", true];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
private _hitpointAliases = [_vehicleConfig >> QGVAR(hitpointAlias), "ARRAY", []] call CBA_fnc_getConfigEntry;
|
private _turretConfig = _vehicleConfig >> "Turrets";
|
||||||
TRACE_1("hitpoint alias",_hitpointAliases);
|
private _eraHitpoints = (getArray (_vehicleConfig >> QGVAR(eraHitpoints))) apply {toLowerANSI _x};
|
||||||
[_vehicle, _hitpointsConfig, _iterateThroughConfig, _hitpointAliases] call _iterateThroughConfig;
|
private _slatHitpoints = (getArray (_vehicleConfig >> QGVAR(slatHitpoints))) apply {toLowerANSI _x};
|
||||||
[_vehicle, _turretConfig, _iterateThroughConfig, _hitpointAliases] call _iterateThroughConfig;
|
|
||||||
|
|
||||||
_vehicle allowCrewInImmobile true;
|
private _fnc_toLowerCase = {
|
||||||
private _eh = _vehicle getVariable [QGVAR(handleDamage), nil];
|
_this apply {
|
||||||
if (isNil "_eh") then {
|
if (_x isEqualType []) then {
|
||||||
// no clue why, but for some reason this needs to exec'd next frame or else it isnt the last event handler in the system.
|
_x call _fnc_toLowerCase
|
||||||
// Maybe its overridden somewhere else, but this makes sure it is the last one
|
} else {
|
||||||
[{
|
toLowerANSI _x
|
||||||
params ["_vehicle"];
|
};
|
||||||
TRACE_1("EH not added yet - added eh now",_vehicle);
|
};
|
||||||
private _hd = _vehicle addEventHandler ["HandleDamage", { _this call FUNC(handleDamage) }];
|
|
||||||
_vehicle setVariable [QGVAR(handleDamage), _hd];
|
|
||||||
}, [_vehicle]] call CBA_fnc_execNextFrame;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Convert areas to lower case
|
||||||
|
private _hitPointAliases = (getArray (_vehicleConfig >> QGVAR(hitpointAlias))) call _fnc_toLowerCase;
|
||||||
|
|
||||||
|
TRACE_1("hitpoint alias",_hitPointAliases);
|
||||||
|
|
||||||
|
_hitPointsConfig call _fnc_iterateThroughConfig;
|
||||||
|
_turretConfig call _fnc_iterateThroughConfig;
|
||||||
|
|
||||||
|
GVAR(vehicleClassesHitPointHash) set [_typeOf, _hitPointHash];
|
||||||
|
|
||||||
|
nil
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* (vehicle player) call ace_vehicle_damage_fnc_blowOffTurret
|
* cursorObject call ace_vehicle_damage_fnc_blowOffTurret
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
@ -19,6 +19,7 @@
|
|||||||
// The sudden change in the model would cause nearby PhysX objects to get stuck
|
// The sudden change in the model would cause nearby PhysX objects to get stuck
|
||||||
[{
|
[{
|
||||||
params ["_vehicle"];
|
params ["_vehicle"];
|
||||||
|
TRACE_1("blowOffTurret",_vehicle);
|
||||||
|
|
||||||
(getArray (configOf _vehicle >> QGVAR(turret))) params [["_model", "", [""]], ["_offset", [0, 0, 0], [[]], 3]];
|
(getArray (configOf _vehicle >> QGVAR(turret))) params [["_model", "", [""]], ["_offset", [0, 0, 0], [[]], 3]];
|
||||||
|
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
#include "..\script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: tcvm
|
|
||||||
* Calculates whether or not hit penetrated given armour or not. Only enabled with advanced penetration simulation turned on.
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: Source of damage <OBJECT>
|
|
||||||
* 1: The vehicle <OBJECT>
|
|
||||||
* 2: Projectile that hit <OBJECT>
|
|
||||||
* 3: Hitpoint damaged <STRING>
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [myVehicle, projectile, 5, 0.663] call ace_vehicle_damage_fnc_calculatePenetrationInfo;
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
params ["_source", "_vehicle", "_projectileData", "_hitpointConfig"];
|
|
||||||
_projectileData params ["_projectileType", "_projectileConfig"];
|
|
||||||
/*
|
|
||||||
http://www.longrods.ch/peneq.php
|
|
||||||
https://www.scribd.com/doc/267210898/57-mm-APFSDS-2-000-m#download
|
|
||||||
Perforation Calculation of APFSDS:
|
|
||||||
Tungsten/Depleted Uranium: Rods
|
|
||||||
P/Lw = a * (1 / tanh(b0 + b1 * (Lw/D))) * cos^m (theta) * sqrt (Pp / Pt) * e^((-(c0 + c1 * BHNT) * BHNT) / (Pp * Vt^2))
|
|
||||||
|
|
||||||
Steel Rods
|
|
||||||
P/Lw = a * (1 / tanh(b0 + b1 * (Lw/D))) * cos^m (theta) * sqrt (Pp / Pt) * e^((-c * BHNT^k * BHNP^n) / (Pp * Vt^2))
|
|
||||||
|
|
||||||
Penetration Calculation of Tungsten APFSDS (Used for all penetrators):
|
|
||||||
P/Lw = a * (1 / tanh(b0 + b1 * (Lw/D))) sqrt (Pp / Pt) * e^((-(c0 + c1 * BHNT) * BHNT) / (Pp * Vt^2))
|
|
||||||
|
|
||||||
where:
|
|
||||||
Penetrator:
|
|
||||||
D = Diameter of penetrator rod (always 22mm)
|
|
||||||
L = Total length of penetrator in millimeters (always 950mm)
|
|
||||||
Lw = Working length of rod in millimeters
|
|
||||||
Vt = impact velocity in Kilometers/Second
|
|
||||||
theta = NATO Obliquity angle of Penetration
|
|
||||||
Pp = Penetrator Density in kg/m^3
|
|
||||||
BHNP = Brinell hardness number of penetrator
|
|
||||||
|
|
||||||
Target:
|
|
||||||
Pt = target density in kg/m^3 (always 7840kg/m^3)
|
|
||||||
d = plate thickness in millimeters
|
|
||||||
BHNT = Brinell hardness number of target (always 350)
|
|
||||||
|
|
||||||
Material Data:
|
|
||||||
Tungsten:
|
|
||||||
Pp = 19300
|
|
||||||
BHNP = N/A
|
|
||||||
|
|
||||||
a = 0.994
|
|
||||||
c0 = 134.5
|
|
||||||
c1 = -0.148
|
|
||||||
|
|
||||||
Depleted Uranium:
|
|
||||||
Pp = 18600
|
|
||||||
BHNP = N/A
|
|
||||||
|
|
||||||
a = 0.825
|
|
||||||
c0 = 90.0
|
|
||||||
c1 = -0.0849
|
|
||||||
|
|
||||||
Steel:
|
|
||||||
Pp = 7850
|
|
||||||
BHNP = 500
|
|
||||||
|
|
||||||
a = 1.104
|
|
||||||
c = 9874
|
|
||||||
k = 0.3598
|
|
||||||
n = -0.2342
|
|
||||||
|
|
||||||
Cofficients:
|
|
||||||
m = -0.224
|
|
||||||
b0 = 0.283
|
|
||||||
b1 = 0.0656
|
|
||||||
*/
|
|
||||||
|
|
||||||
private _enabled = ([_hitpointConfig >> QGVAR(enabled), "NUMBER", 0] call CBA_fnc_getConfigEntry) == 1;
|
|
||||||
#define MATERIAL_ARRAY ([[0, 0, 0, 0, 0, 0], "steel", [7850, 500, 1.104, 9874, 0.3598, -0.2342], "tungsten", [19300, 0, 0.994, 134.5, -0.148], "depleted_uranium", [18600, 0, 0.825, 90, -0.0849]])
|
|
||||||
private _rodMaterialStr = [_projectileConfig >> QGVAR(material), "STRING", "tungsten"] call CBA_fnc_getConfigEntry;
|
|
||||||
private _rodMaterialParams = MATERIAL_ARRAY select (1 + MATERIAL_ARRAY find toLowerANSI _rodMaterial);
|
|
||||||
|
|
||||||
if !(_enabled) exitWith { [false, 0, 0, 0, 0] };
|
|
||||||
if (_rodMaterialParams isEqualTo [0, 0, 0, 0, 0, 0]) exitWith { [] };
|
|
||||||
|
|
||||||
private _tanX = 2 * (0.283 * 0.0656 * (1));
|
|
||||||
private _tanh = 1 / (((exp _tanX) - 1) / ((exp _tanX) + 1));
|
|
||||||
private _cosm = (cos 0) ^ -0.224;
|
|
||||||
private _lw = 950; // technically this would be something else depending on armour slant but this is a good enough aproximation
|
|
||||||
|
|
||||||
private _aproximateVelocity = 0;
|
|
||||||
|
|
||||||
private _perf_pLw = 0;
|
|
||||||
private _pen_pLw = 0;
|
|
||||||
if (_rodMaterialStr isEqualTo "steel") then {
|
|
||||||
_rodMaterialParams params ["_Pp", "_BHNP", "_a", "_c", "_k", "_n"];
|
|
||||||
private _exp = (-_c * 350^_k * _BHNP^_n) / (_Pp * _aproximateVelocity * _aproximateVelocity);
|
|
||||||
_pen_pLw = _a * _tanh * sqrt (_Pp / 7840) * exp _exp;
|
|
||||||
_perf_pLw = _pen_pLw * _cosm;
|
|
||||||
} else {
|
|
||||||
_rodMaterialParams params ["_Pp", "_BHNP", "_a", "_c0", "_c1"];
|
|
||||||
private _exp = (-(_c0 + _c1 * 350) * 350) / (_Pp * _aproximateVelocity * _aproximateVelocity);
|
|
||||||
_pen_pLw = _a * _tanh * _cosm * sqrt (_Pp / 7840) * exp _exp;
|
|
||||||
_perf_pLw = _pen_pLw * _cosm;
|
|
||||||
};
|
|
||||||
|
|
||||||
private _perforationDistance = _lw * _perf_pLw;
|
|
||||||
private _penetrationDistance = _lw * _pen_pLw;
|
|
||||||
private _hitpointEffectiveArmour = [_hitpointConfig >> QGVAR(thickness), "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
|
||||||
private _hitpointEffectiveSlope = [_hitpointConfig >> QGVAR(slope), "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
|
||||||
_penetrationDistance = _penetrationDistance * cos (_hitpointEffectiveSlope);
|
|
||||||
|
|
||||||
[_penetrationDistance > _hitpointEffectiveArmour, _penetrationDistance - _hitpointEffectiveArmour, _penetrationDistance, _perforationDistance, _hitpointEffectiveArmour]
|
|
@ -1,27 +0,0 @@
|
|||||||
#include "..\script_component.hpp"
|
|
||||||
/*
|
|
||||||
* Author: tcvm
|
|
||||||
* Detonates vehicle ammo and heavily wounds all inside.
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* 0: The vehicle <OBJECT>
|
|
||||||
* 1: Person who caused detonation <OBJECT> (default: objNull)
|
|
||||||
*
|
|
||||||
* Return Value:
|
|
||||||
* None
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* [tank2] call ace_vehicle_damage_fnc_detonate;
|
|
||||||
*
|
|
||||||
* Public: No
|
|
||||||
*/
|
|
||||||
|
|
||||||
params ["_vehicle", ["_injurer", objNull]];
|
|
||||||
|
|
||||||
if (((_vehicle call EFUNC(cookoff,getVehicleAmmo)) select 1) > 0) then {
|
|
||||||
{
|
|
||||||
[QGVAR(medicalDamage), [_x, _injurer, _injurer], _x] call CBA_fnc_targetEvent;
|
|
||||||
} forEach (crew _vehicle);
|
|
||||||
};
|
|
||||||
|
|
||||||
[QEGVAR(cookoff,detonateAmmunitionServer), [_vehicle, false, _injurer, _injurer]] call CBA_fnc_serverEvent;
|
|
@ -4,64 +4,66 @@
|
|||||||
* Handles whether or not the crew should bail.
|
* Handles whether or not the crew should bail.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
* 1: Can the vehicle move? <BOOL>
|
|
||||||
* 2: Can the vehicle shoot? <BOOL>
|
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [tank1, false, true] call ace_vehicle_damage_fnc_handleBail
|
* cursorObject call ace_vehicle_damage_fnc_handleBail
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle", "_canMove", "_canShoot"];
|
params ["_vehicle"];
|
||||||
private _isCar = (_vehicle isKindOf "Car" && { !(_vehicle isKindOf "Wheeled_APC_F") });
|
TRACE_1("handleBail",_vehicle);
|
||||||
|
|
||||||
if (_canMove) then {
|
private _isCar = _vehicle isKindOf "Car" && {!(_vehicle isKindOf "Wheeled_APC_F")};
|
||||||
_canMove = alive driver _vehicle;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_canShoot) then {
|
// canFire command is broken, hence the variable
|
||||||
_canShoot = alive gunner _vehicle;
|
private _canMove = (_vehicle getVariable [QGVAR(canMove), true]) && {alive driver _vehicle};
|
||||||
};
|
private _canShoot = (_vehicle getVariable [QGVAR(canShoot), true]) && {alive gunner _vehicle};
|
||||||
|
|
||||||
_vehicle setVariable[QGVAR(canMove), _canMove];
|
_vehicle setVariable [QGVAR(canMove), _canMove];
|
||||||
_vehicle setVariable[QGVAR(canShoot), _canShoot];
|
_vehicle setVariable [QGVAR(canShoot), _canShoot];
|
||||||
|
|
||||||
private _rand = random 1;
|
private _rand = random 1;
|
||||||
|
|
||||||
if (_isCar) then {
|
if (_isCar) then {
|
||||||
if !(_canMove) then {
|
if (!_canMove) then {
|
||||||
[_vehicle] spawn FUNC(abandon);
|
_vehicle call FUNC(abandon);
|
||||||
LOG_3("[%1] can't move and is bailing and is a car [%2 | %3]",_vehicle,_canMove,_isCar);
|
|
||||||
|
TRACE_3("car immobile - bailing",_vehicle,_canMove,_isCar);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (!_canMove && !_canShoot ) exitWith { // If you can't move and you can't shoot, you better GTFO
|
// If you can't move and you can't shoot, you better GTFO
|
||||||
[_vehicle] spawn FUNC(abandon);
|
if (!_canMove && !_canShoot) exitWith {
|
||||||
LOG_3("[%1] is a sitting duck and is bailing [%2 | %3]",_vehicle,_canMove,_canShoot);
|
_vehicle call FUNC(abandon);
|
||||||
|
|
||||||
|
TRACE_3("immobile and can't shoot - bailing",_vehicle,_canMove,_canShoot);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!_canShoot && !_isCar) then {
|
if (!_canShoot) then {
|
||||||
if (BAILOUT_CHANCE_SHOOT > _rand) then { // 50% chance of bailing out if turret/gun is destroyed
|
// 50% chance of bailing out if turret/gun is disabled
|
||||||
[_vehicle] spawn FUNC(abandon);
|
if (BAILOUT_CHANCE_SHOOT > _rand) then {
|
||||||
LOG_4("[%1] Cannot shoot and is bailing with chance [%2] [%3 | %4]",_vehicle,_rand,_canMove,_canShoot);
|
_vehicle call FUNC(abandon);
|
||||||
|
|
||||||
|
TRACE_4("can't shoot - bailing",_vehicle,_rand,_canMove,_canShoot);
|
||||||
} else {
|
} else {
|
||||||
_vehicle allowFleeing 1;
|
_vehicle allowFleeing 1;
|
||||||
LOG_4("[%1] Cannot shoot and is fleeing with chance [%2] [%3 | %4]",_vehicle,_rand,_canMove,_canShoot);
|
|
||||||
|
TRACE_4("fleeing",_vehicle,_rand,_canMove,_canShoot);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
if !(_canMove) then {
|
if (!_canMove) then {
|
||||||
if (BAILOUT_CHANCE_MOVE > _rand) then { // 80% Chance of bailing out if engine is destroyed
|
// 80% Chance of bailing out if engine is disabled
|
||||||
[_vehicle] spawn FUNC(abandon);
|
if (BAILOUT_CHANCE_MOVE > _rand) then {
|
||||||
LOG_4("[%1] Cannot move and is bailing with chance [%2] [%3 | %4]",_vehicle,_rand,_canMove,_canShoot);
|
_vehicle call FUNC(abandon);
|
||||||
|
|
||||||
|
TRACE_4("immobile - bailing",_vehicle,_rand,_canMove,_canShoot);
|
||||||
} else {
|
} else {
|
||||||
LOG_4("[%1] Cannot move and is bunkering with chance [%2] [%3 | %4]",_vehicle,_rand,_canMove,_canShoot);
|
TRACE_4("immobile - bunkering",_vehicle,_rand,_canMove,_canShoot);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,59 +1,71 @@
|
|||||||
#include "..\script_component.hpp"
|
#include "..\script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: tcvm
|
* Author: tcvm
|
||||||
* Checks hitpoint damage and determines if a vehicle should cookoff.
|
* Checks hitpoint damage and determines if a vehicle should cook off.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
* 1: Chance of fire <NUMBER>
|
* 1: Chance of fire <NUMBER>
|
||||||
* 2: Intensity of cookoff <NUMBER>
|
* 2: Intensity of cookoff <NUMBER>
|
||||||
* 3: Person who instigated cookoff <OBJECT> (default: objNull)
|
* 3: Source of damage <OBJECT>
|
||||||
* 4: Part of vehicle which got hit <STRING> (default: "")
|
* 4: Person who caused damage <OBJECT>
|
||||||
* 5: Whether or not the vehicle can spawn ring-fire effect <BOOL> (default: false)
|
* 5: Part of vehicle which got hit <STRING> (default: "")
|
||||||
* 6: Can Jet <BOOL> (default: true)
|
* 6: Whether or not the vehicle can spawn ring-fire effect <BOOL> (default: false)
|
||||||
|
* 7: Whether or not the vehicle can spawn jet-fire effect <BOOL> (default: true)
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* If cooked off
|
* If vehicle started or already cooking off <BOOL>
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [tank2, 0.1, 5] call ace_vehicle_damage_fnc_handleCookoff;
|
* [cursorObject, 0.1, 5, player, player] call ace_vehicle_damage_fnc_handleCookoff
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle", "_chanceOfFire", "_intensity", ["_injurer", objNull], ["_hitPart", ""], ["_canRing", false], ["_canJet", true]];
|
params ["_vehicle", "_chanceOfFire", "_intensity", "_source", "_instigator", ["_hitPart", ""], ["_canRing", true], ["_canJet", true]];
|
||||||
|
TRACE_8("handleCookoff",_vehicle,_chanceOfFire,_intensity,_source,_instigator,_hitPart,_canRing,_canJet);
|
||||||
|
|
||||||
// Ignore if the vehicle is already cooking off
|
// Ignore if the vehicle is already cooking off
|
||||||
if (_vehicle getVariable [QEGVAR(cookoff,isCookingOff), false]) exitWith {true};
|
if (_vehicle getVariable [QEGVAR(cookoff,isCookingOff), false]) exitWith {
|
||||||
|
TRACE_3("already cooking off",_vehicle,_chanceOfFire,_intensity);
|
||||||
|
|
||||||
|
true // return
|
||||||
|
};
|
||||||
|
|
||||||
_chanceOfFire = _chanceOfFire * EGVAR(cookoff,probabilityCoef);
|
_chanceOfFire = _chanceOfFire * EGVAR(cookoff,probabilityCoef);
|
||||||
|
|
||||||
if (_chanceOfFire >= random 1) exitWith {
|
// Failure to cook off
|
||||||
private _configOf = configOf _vehicle;
|
if (_chanceOfFire == 0 || {_chanceOfFire < random 1}) exitWith {
|
||||||
private _fireDetonateChance = [_configOf >> QGVAR(detonationDuringFireProb), "number", 0] call CBA_fnc_getConfigEntry;
|
TRACE_3("no cook-off",_vehicle,_chanceOfFire,_intensity);
|
||||||
if (_canRing) then {
|
|
||||||
_canRing = ([_configOf >> QGVAR(canHaveFireRing), "number", 0] call CBA_fnc_getConfigEntry) == 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_canJet) then {
|
false // return
|
||||||
_canJet = ([_configOf >> QEGVAR(cookoff,canHaveFireJet), "number", 1] call CBA_fnc_getConfigEntry) == 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
private _delayWithSmoke = _chanceOfFire < random 1;
|
|
||||||
private _detonateAfterCookoff = (_fireDetonateChance / 4) > random 1;
|
|
||||||
|
|
||||||
private _source = "";
|
|
||||||
if (_hitPart == "engine") then {
|
|
||||||
_source = ["hit_engine_point", "HitPoints"];
|
|
||||||
};
|
|
||||||
|
|
||||||
[QEGVAR(cookOff,cookOffServer), [_vehicle, _intensity, _injurer, _injurer, _delayWithSmoke, _fireDetonateChance, _detonateAfterCookoff, _source, _canRing, _canJet]] call CBA_fnc_serverEvent;
|
|
||||||
LOG_4("Cooking-off [%1] with a chance-of-fire [%2] - Delayed Smoke | Detonate after cookoff [%3 | %4]",_vehicle,_chanceOfFire,_delayWithSmoke,_detonateAfterCookoff);
|
|
||||||
[_vehicle] spawn FUNC(abandon);
|
|
||||||
LOG_1("[%1] is on fire is bailing",_vehicle);
|
|
||||||
|
|
||||||
true
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_2("[%1] No Cook-off - Chance of fire [%2]",_vehicle,_chanceOfFire);
|
// Vehicle will cook off
|
||||||
false
|
private _configOf = configOf _vehicle;
|
||||||
|
private _fireDetonateChance = getNumber (_configOf >> QGVAR(detonationDuringFireProb));
|
||||||
|
|
||||||
|
if (_canRing) then {
|
||||||
|
_canRing = getNumber (_configOf >> QGVAR(canHaveFireRing)) == 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_canJet) then {
|
||||||
|
_canJet = getNumber (_configOf >> QEGVAR(cookoff,canHaveFireJet)) == 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _delaySmoke = _chanceOfFire < random 1;
|
||||||
|
private _detonateAfterCookoff = (_fireDetonateChance / 4) > random 1;
|
||||||
|
|
||||||
|
private _source = "";
|
||||||
|
|
||||||
|
if (_hitPart == "engine") then {
|
||||||
|
_source = ["hit_engine_point", "HitPoints"];
|
||||||
|
};
|
||||||
|
|
||||||
|
[QEGVAR(cookOff,cookOffServer), [_vehicle, _intensity, _injurer, _injurer, _delayWithSmoke, _fireDetonateChance, _detonateAfterCookoff, _source, _canRing, _canJet]] call CBA_fnc_serverEvent;
|
||||||
|
TRACE_4("cooking-off",_vehicle,_chanceOfFire,_delaySmoke,_detonateAfterCookoff);
|
||||||
|
|
||||||
|
// Abandon vehicle
|
||||||
|
_vehicle call FUNC(abandon);
|
||||||
|
|
||||||
|
true // return
|
||||||
|
@ -4,91 +4,88 @@
|
|||||||
* Called by "HandleDamage" event handler. Sets up hit array for this frame's damage.
|
* Called by "HandleDamage" event handler. Sets up hit array for this frame's damage.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
* 1: Name of selection where unit was damaged <STRING> (unused)
|
* 1: Selection <STRING>
|
||||||
* 2: Damage taken <NUMBER>
|
* 2: New level of damage <NUMBER>
|
||||||
* 3: Source unit of damage <OBJECT> (unused)
|
* 3: Source of damage <OBJECT>
|
||||||
* 4: Projectile that caused damage <STRING>
|
* 4: Projectile that caused damage <STRING>
|
||||||
* 5: Hit part index of hit point <NUMBER>
|
* 5: Hit index <NUMBER>
|
||||||
* 6: Instigator of damage <OBJECT> (unused)
|
* 6: Person who caused damage <OBJECT>
|
||||||
* 7: Hit point config name <STRING>
|
* 7: Hit point <STRING>
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* Current or maximum damage of part
|
* Current or maximum damage of part <NUMBER>
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [myVehicle, projectile, 5, 0.663] call ace_vehicle_damage_fnc_handleDamage;
|
* [cursorObject, "hit_engine_point", 0.5, player, projectile, 1, player, "HitEngine"] call ace_vehicle_damage_fnc_handleDamage
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle", "_hitSelection", "_damage", "", "_projectile", "_hitIndex", "", "_hitPoint"];
|
params ["_vehicle", "_selection", "_newDamage", "_source", "_projectile", "_hitIndex", "_instigator", "_hitPoint"];
|
||||||
TRACE_6("HandleDamage event inputs",_vehicle,_hitSelection,_damage,_projectile,_hitIndex,_hitPoint);
|
TRACE_8("handleDamage",_vehicle,_selection,_newDamage,_source,_projectile,_hitIndex,_instigator,_hitPoint);
|
||||||
|
|
||||||
private _returnHit = if (_hitSelection isNotEqualTo "") then {
|
if (!local _vehicle) exitWith {};
|
||||||
|
|
||||||
|
private _currentDamage = if (_selection != "") then {
|
||||||
_vehicle getHitIndex _hitIndex
|
_vehicle getHitIndex _hitIndex
|
||||||
} else {
|
} else {
|
||||||
damage _vehicle
|
damage _vehicle
|
||||||
};
|
};
|
||||||
|
|
||||||
if !(_projectile in ["ace_ammoExplosion", "ACE_ammoExplosionLarge"]) then {
|
if !(_projectile in ["ace_ammoExplosion", "ACE_ammoExplosionLarge"]) then {
|
||||||
if (local _vehicle) then {
|
// If an invalid hit, don't process it
|
||||||
// set up hit array so we can execute all damage next frame. Always in order of hit done.
|
if (_newDamage <= 0 || {"#light" in _hitPoint}) exitWith {};
|
||||||
private _hitHash = _vehicle getVariable [QGVAR(hitHash), nil];
|
|
||||||
if (isNil "_hitHash") then {
|
|
||||||
_hitHash = [[], nil] call CBA_fnc_hashCreate;
|
|
||||||
};
|
|
||||||
private _currentFrameArray = [_hitHash, diag_frameNo] call CBA_fnc_hashGet;
|
|
||||||
if (isNil "_currentFrameArray") then {
|
|
||||||
_currentFrameArray = [];
|
|
||||||
};
|
|
||||||
// if a valid hit, process it
|
|
||||||
if !((_hitPoint find "#light") >= 0 || { _damage <= 0 }) then {
|
|
||||||
if (_currentFrameArray isEqualTo []) then {
|
|
||||||
[{
|
|
||||||
params ["_vehicle", "_processingFrame"];
|
|
||||||
private _frameHash = _vehicle getVariable [QGVAR(hitHash), nil];
|
|
||||||
private _hitArray = [_frameHash, _processingFrame] call CBA_fnc_hashGet;
|
|
||||||
if (_hitArray isEqualTo []) exitWith {};
|
|
||||||
|
|
||||||
reverse _hitArray;
|
// Set up hit array so we can execute all damage next frame. Always in order of hit done.
|
||||||
TRACE_3("processing data from old frame",diag_frameNo,_processingFrame,_hitArray);
|
private _hitHash = _vehicle getVariable QGVAR(hitHash);
|
||||||
{
|
private _currentFrameArray = _hitHash getOrDefault [diag_frameNo, [], true];
|
||||||
_x params ["_vehicle", "_selection", "_damage", "_injurer", "_projectile", "_hitIndex", "", "_hitPoint"];
|
|
||||||
|
|
||||||
private _returnHit = if (_selection isNotEqualTo "") then {
|
if (_currentFrameArray isEqualTo []) then {
|
||||||
_vehicle getHitIndex _hitIndex
|
[{
|
||||||
} else {
|
params ["_vehicle", "_processingFrame"];
|
||||||
damage _vehicle
|
|
||||||
};
|
|
||||||
|
|
||||||
private _newDamage = _damage - _returnHit;
|
private _hitHash = _vehicle getVariable QGVAR(hitHash);
|
||||||
if !([_vehicle, _hitPoint, _hitIndex, _injurer, _returnHit, _newDamage, _projectile, _selection] call FUNC(handleVehicleDamage)) exitWith {
|
private _hitArray = _hitHash deleteAt _processingFrame;
|
||||||
LOG_2("cancelling rest of vehicle damage queue ( [%1] items left out of [%2] )",(count (_hitArray#1)) - _forEachIndex,count (_hitArray#1))
|
|
||||||
};
|
|
||||||
} forEach _hitArray;
|
|
||||||
|
|
||||||
[_frameHash, _processingFrame] call CBA_fnc_hashRem;
|
if (_hitArray isEqualTo []) exitWith {};
|
||||||
|
|
||||||
}, [_vehicle, diag_frameNo]] call CBA_fnc_execNextFrame;
|
TRACE_3("processing data from old frame",diag_frameNo,_processingFrame,_hitArray);
|
||||||
};
|
|
||||||
_currentFrameArray pushBack _this;
|
|
||||||
};
|
|
||||||
|
|
||||||
[_hitHash, diag_frameNo, _currentFrameArray] call CBA_fnc_hashSet;
|
// Start from newest damage and work backwards
|
||||||
_vehicle setVariable [QGVAR(hitHash), _hitHash];
|
{
|
||||||
|
_x params ["_vehicle", "_selection", "_newDamage", "_source", "_projectile", "_hitIndex", "_instigator", "_hitPoint"];
|
||||||
|
|
||||||
|
private _currentDamage = if (_selection != "") then {
|
||||||
|
_vehicle getHitIndex _hitIndex
|
||||||
|
} else {
|
||||||
|
damage _vehicle
|
||||||
|
};
|
||||||
|
|
||||||
|
private _addedDamage = _newDamage - _currentDamage;
|
||||||
|
|
||||||
|
TRACE_1("handleDamage",_currentDamage);
|
||||||
|
|
||||||
|
if !([_vehicle, _hitPoint, _hitIndex, _selection, _addedDamage, _projectile, _source, _instigator] call FUNC(handleVehicleDamage)) exitWith {
|
||||||
|
TRACE_2("cancelling rest of vehicle damage queue",(count (_hitArray#1)) - _forEachIndex,count (_hitArray#1))
|
||||||
|
};
|
||||||
|
} forEachReversed _hitArray;
|
||||||
|
}, [_vehicle, diag_frameNo]] call CBA_fnc_execNextFrame;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_currentFrameArray pushBack _this;
|
||||||
};
|
};
|
||||||
|
|
||||||
// damage is never to be handled in-engine. Always handle out of engine with this event handler
|
// Damage is never to be handled in-engine. Always handle out of engine with this event handler
|
||||||
// don't return 0 or else old parts will be reset in damage
|
// Don't return 0 or else old parts will be reset in damage
|
||||||
private _criticalDamageIndex = (CRITICAL_HITPOINTS findIf { _x isEqualTo _hitPoint }) + 1;
|
private _criticalDamageIndex = CRITICAL_HITPOINTS findIf {_x == _hitPoint};
|
||||||
if (_criticalDamageIndex > 0) then {
|
|
||||||
_returnHit = (_returnHit min (CRITICAL_HITPOINTS select _criticalDamageIndex));
|
if (_criticalDamageIndex != -1) then {
|
||||||
|
_currentDamage = _currentDamage min (CRITICAL_HITPOINTS_THRESHOLDS select _criticalDamageIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_hitPoint isEqualTo "" && _hitIndex < 0) then {
|
if (_hitPoint == "" && {_hitIndex < 0}) then {
|
||||||
_returnHit = _returnHit min 0.89;
|
_currentDamage = _currentDamage min 0.89;
|
||||||
};
|
};
|
||||||
|
|
||||||
_returnHit
|
_currentDamage
|
||||||
|
@ -20,7 +20,7 @@ params ["_vehicle", "", "", "", "_ammo"];
|
|||||||
|
|
||||||
if (alive _vehicle) exitWith {};
|
if (alive _vehicle) exitWith {};
|
||||||
|
|
||||||
TRACE_2("ejectIfDestroyed HDEH",typeOf _vehicle,_this);
|
TRACE_2("handleDamageEjectIfDestroyed",typeOf _vehicle,_this);
|
||||||
|
|
||||||
if (!IS_EXPLOSIVE_AMMO(_ammo)) then {
|
if (!IS_EXPLOSIVE_AMMO(_ammo)) then {
|
||||||
{
|
{
|
||||||
|
@ -1,37 +1,59 @@
|
|||||||
#include "..\script_component.hpp"
|
#include "..\script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: tcvm
|
* Author: tcvm, johnb43
|
||||||
* Checks hitpoint damage and determines if a vehicle should cookoff.
|
* Checks hitpoint damage and determines if a vehicle should detonate its ammo.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
* 1: Chance of detonation <NUMBER>
|
* 1: Chance of detonation <NUMBER>
|
||||||
* 2: Vehicle ammo array <ARRAY>
|
* 2: If the vehicle should be knocked out <BOOL>
|
||||||
* 3: How much explosive ammo is inside vehicle <NUMBER>
|
* 3: If the crew should be injured <BOOL>
|
||||||
* 4: How much non-explosive ammo inside vehicle <NUMBER>
|
* 4: Source of damage <OBJECT>
|
||||||
* 5: Person who instigated damage <OBJECT> (default: objNull)
|
* 5: Person who caused damage <OBJECT>
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* Detonated <BOOL>
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [tank2, 0.5] call ace_vehicle_damage_fnc_handleDetonation;
|
* [cursorObject, 0.5, true, player, player] call ace_vehicle_damage_fnc_handleDetonation
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle", "_chanceOfDetonate", "_vehicleAmmo", "_explosiveAmmoCount", "_nonExplosiveAmmoCount", ["_injurer", objNull]];
|
params ["_vehicle", "_chanceToDetonate", "_knockOut", "_injureCrew", "_source", "_instigator"];
|
||||||
|
|
||||||
private _isKnockedOut = _explosiveAmmoCount > 0;
|
|
||||||
|
|
||||||
// Ignore if the vehicle is already detonating ammo
|
// Ignore if the vehicle is already detonating ammo
|
||||||
if (_vehicle getVariable [QEGVAR(cookoff,isAmmoDetonating), false]) exitWith {_isKnockedOut};
|
if (_vehicle getVariable [QEGVAR(cookoff,isAmmoDetonating), false]) exitWith {
|
||||||
|
TRACE_2("already detonating",_vehicle,_chanceToDetonate);
|
||||||
|
|
||||||
if (_chanceOfDetonate >= random 1) exitWith {
|
if (_knockOut) then {
|
||||||
[_vehicle, _injurer, _vehicleAmmo] call FUNC(detonate);
|
[_vehicle, _source, _instigator] call FUNC(knockOut);
|
||||||
LOG_2("Detonating [%1] with a chance-to-detonate [%2]",_vehicle,_chanceOfDetonate);
|
};
|
||||||
_isKnockedOut
|
|
||||||
|
_knockOut // return
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_2("[%1] No Detonation - Chance of detonation [%2]",_vehicle,_chanceOfDetonate);
|
// Failure to detonate
|
||||||
false
|
if (_chanceToDetonate == 0 || {_chanceToDetonate < random 1}) exitWith {
|
||||||
|
TRACE_2("no detonation",_vehicle,_chanceToDetonate);
|
||||||
|
|
||||||
|
false // return
|
||||||
|
};
|
||||||
|
|
||||||
|
// Vehicle will be detonated
|
||||||
|
if (_injureCrew) then {
|
||||||
|
{
|
||||||
|
[QGVAR(medicalDamage), [_x, _source, _instigator], _x] call CBA_fnc_targetEvent;
|
||||||
|
} forEach (crew _vehicle);
|
||||||
|
};
|
||||||
|
|
||||||
|
TRACE_2("detonation",_vehicle,_chanceToDetonate);
|
||||||
|
|
||||||
|
// Detonate the vehicle
|
||||||
|
[QEGVAR(cookoff,detonateAmmunitionServer), [_vehicle, false, _source, _instigator]] call CBA_fnc_serverEvent;
|
||||||
|
|
||||||
|
if (_knockOut) then {
|
||||||
|
[_vehicle, _source, _instigator] call FUNC(knockOut);
|
||||||
|
};
|
||||||
|
|
||||||
|
_knockOut // return
|
||||||
|
@ -4,96 +4,101 @@
|
|||||||
* Process vehicle hit.
|
* Process vehicle hit.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
* 1: The hitpoint which got hit <STRING>
|
* 1: Hit point <STRING>
|
||||||
* 2: The index of what got hit <NUMBER>
|
* 2: Hit index <NUMBER>
|
||||||
* 3: The damage that the new part took <NUMBER>
|
* 3: Selection <STIRNG>
|
||||||
* 4: Person who hit vehicle <OBJECT>
|
* 4: Added damage to part <NUMBER>
|
||||||
* 5: Damage before hit <NUMBER>
|
* 5: Projectile <OBJECT>
|
||||||
* 6: Damage after hit <NUMBER>
|
* 6: Source of damage <OBJECT>
|
||||||
* 7: Projectile <OBJECT>
|
* 7: Person who caused damage <OBJECT>
|
||||||
* 8: Selection that got hit <STIRNG>
|
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* Whether or not to continue handling last frame's damage
|
* Whether or not to continue handling last frame's damage <BOOL>
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [ace_vehicle_damage_fnc_handleVehicleDamage, tank1, "Hit_Engine", 12]] call CBA_fnc_execNextFrame
|
* [ace_vehicle_damage_fnc_handleVehicleDamage, [cursorObject, "HitEngine", 12, "hit_engine_point", 0.25, projectile, player, player]] call CBA_fnc_execNextFrame
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params["_vehicle", "_hitPoint", "_hitIndex", "_injurer", "_oldDamage", "_newDamage", "_projectile", "_selection"];
|
params ["_vehicle", "_hitPoint", "_hitIndex", "_selection", "_addedDamage", "_projectile", "_source", "_instigator"];
|
||||||
TRACE_6("handleVehicleDamage",_vehicle,_hitPoint,_hitIndex,_injurer,_oldDamage,_newDamage);
|
TRACE_8("handleVehicleDamage",_vehicle,_hitPoint,_hitIndex,_selection,_addedDamage,_projectile,_source,_instigator);
|
||||||
if !(alive _vehicle) exitWith {
|
|
||||||
private _eventHandler = _vehicle getVariable[QGVAR(handleDamage), nil];
|
if (!alive _vehicle) exitWith {
|
||||||
if !(isNil "_eventHandler") then {
|
private _handleDamageEH = _vehicle getVariable [QGVAR(handleDamage), nil];
|
||||||
_vehicle removeEventHandler ["HandleDamage", _eventHandler];
|
|
||||||
|
if (!isNil "_handleDamageEH") then {
|
||||||
|
_vehicle removeEventHandler ["HandleDamage", _handleDamageEH];
|
||||||
};
|
};
|
||||||
LOG_1("Vehicle [%1] no longer alive",_vehicle);
|
|
||||||
true
|
TRACE_1("vehicle no longer alive",_vehicle);
|
||||||
|
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
_hitPoint = toLowerANSI _hitPoint;
|
_hitPoint = toLowerANSI _hitPoint;
|
||||||
private _hitpointHash = _vehicle getVariable [QGVAR(hitpointHash), []];
|
private _hitPointHash = GVAR(vehicleClassesHitPointHash) getOrDefault [typeOf _vehicle, createHashMap];
|
||||||
private _type = if (_hitpointHash isEqualTo []) then {
|
private _type = (_hitPointHash getOrDefault [_hitPoint, []]) select 0;
|
||||||
"exit"
|
|
||||||
} else {
|
|
||||||
([_hitpointHash, _hitPoint] call CBA_fnc_hashGet) select 0
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isNil "_type") then {
|
// Generic structural damage will be transfered into hull damage for simulation's sake
|
||||||
_type = "exit";
|
|
||||||
};
|
|
||||||
|
|
||||||
// generic structural damage will be transfered into hull damage for simulation's sake
|
|
||||||
private _structural = false;
|
private _structural = false;
|
||||||
if (_selection isEqualTo "") then {
|
|
||||||
|
if (_selection == "") then {
|
||||||
_type = "hull";
|
_type = "hull";
|
||||||
_hitPoint = "hithull";
|
_hitPoint = "hithull";
|
||||||
_structural = true;
|
_structural = true;
|
||||||
|
|
||||||
TRACE_1("structural damage",_selection);
|
TRACE_1("structural damage",_selection);
|
||||||
_newDamage = abs _newDamage;
|
|
||||||
|
_addedDamage = abs _addedDamage;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_type isEqualTo "exit") exitWith { LOG_1("No relevant hitpoints hit [%1]. Exiting",_hitPoint); true };
|
if (isNil "_type") exitWith {
|
||||||
|
TRACE_1("no relevant hitpoints hit, exiting",_hitPoint);
|
||||||
|
|
||||||
|
true
|
||||||
|
};
|
||||||
|
|
||||||
// Ignore multiple hits at the same time
|
// Ignore multiple hits at the same time
|
||||||
private _ignoreHit = false;
|
private _ignoreHit = false;
|
||||||
private _ignoreBailCheck = false;
|
private _ignoreBailCheck = false;
|
||||||
private _multHit = _vehicle getVariable [QGVAR(hitTime), nil];
|
private _multHit = _vehicle getVariable [QGVAR(hitTime), nil];
|
||||||
|
|
||||||
if (isNil "_multHit") then {
|
if (isNil "_multHit") then {
|
||||||
_vehicle setVariable[QGVAR(hitTime), [CBA_missionTime, _injurer, [_hitPoint]]];
|
_vehicle setVariable [QGVAR(hitTime), [CBA_missionTime, _source, [_hitPoint]]];
|
||||||
} else {
|
} else {
|
||||||
private _hitPointInOldArray = _hitPoint in (_multHit select 2);
|
private _hitPointInOldArray = _hitPoint in (_multHit select 2);
|
||||||
private _withinTime = (CBA_missionTime <= (_multHit select 0) + CONST_TIME) && { _injurer == (_multHit select 1) };
|
private _withinTime = (CBA_missionTime <= (_multHit select 0) + CONST_TIME) && {_source == (_multHit select 1)};
|
||||||
|
|
||||||
if (_hitPointInOldArray && _withinTime) then {
|
if (_hitPointInOldArray && _withinTime) then {
|
||||||
_ignoreHit = true;
|
_ignoreHit = true;
|
||||||
} else {
|
} else {
|
||||||
// If the hitpoint isnt in the old array then that means that the time expired and a new array should be generated
|
// If the hitpoint isnt in the old array then that means that the time expired and a new array should be generated
|
||||||
if !(_hitPointInOldArray) then {
|
if (!_hitPointInOldArray) then {
|
||||||
private _oldHitPoints = _multHit select 2;
|
private _oldHitPoints = _multHit select 2;
|
||||||
_oldHitPoints pushBack _hitPoint;
|
_oldHitPoints pushBack _hitPoint;
|
||||||
_vehicle setVariable [QGVAR(hitTime), [CBA_missionTime, _injurer, _oldHitPoints]];
|
_vehicle setVariable [QGVAR(hitTime), [CBA_missionTime, _source, _oldHitPoints]];
|
||||||
|
|
||||||
_ignoreBailCheck = true;
|
_ignoreBailCheck = true;
|
||||||
} else {
|
} else {
|
||||||
_vehicle setVariable [QGVAR(hitTime), [CBA_missionTime, _injurer, [_hitPoint]]];
|
_vehicle setVariable [QGVAR(hitTime), [CBA_missionTime, _source, [_hitPoint]]];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_ignoreHit && !_structural) exitWith {
|
if (_ignoreHit && !_structural) exitWith {
|
||||||
LOG_3("Ignoring multiple hits done to vehicle [%1] by [%2] -- hitpoint [%3].",_vehicle,_injurer,_hitPoint);
|
TRACE_3("ignoring multiple hits done to vehicle",_vehicle,_source,_hitPoint);
|
||||||
|
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
LOG_3("Processing hit done to vehicle [%1] by [%2] at time [%3].",_vehicle,_injurer,CBA_missionTime);
|
|
||||||
|
|
||||||
if !([_vehicle, _projectile, _hitIndex, _newDamage, [_hitpointHash, _hitPoint] call CBA_fnc_hashGet, _injurer] call FUNC(processHit)) exitWith { false };
|
TRACE_3("processing hit done to vehicle",_vehicle,_source,CBA_missionTime);
|
||||||
|
|
||||||
private _canMove = _vehicle getVariable[QGVAR(canMove), true];
|
if !([_vehicle, _hitPoint, _hitIndex, _addedDamage, _projectile, _source, _instigator] call FUNC(processHit)) exitWith {false};
|
||||||
private _canShoot = _vehicle getVariable[QGVAR(canShoot), true];
|
|
||||||
|
|
||||||
if !(_ignoreBailCheck) then {
|
if (!_ignoreBailCheck) then {
|
||||||
[_vehicle, _canMove, _canShoot] call FUNC(handleBail);
|
_vehicle call FUNC(handleBail);
|
||||||
};
|
};
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -1,37 +1,37 @@
|
|||||||
#include "..\script_component.hpp"
|
#include "..\script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: tcvm
|
* Author: tcvm
|
||||||
* Knock out vehicle from battle. Destroy all internal hitpoints.
|
* Knock out a vehicle from battle by destroying all internal hitpoints.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
|
* 1: Source of damage <OBJECT>
|
||||||
|
* 2: Person who caused damage <OBJECT>
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [vehicle player] call ace_vehicle_damage_fnc_knockOut
|
* [cursorObject, player, player] call ace_vehicle_damage_fnc_knockOut
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle"];
|
params ["_vehicle", "_source", "_instigator"];
|
||||||
private _hash = _vehicle getVariable [QGVAR(hitpointHash), nil];
|
TRACE_3("knockOut",_vehicle,_source,_instigator);
|
||||||
if (isNil "_hash") exitWith {};
|
|
||||||
|
|
||||||
[_hash, {
|
{
|
||||||
private _hitpointAlias = _value#0;
|
private _hitArea = _y select 0;
|
||||||
if (_hitpointAlias isEqualTo "hull") then {
|
|
||||||
[_vehicle, -1, _key, 0.89] call FUNC(addDamage);
|
if (_hitArea == "hull") then {
|
||||||
|
[_vehicle, _x, -1, 0.89, _source, _instigator] call FUNC(setDamage);
|
||||||
} else {
|
} else {
|
||||||
if (_hitpointAlias in ["fuel", "turret", "gun", "engine"]) then {
|
if (_hitArea in ["fuel", "turret", "gun", "engine"]) then {
|
||||||
if ((0.3 > random 1) || { _hitpointAlias isEqualTo "engine" }) then {
|
if ((0.3 > random 1) || {_hitArea == "engine"}) then {
|
||||||
[_vehicle, -1, _key, 1] call FUNC(addDamage);
|
[_vehicle, _x, -1, 1, _source, _instigator] call FUNC(setDamage);
|
||||||
} else {
|
} else {
|
||||||
private _currentDamage = _vehicle getHitpointDamage _key;
|
[_vehicle, _x, -1, ((_vehicle getHitPointDamage _x) + (0.3 max random 1)) min 1, _source, _instigator] call FUNC(setDamage);
|
||||||
[_vehicle, -1, _key, (_currentDamage + (0.3 max random 1)) min 1] call FUNC(addDamage);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}] call CBA_fnc_hashEachPair;
|
} forEach (GVAR(vehicleClassesHitPointHash) getOrDefault [typeOf _vehicle, createHashMap]);
|
||||||
|
|
||||||
|
@ -1,133 +1,132 @@
|
|||||||
#include "..\script_component.hpp"
|
#include "..\script_component.hpp"
|
||||||
/*
|
/*
|
||||||
* Author: tcvm
|
* Author: tcvm, johnb43
|
||||||
* Process hit by projectile against vehicle and apply appropiate damage to part.
|
* Process hit by projectile against vehicle and apply appropiate damage to part.
|
||||||
*
|
*
|
||||||
* Arguments:
|
* Arguments:
|
||||||
* 0: The vehicle <OBJECT>
|
* 0: Vehicle <OBJECT>
|
||||||
* 1: Projectile that hit <OBJECT>
|
* 1: Hit point <STRING>
|
||||||
* 2: Hit index of potentially damaged part <NUMBER>
|
* 2: Hit index <NUMBER>
|
||||||
* 3: New damage done to part <NUMBER>
|
* 3: Added damage to part <NUMBER>
|
||||||
* 4: Information about hitpoint <ARRAY>
|
* 4: Projectile <OBJECT>
|
||||||
* 5: Person who caused damage <OBJECT>
|
* 5: Source of damage <OBJECT>
|
||||||
|
* 6: Person who caused damage <OBJECT>
|
||||||
*
|
*
|
||||||
* Return Value:
|
* Return Value:
|
||||||
* None
|
* Whether or not to continue handling last frame's damage <BOOL>
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
* [myVehicle, projectile, 5, 0.663] call ace_vehicle_damage_fnc_processHit;
|
* [cursorObject, "HitEngine", 1, 0.25, projectile, player, player] call ace_vehicle_damage_fnc_processHit
|
||||||
*
|
*
|
||||||
* Public: No
|
* Public: No
|
||||||
*/
|
*/
|
||||||
|
|
||||||
params ["_vehicle", "_projectile", "_hitIndex", "_newDamage", "_hitpointData", "_injurer"];
|
params ["_vehicle", "_hitPoint", "_hitIndex", "_addedDamage", "_projectile", "_source", "_instigator"];
|
||||||
_hitpointData params ["_hitArea", "_hitpointConfig", "_hitpointName"];
|
TRACE_7("processHit",_vehicle,_hitPoint,_hitIndex,_addedDamage,_projectile,_source,_instigator);
|
||||||
|
|
||||||
private _return = true;
|
_addedDamage = abs _addedDamage;
|
||||||
|
|
||||||
if (_newDamage < 0) then {
|
|
||||||
_newDamage = -_newDamage;
|
|
||||||
};
|
|
||||||
|
|
||||||
private _currentPartDamage = _vehicle getHitIndex _hitIndex;
|
private _currentPartDamage = _vehicle getHitIndex _hitIndex;
|
||||||
private _nextPartDamage = _currentPartDamage + _newDamage;
|
private _newPartDamage = _currentPartDamage + _addedDamage;
|
||||||
|
|
||||||
|
// Damage is high enough for immediate destruction
|
||||||
|
if (_addedDamage >= 15) exitWith {
|
||||||
|
TRACE_2("immediate destruction - high damage",_addedDamage,_currentPartDamage);
|
||||||
|
|
||||||
// damage is high enough for immediate destruction
|
|
||||||
if (_newDamage >= 15) exitWith {
|
|
||||||
TRACE_2("immediate destruction - high damage",_newDamage,_currentPartDamage);
|
|
||||||
[_vehicle] call FUNC(knockOut);
|
|
||||||
[_vehicle, 1] call FUNC(handleDetonation);
|
|
||||||
// Kill everyone inside for very insane damage
|
// Kill everyone inside for very insane damage
|
||||||
{
|
{
|
||||||
[QGVAR(medicalDamage), [_x, _injurer, _injurer, true], _x] call CBA_fnc_targetEvent;
|
[QGVAR(medicalDamage), [_x, _source, _instigator, true], _x] call CBA_fnc_targetEvent;
|
||||||
} forEach (crew _vehicle);
|
} forEach (crew _vehicle);
|
||||||
_vehicle setDamage 1;
|
|
||||||
_return = false;
|
// setDamage triggers "Killed" EH in cookoff, which starts ammo cook-off
|
||||||
_return
|
[QGVAR(setDamage), [_vehicle, [1, true, _source, _instigator]]] call CBA_fnc_serverEvent;
|
||||||
|
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
private _projectileConfig = _projectile call CBA_fnc_getObjectConfig;
|
private _projectileConfig = _projectile call CBA_fnc_getObjectConfig;
|
||||||
|
|
||||||
private _warheadTypeStr = getText (_projectileConfig >> "warheadName");
|
private _warheadTypeStr = toLowerANSI getText (_projectileConfig >> "warheadName");
|
||||||
private _incendiary = [_projectileConfig >> QGVAR(incendiary), "NUMBER", -1] call CBA_fnc_getConfigEntry;
|
private _warheadType = ["he", "ap", "heat", "tandemheat"] find _warheadTypeStr; // numerical index for warhead type for quicker checks. Numbers defined in script_macros.hpp
|
||||||
private _warheadType = ["HE", "AP", "HEAT", "TandemHEAT"] find _warheadTypeStr; // numerical index for warhead type for quicker checks. Numbers defined in script_macros.hpp
|
|
||||||
if (_warheadType < 0) then {
|
|
||||||
_warheadType = WARHEAD_TYPE_NONE;
|
|
||||||
};
|
|
||||||
if (_incendiary < 0) then {
|
|
||||||
_incendiary = [0.3, 0.1, 1, 1, 0] select _warheadType;
|
|
||||||
};
|
|
||||||
|
|
||||||
private _minDamage = [_hitpointConfig >> "minimalHit", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
private _incendiary = [_projectileConfig >> QGVAR(incendiary), "NUMBER", [0.3, 0.1, 1, 1, 0] select _warheadType] call CBA_fnc_getConfigEntry;
|
||||||
if (_minDamage < 0) then {
|
|
||||||
_minDamage = -_minDamage;
|
|
||||||
};
|
|
||||||
|
|
||||||
private _ammoEffectiveness = 0;
|
private _hitPointHash = GVAR(vehicleClassesHitPointHash) getOrDefault [typeOf _vehicle, createHashMap];
|
||||||
private _projectileExplosive = [_projectileConfig >> "explosive", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
(_hitPointHash getOrDefault [_hitPoint, []]) params ["_hitArea", "_minDamage"];
|
||||||
private _indirectHit = [_projectileConfig >> "indirectHit", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
|
||||||
|
|
||||||
if (_warheadType isEqualTo WARHEAD_TYPE_AP) then {
|
private _projectileExplosive = getNumber (_projectileConfig >> "explosive");
|
||||||
// change damage based on projectile speed (doesn't do this in vanilla ARMA believe it or not)
|
private _indirectHit = getNumber (_projectileConfig >> "indirectHit");
|
||||||
if !(isNull _injurer) then {
|
|
||||||
private _airFriction = [_projectileConfig >> "airFriction", "NUMBER", 0] call CBA_fnc_getConfigEntry;
|
if (_warheadType == WARHEAD_TYPE_AP) then {
|
||||||
private _distance = _injurer distance _vehicle;
|
// Change damage based on projectile speed (doesn't do this in vanilla Arma believe it or not)
|
||||||
_newDamage = (1 - _projectileExplosive) * _newDamage * exp(_airFriction * _distance);
|
if (!isNull _source) then {
|
||||||
|
private _airFriction = getNumber (_projectileConfig >> "airFriction");
|
||||||
|
private _distance = _source distance _vehicle;
|
||||||
|
_addedDamage = (1 - _projectileExplosive) * _addedDamage * exp (_airFriction * _distance);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
private _penChance = 1;
|
private _penChance = 1;
|
||||||
if (_newDamage < _minDamage) then {
|
|
||||||
_penChance = _newDamage / _minDamage;
|
// Added damage can't be 0, so don't need to worry about 0 division here
|
||||||
TRACE_5("minimum damage modifying hit",_newDamage,_penChance,abs _minDamage,_warheadTypeStr,_hitArea);
|
if (_addedDamage < _minDamage) then {
|
||||||
|
_penChance = _addedDamage / _minDamage;
|
||||||
|
|
||||||
|
TRACE_5("minimum damage modifying hit",_addedDamage,_penChance,_minDamage,_warheadTypeStr,_hitArea);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_penChance < random 1) exitWith {
|
if (_penChance < random 1) exitWith {
|
||||||
TRACE_1("didn't penetrate",_penChance);
|
TRACE_1("didn't penetrate",_penChance);
|
||||||
_return
|
|
||||||
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_minDamage == 0) then {
|
if (_minDamage == 0) then {
|
||||||
_minDamage = 1;
|
_minDamage = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_warheadType isEqualTo WARHEAD_TYPE_HE) then {
|
if (_warheadType == WARHEAD_TYPE_HE) then {
|
||||||
private _modifiedIndirectHit = _indirectHit / 100;
|
private _modifiedIndirectHit = _indirectHit / 100;
|
||||||
if (_newDamage > _modifiedIndirectHit) then {
|
|
||||||
_newDamage = _newDamage / 2;
|
if (_addedDamage > _modifiedIndirectHit) then {
|
||||||
|
_addedDamage = _addedDamage / 2;
|
||||||
};
|
};
|
||||||
_newDamage = (_newDamage * (_newDamage / _modifiedIndirectHit)) min _newDamage;
|
|
||||||
|
_addedDamage = (_addedDamage * (_addedDamage / _modifiedIndirectHit)) min _addedDamage;
|
||||||
};
|
};
|
||||||
|
|
||||||
_ammoEffectiveness = if (_warheadType isEqualTo WARHEAD_TYPE_AP) then {
|
private _ammoEffectiveness = if (_warheadType == WARHEAD_TYPE_AP) then {
|
||||||
0.15 max _newDamage
|
0.15 max _addedDamage
|
||||||
} else {
|
} else {
|
||||||
if (_warheadType isEqualTo WARHEAD_TYPE_HE) then {
|
if (_warheadType == WARHEAD_TYPE_HE) then {
|
||||||
(_newDamage / (_minDamage + (_indirectHit / 100)) * 0.2)
|
(_addedDamage / (_minDamage + (_indirectHit / 100)) * 0.2)
|
||||||
} else {
|
} else {
|
||||||
((_newDamage / _minDamage) * 0.4) min 1
|
((_addedDamage / _minDamage) * 0.4) min 1
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
TRACE_4("ammo effectiveness",_ammoEffectiveness,_newDamage,_minDamage,_warheadTypeStr);
|
|
||||||
|
TRACE_4("ammo effectiveness",_ammoEffectiveness,_addedDamage,_minDamage,_warheadTypeStr);
|
||||||
|
|
||||||
_incendiary = _incendiary * _ammoEffectiveness;
|
_incendiary = _incendiary * _ammoEffectiveness;
|
||||||
|
|
||||||
private _isCar = (_vehicle isKindOf "Car" && { !(_vehicle isKindOf "Wheeled_APC_F") });
|
private _isCar = _vehicle isKindOf "Car" && {!(_vehicle isKindOf "Wheeled_APC_F")};
|
||||||
|
|
||||||
if (_isCar) then {
|
if (_isCar) then {
|
||||||
_ammoEffectiveness = (_ammoEffectiveness + (_ammoEffectiveness * 0.5)) min 1;
|
_ammoEffectiveness = (_ammoEffectiveness * 1.5) min 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
private _currentVehicleAmmo = _vehicle call EFUNC(cookoff,getVehicleAmmo);
|
(_vehicle call EFUNC(cookoff,getVehicleAmmo)) params ["_magazines", "_totalAmmo"];
|
||||||
private _chanceOfDetonation = 0;
|
private _chanceOfDetonation = 0;
|
||||||
private _explosiveAmmoCount = 0;
|
private _explosiveAmmoCount = 0;
|
||||||
private _nonExplosiveAmmoCount = 0;
|
|
||||||
|
|
||||||
if ((_currentVehicleAmmo select 0) isNotEqualTo []) then {
|
if (_magazines isNotEqualTo []) then {
|
||||||
private _magConfig = configFile >> "CfgMagazines";
|
private _magConfig = configFile >> "CfgMagazines";
|
||||||
private _ammoConfig = configFile >> "CfgAmmo";
|
private _ammoConfig = configFile >> "CfgAmmo";
|
||||||
private _countOfExplodableAmmo = 0;
|
private _countOfExplodableAmmo = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
_x params ["_magazineClassname", "_currentAmmoCount"];
|
_x params ["_magazineClassname", "_currentAmmoCount"];
|
||||||
|
|
||||||
private _initialAmmoCount = getNumber (_magConfig >> _magazineClassname >> "count");
|
private _initialAmmoCount = getNumber (_magConfig >> _magazineClassname >> "count");
|
||||||
_chanceOfDetonation = _chanceOfDetonation + (_currentAmmoCount / _initialAmmoCount);
|
_chanceOfDetonation = _chanceOfDetonation + (_currentAmmoCount / _initialAmmoCount);
|
||||||
_countOfExplodableAmmo = _countOfExplodableAmmo + 1;
|
_countOfExplodableAmmo = _countOfExplodableAmmo + 1;
|
||||||
@ -135,215 +134,241 @@ if ((_currentVehicleAmmo select 0) isNotEqualTo []) then {
|
|||||||
private _ammoClassname = getText (_magConfig >> _magazineClassname >> "ammo");
|
private _ammoClassname = getText (_magConfig >> _magazineClassname >> "ammo");
|
||||||
private _explosive = getNumber (_ammoConfig >> _ammoClassname >> "explosive");
|
private _explosive = getNumber (_ammoConfig >> _ammoClassname >> "explosive");
|
||||||
private _hit = getNumber (_ammoConfig >> _ammoClassname >> "hit");
|
private _hit = getNumber (_ammoConfig >> _ammoClassname >> "hit");
|
||||||
if (_explosive > 0.5 || _hit > 50) then {
|
|
||||||
|
if (_explosive > 0.5 || {_hit > 50}) then {
|
||||||
_explosiveAmmoCount = _explosiveAmmoCount + 1;
|
_explosiveAmmoCount = _explosiveAmmoCount + 1;
|
||||||
} else {
|
|
||||||
_nonExplosiveAmmoCount = _nonExplosiveAmmoCount + 1;
|
|
||||||
};
|
};
|
||||||
} forEach (_currentVehicleAmmo select 0);
|
} forEach _magazines;
|
||||||
|
|
||||||
if (_countOfExplodableAmmo != 0) then {
|
if (_countOfExplodableAmmo != 0) then {
|
||||||
_chanceOfDetonation = _chanceOfDetonation / _countOfExplodableAmmo;
|
_chanceOfDetonation = _chanceOfDetonation / _countOfExplodableAmmo;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
private _chanceToDetonate = 0;
|
|
||||||
private _chanceOfFire = 0;
|
private _return = true;
|
||||||
private _currentFuel = fuel _vehicle;
|
|
||||||
private _vehicleConfig = _vehicle call CBA_fnc_getObjectConfig;
|
|
||||||
switch (_hitArea) do {
|
switch (_hitArea) do {
|
||||||
case "engine": {
|
case "engine": {
|
||||||
_chanceToDetonate = ([_vehicleConfig >> QGVAR(engineDetonationProb), "NUMBER", 0] call CBA_fnc_getConfigEntry) * _incendiary * _currentFuel * _penChance;
|
private _vehicleConfig = configOf _vehicle;
|
||||||
_chanceOfFire = ([_vehicleConfig >> QGVAR(engineFireProb), "NUMBER", 0] call CBA_fnc_getConfigEntry) * _incendiary * _currentFuel * _penChance;
|
private _currentFuel = fuel _vehicle;
|
||||||
|
private _chanceToDetonate = getNumber (_vehicleConfig >> QGVAR(engineDetonationProb)) * _incendiary * _currentFuel * _penChance;
|
||||||
|
|
||||||
private _cookoffIntensity = 4 * _currentFuel;
|
TRACE_4("hit engine",_chanceToDetonate,_incendiary,_chanceOfDetonation,_currentFuel);
|
||||||
TRACE_6("hit engine",_chanceToDetonate,_chanceOfFire,_incendiary,_chanceOfDetonation,_currentFuel,_cookoffIntensity);
|
|
||||||
|
|
||||||
if (_isCar) then {
|
// Knock out and detonate vehicle if necessary
|
||||||
_chanceOfFire = 0; // no cookoff for cars
|
if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount > 0, _totalAmmo > 0, _source, _instigator] call FUNC(handleDetonation)) exitWith {};
|
||||||
|
|
||||||
|
// Cap damage at 0.9 to avoid hard coded blow up
|
||||||
|
_newPartDamage = 0.9 min _newPartDamage;
|
||||||
|
|
||||||
|
// Fatal engine/drive system damage (engine and tracks stop working at 0.9)
|
||||||
|
if (0.8 * _ammoEffectiveness > random 1) then {
|
||||||
|
_newPartDamage = 0.9;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith {
|
if (_newPartDamage == 0.9) then {
|
||||||
[_vehicle] call FUNC(knockOut);
|
|
||||||
};
|
|
||||||
|
|
||||||
// cap damage at 0.9 to avoid hard coded blow up
|
|
||||||
_nextPartDamage = (0.9 min _nextPartDamage);
|
|
||||||
|
|
||||||
// fatal engine/drive system damage
|
|
||||||
if (_nextPartDamage == 0.9 || { 0.8 * _ammoEffectiveness > random 1 }) then {
|
|
||||||
[_vehicle, _hitIndex, _hitpointName, 0.9 * _penChance] call FUNC(addDamage);
|
|
||||||
_vehicle setVariable [QGVAR(canMove), false];
|
_vehicle setVariable [QGVAR(canMove), false];
|
||||||
} else {
|
|
||||||
[_vehicle, _hitIndex, _hitpointName, _nextPartDamage * _penChance] call FUNC(addDamage);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, _hitArea, false] call FUNC(handleCookoff);
|
[_vehicle, _hitPoint, _hitIndex, _newPartDamage * _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
|
|
||||||
|
// No cookoff for cars
|
||||||
|
if (_isCar) exitWith {};
|
||||||
|
|
||||||
|
private _chanceOfFire = getNumber (_vehicleConfig >> QGVAR(engineFireProb)) * _incendiary * _currentFuel * _penChance;
|
||||||
|
private _cookoffIntensity = 4 * _currentFuel;
|
||||||
|
|
||||||
|
[_vehicle, _chanceOfFire, _cookoffIntensity, _source, _instigator, "engine", false, false] call FUNC(handleCookoff);
|
||||||
};
|
};
|
||||||
case "hull": {
|
case "hull": {
|
||||||
_chanceToDetonate = ([_vehicleConfig >> QGVAR(hullDetonationProb), "NUMBER", 0] call CBA_fnc_getConfigEntry) * _incendiary * ((_chanceOfDetonation + _currentFuel) / 2) * _penChance;
|
private _vehicleConfig = configOf _vehicle;
|
||||||
_chanceOfFire = ([_vehicleConfig >> QGVAR(hullFireProb), "NUMBER", 0] call CBA_fnc_getConfigEntry) * _incendiary * ((_chanceOfDetonation + _currentFuel) / 2) * _penChance;
|
private _currentFuel = fuel _vehicle;
|
||||||
|
private _chanceToDetonate = getNumber (_vehicleConfig >> QGVAR(hullDetonationProb)) * _incendiary * ((_chanceOfDetonation + _currentFuel) / 2) * _penChance;
|
||||||
|
|
||||||
private _cookoffIntensity = 1.5 + (_explosiveAmmoCount * _chanceOfFire);
|
TRACE_4("hit hull",_chanceToDetonate,_incendiary,_chanceOfDetonation,_currentFuel);
|
||||||
TRACE_6("hit hull",_chanceToDetonate,_chanceOfFire,_incendiary,_chanceOfDetonation,_currentFuel,_cookoffIntensity);
|
|
||||||
|
|
||||||
if (_isCar) then {
|
// Knock out and detonate vehicle if necessary
|
||||||
_chanceOfFire = 0; // no cookoff for cars
|
if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount > 0, _totalAmmo > 0, _source, _instigator] call FUNC(handleDetonation)) exitWith {
|
||||||
|
[_vehicle, _hitPoint, _hitIndex, 0.89 * _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
};
|
};
|
||||||
|
|
||||||
if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith {
|
|
||||||
[_vehicle, _hitIndex, _hitpointName, 0.89 * _penChance] call FUNC(addDamage);
|
|
||||||
[_vehicle] call FUNC(knockOut);
|
|
||||||
};
|
|
||||||
|
|
||||||
private _hash = _vehicle getVariable [QGVAR(hitpointHash), []];
|
|
||||||
private _hashKeys = [_hash] call CBA_fnc_hashKeys;
|
|
||||||
|
|
||||||
// 25% chance of jamming turret - 25% of mobility kill - 25% of both - 75% chance of critical hull damage
|
// 25% chance of jamming turret - 25% of mobility kill - 25% of both - 75% chance of critical hull damage
|
||||||
private _rand = random 1;
|
private _rand = random 1;
|
||||||
|
|
||||||
TRACE_2("rolling hull damage",_ammoEffectiveness,_rand);
|
TRACE_2("rolling hull damage",_ammoEffectiveness,_rand);
|
||||||
|
|
||||||
private _partKill = [];
|
private _partKill = [];
|
||||||
|
|
||||||
if (_ammoEffectiveness > _rand) then {
|
if (_ammoEffectiveness > _rand) then {
|
||||||
_rand = random 1;
|
_rand = random 1;
|
||||||
|
|
||||||
TRACE_2("damaged hull part",_ammoEffectiveness,_rand);
|
TRACE_2("damaged hull part",_ammoEffectiveness,_rand);
|
||||||
|
|
||||||
switch (true) do {
|
switch (true) do {
|
||||||
case (_rand < 0.25): {
|
case (_rand < 0.25): {
|
||||||
[_vehicle, _hitIndex, _hitpointName, 0.89 * _penChance] call FUNC(addDamage);
|
[_vehicle, _hitPoint, _hitIndex, 0.89 * _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
// iterate through all keys and find appropriate turret
|
|
||||||
[_hash, {
|
// Iterate through all keys and find appropriate turret
|
||||||
if (_value#0 isEqualTo "turret") then {
|
{
|
||||||
_partKill pushBack _key;
|
if ((_y select 0) == "turret") then {
|
||||||
|
_partKill pushBack _x;
|
||||||
};
|
};
|
||||||
}] call CBA_fnc_hashEachPair;
|
} forEach _hitPointHash;
|
||||||
|
|
||||||
_vehicle setVariable [QGVAR(canShoot), false];
|
_vehicle setVariable [QGVAR(canShoot), false];
|
||||||
};
|
};
|
||||||
case (_rand < 0.5): {
|
case (_rand < 0.5): {
|
||||||
[_vehicle, _hitIndex, _hitpointName, 0.89 * _penChance] call FUNC(addDamage);
|
[_vehicle, _hitPoint, _hitIndex, 0.89 * _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
_partKill = _partKill + ENGINE_HITPOINTS#0;
|
|
||||||
|
_partKill append (ENGINE_HITPOINTS select 0);
|
||||||
|
|
||||||
if !(_vehicle isKindOf "Wheeled_APC_F") then {
|
if !(_vehicle isKindOf "Wheeled_APC_F") then {
|
||||||
_partKill = _partKill + TRACK_HITPOINTS#0;
|
_partKill append (TRACK_HITPOINTS select 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
_vehicle setVariable [QGVAR(canMove), false];
|
_vehicle setVariable [QGVAR(canMove), false];
|
||||||
};
|
};
|
||||||
case (_rand < 0.75): {
|
case (_rand < 0.75): {
|
||||||
[_vehicle, _hitIndex, _hitpointName, 0.89 * _penChance] call FUNC(addDamage);
|
[_vehicle, _hitPoint, _hitIndex, 0.89 * _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
_partKill = _partKill + ENGINE_HITPOINTS#0;
|
|
||||||
|
_partKill append (ENGINE_HITPOINTS select 0);
|
||||||
|
|
||||||
if !(_vehicle isKindOf "Wheeled_APC_F") then {
|
if !(_vehicle isKindOf "Wheeled_APC_F") then {
|
||||||
_partKill = _partKill + TRACK_HITPOINTS#0;
|
_partKill append (TRACK_HITPOINTS select 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
// iterate through all keys and find appropriate turret
|
// Iterate through all keys and find appropriate turret
|
||||||
[_hash, {
|
{
|
||||||
if (_value#0 isEqualTo "turret") then {
|
if ((_y select 0) == "turret") then {
|
||||||
_partKill pushBack _key;
|
_partKill pushBack _x;
|
||||||
};
|
};
|
||||||
}] call CBA_fnc_hashEachPair;
|
} forEach _hitPointHash;
|
||||||
|
|
||||||
_vehicle setVariable [QGVAR(canMove), false];
|
_vehicle setVariable [QGVAR(canMove), false];
|
||||||
_vehicle setVariable [QGVAR(canShoot), false];
|
_vehicle setVariable [QGVAR(canShoot), false];
|
||||||
};
|
};
|
||||||
default{};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
[_vehicle, _x, -1, _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
|
|
||||||
TRACE_1("doing damage to hitpoint",_x);
|
TRACE_1("doing damage to hitpoint",_x);
|
||||||
[_vehicle, -1, _x, 1 * _penChance] call FUNC(addDamage);
|
|
||||||
} forEach _partKill;
|
} forEach _partKill;
|
||||||
|
|
||||||
[_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, "", true] call FUNC(handleCookoff);
|
// No cookoff for cars
|
||||||
|
if (_isCar) exitWith {};
|
||||||
|
|
||||||
|
private _chanceOfFire = getNumber (_vehicleConfig >> QGVAR(hullFireProb)) * _incendiary * ((_chanceOfDetonation + _currentFuel) / 2) * _penChance;
|
||||||
|
private _cookoffIntensity = 1.5 + (_explosiveAmmoCount * _chanceOfFire);
|
||||||
|
|
||||||
|
[_vehicle, _chanceOfFire, _cookoffIntensity, _source, _instigator] call FUNC(handleCookoff);
|
||||||
};
|
};
|
||||||
case "turret": {
|
case "turret": {
|
||||||
_chanceToDetonate = ([_vehicleConfig >> QGVAR(turretDetonationProb), "NUMBER", 0] call CBA_fnc_getConfigEntry) * _incendiary * _chanceOfDetonation * _penChance;
|
private _vehicleConfig = configOf _vehicle;
|
||||||
_chanceOfFire = ([_vehicleConfig >> QGVAR(turretFireProb), "NUMBER", 0] call CBA_fnc_getConfigEntry) * _incendiary * _chanceOfDetonation * _penChance;
|
private _chanceToDetonate = getNumber (_vehicleConfig >> QGVAR(turretDetonationProb)) * _incendiary * _chanceOfDetonation * _penChance;
|
||||||
|
|
||||||
private _cookoffIntensity = _explosiveAmmoCount * _chanceOfFire;
|
TRACE_3("hit turret",_chanceToDetonate,_incendiary,_chanceOfDetonation);
|
||||||
TRACE_6("hit turret",_chanceToDetonate,_chanceOfFire,_incendiary,_chanceOfDetonation,_currentFuel,_cookoffIntensity);
|
|
||||||
|
|
||||||
if (_isCar) then {
|
if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount > 0, _totalAmmo > 0, _source, _instigator] call FUNC(handleDetonation)) exitWith {};
|
||||||
_chanceOfFire = 0; // no cookoff for cars
|
|
||||||
};
|
|
||||||
|
|
||||||
if ([_vehicle, _chanceToDetonate, _explosiveAmmoCount, _nonExplosiveAmmoCount, _injurer] call FUNC(handleDetonation)) exitWith {
|
|
||||||
[_vehicle] call FUNC(knockOut);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (0.8 * _ammoEffectiveness > random 1) then {
|
if (0.8 * _ammoEffectiveness > random 1) then {
|
||||||
TRACE_1("damaged turret",_ammoEffectiveness * 0.8);
|
TRACE_1("damaged turret",_ammoEffectiveness * 0.8);
|
||||||
[_vehicle, _hitIndex, _hitpointName, 1 * _penChance] call FUNC(addDamage);
|
|
||||||
|
[_vehicle, _hitPoint, _hitIndex, _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
|
|
||||||
_vehicle setVariable [QGVAR(canShoot), false];
|
_vehicle setVariable [QGVAR(canShoot), false];
|
||||||
};
|
};
|
||||||
|
|
||||||
[_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, "", true] call FUNC(handleCookoff);
|
// No cookoff for cars
|
||||||
|
if (_isCar) exitWith {};
|
||||||
|
|
||||||
|
private _chanceOfFire = getNumber (_vehicleConfig >> QGVAR(turretFireProb)) * _incendiary * _chanceOfDetonation * _penChance;
|
||||||
|
private _cookoffIntensity = _explosiveAmmoCount * _chanceOfFire;
|
||||||
|
|
||||||
|
[_vehicle, _chanceOfFire, _cookoffIntensity, _source, _instigator] call FUNC(handleCookoff);
|
||||||
};
|
};
|
||||||
case "gun": {
|
case "gun": {
|
||||||
TRACE_5("hit gun",_chanceToDetonate,_chanceOfFire,_incendiary,_chanceOfDetonation,_currentFuel);
|
TRACE_2("hit gun",_addedDamage,_minDamage);
|
||||||
|
|
||||||
if (0.8 * _ammoEffectiveness > random 1) then {
|
if (0.8 * _ammoEffectiveness > random 1) then {
|
||||||
TRACE_1("damaged gun",_ammoEffectiveness * 0.8);
|
TRACE_1("damaged gun",_ammoEffectiveness * 0.8);
|
||||||
[_vehicle, _hitIndex, _hitpointName, 1 * _penChance] call FUNC(addDamage);
|
|
||||||
|
[_vehicle, _hitPoint, _hitIndex, _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
|
|
||||||
_vehicle setVariable [QGVAR(canShoot), false];
|
_vehicle setVariable [QGVAR(canShoot), false];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
case "track": {
|
case "track": {
|
||||||
private _damage = (0.1 max (0.1 * _newDamage / _minDamage)) min 1;
|
private _damage = (0.1 max (0.1 * _addedDamage / _minDamage)) min 1;
|
||||||
[_vehicle, _hitIndex, _hitpointName, (_currentPartDamage + _damage) * _penChance] call FUNC(addDamage);
|
|
||||||
TRACE_3("damaged track",_damage,_newDamage,_minDamage);
|
[_vehicle, _hitPoint, _hitIndex, (_currentPartDamage + _damage) * _penChance] call FUNC(setDamage);
|
||||||
|
|
||||||
|
TRACE_3("damaged track",_damage,_addedDamage,_minDamage);
|
||||||
|
|
||||||
if ((_vehicle getHitIndex _hitIndex) >= 1) then {
|
if ((_vehicle getHitIndex _hitIndex) >= 1) then {
|
||||||
_vehicle setVariable [QGVAR(canMove), false];
|
_vehicle setVariable [QGVAR(canMove), false];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
case "wheel": {
|
case "wheel": {
|
||||||
[_vehicle, _hitIndex, _hitpointName, (_currentPartDamage + _newDamage) * _penChance] call FUNC(addDamage);
|
[_vehicle, _hitPoint, _hitIndex, (_currentPartDamage + _addedDamage) * _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
TRACE_1("damaged wheel",_newDamage);
|
|
||||||
|
TRACE_1("damaged wheel",_addedDamage);
|
||||||
};
|
};
|
||||||
case "fuel": {
|
case "fuel": {
|
||||||
_chanceOfFire = (_incendiary * _currentFuel * _penChance) / 2;
|
private _damage = (0.1 max (0.1 * _addedDamage / _minDamage)) min 1;
|
||||||
|
[_vehicle, _hitPoint, _hitIndex, (_currentPartDamage + _damage) * _penChance, _source, _instigator] call FUNC(setDamage);
|
||||||
|
|
||||||
|
// No cookoff for cars
|
||||||
|
if (_isCar) exitWith {};
|
||||||
|
|
||||||
|
private _currentFuel = fuel _vehicle;
|
||||||
|
private _chanceOfFire = (_incendiary * _currentFuel * _penChance) / 2;
|
||||||
private _cookoffIntensity = _currentFuel * 5;
|
private _cookoffIntensity = _currentFuel * 5;
|
||||||
TRACE_2("damaged fuel",_chanceOfFire,_cookoffIntensity);
|
|
||||||
|
|
||||||
if (_isCar) then {
|
TRACE_4("damaged fuel",_chanceOfFire,_incendiary,_cookoffIntensity,_currentFuel);
|
||||||
_chanceOfFire = 0; // no cookoff for cars
|
|
||||||
};
|
|
||||||
|
|
||||||
[_vehicle, _chanceOfFire, _cookoffIntensity, _injurer, "", false] call FUNC(handleCookoff);
|
[_vehicle, _chanceOfFire, _cookoffIntensity, _source, _instigator, "", false, false] call FUNC(handleCookoff);
|
||||||
|
|
||||||
private _damage = (0.1 max (0.1 * _newDamage / _minDamage)) min 1;
|
|
||||||
[_vehicle, _hitIndex, _hitpointName, (_currentPartDamage + _damage) * _penChance] call FUNC(addDamage);
|
|
||||||
};
|
};
|
||||||
case "slat": {
|
case "slat": {
|
||||||
TRACE_2("hit slat",_warheadType,_warheadTypeStr);
|
TRACE_2("hit slat",_warheadType,_warheadTypeStr);
|
||||||
// incredibly small chance of AP destroying SLAT
|
|
||||||
if (_warheadType in [WARHEAD_TYPE_HE, WARHEAD_TYPE_AP, WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM] || { 0.01 > random 1 }) then {
|
// Incredibly small chance of AP destroying SLAT
|
||||||
|
if (_warheadType in [WARHEAD_TYPE_HE, WARHEAD_TYPE_AP, WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM] || {0.01 > random 1}) then {
|
||||||
private _currentDamage = _vehicle getHitIndex _hitIndex;
|
private _currentDamage = _vehicle getHitIndex _hitIndex;
|
||||||
|
|
||||||
TRACE_3("damaged slat",_warheadType,_warheadTypeStr,_currentDamage);
|
TRACE_3("damaged slat",_warheadType,_warheadTypeStr,_currentDamage);
|
||||||
|
|
||||||
if (_warheadType in [WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM, WARHEAD_TYPE_AP]) then {
|
if (_warheadType in [WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM, WARHEAD_TYPE_AP]) then {
|
||||||
[_vehicle, _hitIndex, _hitpointName, 1] call FUNC(addDamage);
|
[_vehicle, _hitPoint, _hitIndex, 1, _source, _instigator] call FUNC(setDamage);
|
||||||
} else {
|
} else {
|
||||||
[_vehicle, _hitIndex, _hitpointName, _currentDamage + (0.5 max random 1)] call FUNC(addDamage);
|
[_vehicle, _hitPoint, _hitIndex, _currentDamage + (0.5 max random 1), _source, _instigator] call FUNC(setDamage);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_currentDamage < 1 && _warheadType isEqualTo WARHEAD_TYPE_HEAT) then {
|
if (_currentDamage < 1 && {_warheadType == WARHEAD_TYPE_HEAT}) then {
|
||||||
_return = false;
|
_return = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
case "era": {
|
case "era": {
|
||||||
TRACE_2("hit era",_warheadType,_warheadTypeStr);
|
TRACE_2("hit era",_warheadType,_warheadTypeStr);
|
||||||
if (_warheadType in [WARHEAD_TYPE_AP, WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM] || { 0.05 > random 1 }) then {
|
|
||||||
private _currentDamage = _vehicle getHitIndex _hitIndex;
|
|
||||||
TRACE_3("damaged era",_warheadType,_warheadTypeStr,_currentDamage);
|
|
||||||
[_vehicle, _hitIndex, _hitpointName, 1] call FUNC(addDamage);
|
|
||||||
|
|
||||||
// dont process anymore damage if this is HEAT - shouldnt happen anyway but ARMA says it does so you know
|
if (_warheadType in [WARHEAD_TYPE_AP, WARHEAD_TYPE_HEAT, WARHEAD_TYPE_TANDEM] || {0.05 > random 1}) then {
|
||||||
if (_currentDamage < 1 && _warheadType isEqualTo WARHEAD_TYPE_HEAT) then {
|
private _currentDamage = _vehicle getHitIndex _hitIndex;
|
||||||
|
|
||||||
|
TRACE_3("damaged era",_warheadType,_warheadTypeStr,_currentDamage);
|
||||||
|
|
||||||
|
[_vehicle, _hitPoint, _hitIndex, 1, _source, _instigator] call FUNC(setDamage);
|
||||||
|
|
||||||
|
// Don't process anymore damage if this is HEAT - shouldn't happen anyway but Arma says it does so you know
|
||||||
|
if (_currentDamage < 1 && {_warheadType == WARHEAD_TYPE_HEAT}) then {
|
||||||
_return = false;
|
_return = false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
default {
|
default {
|
||||||
TRACE_1("hit unknown hitpoint??",_hitArea);
|
TRACE_1("hit unknown hitpoint??",_hitArea);
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
_return
|
_return
|
||||||
|
45
addons/vehicle_damage/functions/fnc_setDamage.sqf
Normal file
45
addons/vehicle_damage/functions/fnc_setDamage.sqf
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include "..\script_component.hpp"
|
||||||
|
/*
|
||||||
|
* Author: tcvm
|
||||||
|
* Sets vehicle damage based on HitIndex. Failing that it falls back to HitPoint name.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* 0: Vehicle <OBJECT>
|
||||||
|
* 1: Hit point <STRING>
|
||||||
|
* 2: Hit index <NUMBER>
|
||||||
|
* 3: Damage <NUMBER>
|
||||||
|
* 4: Source of damage <OBJECT>
|
||||||
|
* 5: Person who caused damage <OBJECT>
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* [cursorObject, "HitEngine", 1, 0.25, player, player] call ace_vehicle_damage_fnc_setDamage
|
||||||
|
*
|
||||||
|
* Public: No
|
||||||
|
*/
|
||||||
|
|
||||||
|
params ["_vehicle", "_hitPoint", "_hitIndex", "_damage", "_source", "_instigator"];
|
||||||
|
TRACE_6("setDamage",_vehicle,_hitPoint,_hitIndex,_damage,_source,_instigator);
|
||||||
|
|
||||||
|
private _currentDamage = _vehicle getHitPointDamage _hitPoint;
|
||||||
|
|
||||||
|
if (_damage < _currentDamage) exitWith {
|
||||||
|
TRACE_3("capping damage at current",_damage,_currentDamage,_hitPoint);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_hitPoint == "#structural") then {
|
||||||
|
_hitPoint = "hithull";
|
||||||
|
_hitIndex = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_hitIndex >= 0) then {
|
||||||
|
_vehicle setHitIndex [_hitIndex, _damage, true, _source, _instigator];
|
||||||
|
} else {
|
||||||
|
_vehicle setHitPointDamage [_hitPoint, _damage, true, _source, _instigator];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (_hitPoint == "HitEngine" && {_damage >= 0.9}) then {
|
||||||
|
[QEGVAR(cookoff,engineFireServer), _vehicle] call CBA_fnc_serverEvent;
|
||||||
|
};
|
@ -1,19 +1,21 @@
|
|||||||
[
|
[
|
||||||
QGVAR(enabled), "CHECKBOX",
|
QGVAR(enabled),
|
||||||
|
"CHECKBOX",
|
||||||
[ELSTRING(common,Enabled), LSTRING(setting_description)],
|
[ELSTRING(common,Enabled), LSTRING(setting_description)],
|
||||||
LSTRING(category_displayName),
|
LSTRING(category_displayName),
|
||||||
false, // default value
|
false,
|
||||||
true, // isGlobal
|
1,
|
||||||
{[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
{[QGVAR(enabled), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
true // Needs mission restart
|
true // Needs mission restart
|
||||||
] call CBA_settings_fnc_init;
|
] call CBA_fnc_addSetting;
|
||||||
|
|
||||||
[
|
[
|
||||||
QGVAR(enableCarDamage), "CHECKBOX",
|
QGVAR(enableCarDamage),
|
||||||
|
"CHECKBOX",
|
||||||
[LSTRING(carDamage_setting_enable), LSTRING(carDamage_setting_description)],
|
[LSTRING(carDamage_setting_enable), LSTRING(carDamage_setting_description)],
|
||||||
LSTRING(category_displayName),
|
LSTRING(category_displayName),
|
||||||
false, // default value
|
false,
|
||||||
true, // isGlobal
|
1,
|
||||||
{[QGVAR(enableCarDamage), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
{[QGVAR(enableCarDamage), _this] call EFUNC(common,cbaSettings_settingChanged)},
|
||||||
true // Needs mission restart
|
true // Needs mission restart
|
||||||
] call CBA_settings_fnc_init;
|
] call CBA_fnc_addSetting;
|
||||||
|
@ -7,21 +7,23 @@
|
|||||||
#define IS_EXPLOSIVE_AMMO(ammo) (getNumber (ammo call CBA_fnc_getObjectConfig >> "explosive") > 0.5)
|
#define IS_EXPLOSIVE_AMMO(ammo) (getNumber (ammo call CBA_fnc_getObjectConfig >> "explosive") > 0.5)
|
||||||
|
|
||||||
#define ENGINE_HITPOINTS [["hitengine"], "engine"]
|
#define ENGINE_HITPOINTS [["hitengine"], "engine"]
|
||||||
#define HULL_HITPOINTS [["hithull", "hitbody", "#structural"],"hull"]
|
#define HULL_HITPOINTS [["hithull", "hitbody", "#structural"], "hull"]
|
||||||
#define TRACK_HITPOINTS [["hitltrack", "hitrtrack"], "track"]
|
#define TRACK_HITPOINTS [["hitltrack", "hitrtrack"], "track"]
|
||||||
#define WHEEL_HITPOINTS [["hitlbwheel", "hitlmwheel", "hitlfwheel", "hitlf2wheel", "hitrbwheel", "hitrmwheel", "hitrlwheel", "hitrfwheel", "hitrf2wheel"], "wheel"]
|
#define WHEEL_HITPOINTS [["hitlbwheel", "hitlmwheel", "hitlfwheel", "hitlf2wheel", "hitrbwheel", "hitrmwheel", "hitrlwheel", "hitrfwheel", "hitrf2wheel"], "wheel"]
|
||||||
#define FUEL_HITPOINTS [["hitfuel"], "fuel"]
|
#define FUEL_HITPOINTS [["hitfuel"], "fuel"]
|
||||||
#define ALL_HITPOINTS [ENGINE_HITPOINTS, HULL_HITPOINTS, TRACK_HITPOINTS, WHEEL_HITPOINTS, FUEL_HITPOINTS]
|
#define ALL_HITPOINTS [ENGINE_HITPOINTS, HULL_HITPOINTS, TRACK_HITPOINTS, WHEEL_HITPOINTS, FUEL_HITPOINTS]
|
||||||
|
|
||||||
#define CRITICAL_HITPOINTS ["hithull", 0.89, "hitbody", 0.89, "#structural", 0.89, "hitengine", 0.9]
|
#define CRITICAL_HITPOINTS ["hithull", "hitbody", "#structural", "hitengine"]
|
||||||
|
#define CRITICAL_HITPOINTS_THRESHOLDS [0.89, 0.89, 0.89, 0.9]
|
||||||
|
|
||||||
#define WARHEAD_TYPE_HE 0
|
#define WARHEAD_TYPE_HE 0
|
||||||
#define WARHEAD_TYPE_AP 1
|
#define WARHEAD_TYPE_AP 1
|
||||||
#define WARHEAD_TYPE_HEAT 2
|
#define WARHEAD_TYPE_HEAT 2
|
||||||
#define WARHEAD_TYPE_TANDEM 3
|
#define WARHEAD_TYPE_TANDEM 3
|
||||||
#define WARHEAD_TYPE_NONE 4
|
|
||||||
|
|
||||||
#define EJECT_IF_DESTROYED_VEHICLES ["Boat_Transport_02_base_F", "Rubber_duck_base_F"]
|
#define EJECT_IF_DESTROYED_VEHICLES ["Boat_Transport_02_base_F", "Rubber_duck_base_F"]
|
||||||
|
|
||||||
|
#define CREATE_INCENDIARY_AMMO(ammo,base,inc)\
|
||||||
#define CREATE_INCENDIARY_AMMO(ammo,base,inc) class ammo: base { GVAR(incendiary) = inc; }
|
class ammo: base {\
|
||||||
|
GVAR(incendiary) = inc;\
|
||||||
|
}
|
||||||
|
@ -15,43 +15,33 @@
|
|||||||
<Portuguese>ACE Dano avançãdo de veículos</Portuguese>
|
<Portuguese>ACE Dano avançãdo de veículos</Portuguese>
|
||||||
</Key>
|
</Key>
|
||||||
<Key ID="STR_ACE_Vehicle_Damage_setting_description">
|
<Key ID="STR_ACE_Vehicle_Damage_setting_description">
|
||||||
<English>Enable/Disable advanced vehicle damage</English>
|
<English>Enable advanced vehicle damage</English>
|
||||||
<Japanese>アドバンスドビークルダメージを有効/無効にする</Japanese>
|
|
||||||
<French>Active les dégâts de véhicule avancés.</French>
|
<French>Active les dégâts de véhicule avancés.</French>
|
||||||
<German>Aktiviert/Deaktiviert den Erweiterten Fahrzeugsschaden</German>
|
<German>Aktiviert den Erweiterten Fahrzeugsschaden</German>
|
||||||
<Italian>Abilità danni avanzati ai veicoli</Italian>
|
<Italian>Abilità danni avanzati ai veicoli</Italian>
|
||||||
<Polish>Włącz/Wyłącz zaawansowane uszkodzenia pojazdów</Polish>
|
<Polish>Włącz zaawansowane uszkodzenia pojazdów</Polish>
|
||||||
<Chinesesimp>启用/禁用高级载具损坏</Chinesesimp>
|
<Russian>Включить продвинутое повреждение техники</Russian>
|
||||||
<Korean>고급 차량 피해 활성화/비활성화</Korean>
|
<Spanish>Habilitar el daño avanzado de vehículos</Spanish>
|
||||||
<Russian>Включить/выключить продвинутое повреждение техники</Russian>
|
<Portuguese>Ativar dano avançado de veículo</Portuguese>
|
||||||
<Spanish>Habilitar/Deshabilitar el daño avanzado de vehículos</Spanish>
|
|
||||||
<Portuguese>Ativar/Desativar dano avançado de veículo</Portuguese>
|
|
||||||
</Key>
|
|
||||||
<Key ID="STR_ACE_Vehicle_Damage_carDamage_setting_description">
|
|
||||||
<English>Enable/Disable advanced car damage (Experimental)</English>
|
|
||||||
<Japanese>アドバンスド車ダメージを有効/無効にする (試験的)</Japanese>
|
|
||||||
<French>Active les dégâts avancés sur les voitures (expérimental).</French>
|
|
||||||
<German>Aktiviert/Deaktiviert den Erweiterten Fahrzeugsschaden (Experimentell)</German>
|
|
||||||
<Italian>Abilita danni avanzati ai veicoli (sperimentale)</Italian>
|
|
||||||
<Polish>Włącz/Wyłącz zaawansowane uszkodzenia w samochodach (eksperymentalne)</Polish>
|
|
||||||
<Chinesesimp>启用/禁用高级车辆损坏(实验性)</Chinesesimp>
|
|
||||||
<Korean>고급 차량 피해(실험용) 활성화/비활성화</Korean>
|
|
||||||
<Russian>Включить/выключить продвинутое повреждение машин (экспериментальное)</Russian>
|
|
||||||
<Spanish>Habilita/Deshabilita el daño avanzado de coche (Experimental)</Spanish>
|
|
||||||
<Portuguese>Ativar/Desativar dano avançado de carro (Experimental)</Portuguese>
|
|
||||||
</Key>
|
</Key>
|
||||||
<Key ID="STR_ACE_Vehicle_Damage_carDamage_setting_enable">
|
<Key ID="STR_ACE_Vehicle_Damage_carDamage_setting_enable">
|
||||||
<English>Enable/Disable advanced car damage</English>
|
<English>Enable advanced car damage</English>
|
||||||
<Japanese>アドバンスド車ダメージを有効/無効にする</Japanese>
|
|
||||||
<French>Dégâts de voiture avancés</French>
|
<French>Dégâts de voiture avancés</French>
|
||||||
<German>Aktiviert/Deaktiviert erweiterten Autoschaden</German>
|
<German>Aktiviert erweiterten Autoschaden</German>
|
||||||
<Italian>Abilita danni avanzati alle macchine</Italian>
|
<Italian>Abilita danni avanzati alle macchine</Italian>
|
||||||
<Polish>Włącz/Wyłącz zaawansowane uszkodzenia w samochodach</Polish>
|
<Polish>Włącz zaawansowane uszkodzenia w samochodach</Polish>
|
||||||
<Chinesesimp>启用/禁用高级车辆损坏</Chinesesimp>
|
<Spanish>Habilitar daño avanzado de coche</Spanish>
|
||||||
<Korean>고급 차량 피해 활성화/비활성화</Korean>
|
<Portuguese>Habilitar dano avançado para carros</Portuguese>
|
||||||
<Russian>Продвинутое повреждение машин</Russian>
|
</Key>
|
||||||
<Spanish>Habilitar/Deshabilitar daño avanzado de coche (Experimental)</Spanish>
|
<Key ID="STR_ACE_Vehicle_Damage_carDamage_setting_description">
|
||||||
<Portuguese>Ativar/Desativar dano avançado de carro</Portuguese>
|
<English>Enable advanced car damage (Experimental)</English>
|
||||||
|
<French>Active les dégâts avancés sur les voitures (expérimental).</French>
|
||||||
|
<German>Aktiviert den Erweiterten Fahrzeugsschaden (Experimentell)</German>
|
||||||
|
<Italian>Abilita danni avanzati ai veicoli (sperimentale)</Italian>
|
||||||
|
<Polish>Włącz zaawansowane uszkodzenia w samochodach (eksperymentalne)</Polish>
|
||||||
|
<Russian>Включить продвинутое повреждение машин (экспериментальное)</Russian>
|
||||||
|
<Spanish>Habilitar daño avanzado de coche (Experimental)</Spanish>
|
||||||
|
<Portuguese>Habilitar dano avançado para carros (Experimental)</Portuguese>
|
||||||
</Key>
|
</Key>
|
||||||
<Key ID="STR_ACE_Vehicle_Damage_generic_turret_wreck">
|
<Key ID="STR_ACE_Vehicle_Damage_generic_turret_wreck">
|
||||||
<English>Wreck (Turret)</English>
|
<English>Wreck (Turret)</English>
|
||||||
|
@ -19,7 +19,7 @@ Removes hit-point based damage on armoured vehicles.
|
|||||||
|
|
||||||
### 1.1 Differences from vanilla
|
### 1.1 Differences from vanilla
|
||||||
|
|
||||||
Vehicle damage is component based in this system. Rather than catastrophically exploding when an arbitrary amount of damage is recieved, the system calculates what warhead hit you, if it hit SLAT/ERA, and what components it hits.
|
Vehicle damage is component based in this system. Rather than catastrophically exploding when an arbitrary amount of damage is received, the system calculates what warhead hit you, if it hit SLAT/ERA, and what components it hits.
|
||||||
When you are hit, a calculation takes place and determines which people inside the vehicle should get hurt.
|
When you are hit, a calculation takes place and determines which people inside the vehicle should get hurt.
|
||||||
|
|
||||||
### 1.2 How is damage calculated
|
### 1.2 How is damage calculated
|
||||||
@ -116,20 +116,3 @@ When hit, HEAT warheads will be defeated and no damage will be applied. If hit w
|
|||||||
|
|
||||||
- Can cook-off [N]
|
- Can cook-off [N]
|
||||||
- Can injure occupants [N]
|
- Can injure occupants [N]
|
||||||
|
|
||||||
## 3. Addon Options
|
|
||||||
|
|
||||||
### 3.1 Enable
|
|
||||||
|
|
||||||
- Enables/Disables the vehicle damage simulation
|
|
||||||
- Default: On
|
|
||||||
|
|
||||||
### 3.2 Enable/Disable Ammo Removal During Cook-Off
|
|
||||||
|
|
||||||
- Enables/Disables whether or not vehicle ammo will be fully removed upon cooking-off
|
|
||||||
- Default: On
|
|
||||||
|
|
||||||
### 3.3 Enable/Disable advanced car damage (Experimental)
|
|
||||||
|
|
||||||
- Enable experimental car damage. System will apply vehicle damage simulation to "car" types (trucks, SUVs, Humvees, etc.). Not fully tested and could be immbalanced causing weird behaviours.
|
|
||||||
- Default: Off
|
|
||||||
|
@ -73,7 +73,7 @@ Default: 0
|
|||||||
|
|
||||||
Whether or not this vehicle can spawn a `jet` effect (Boolean value: 0 or 1)
|
Whether or not this vehicle can spawn a `jet` effect (Boolean value: 0 or 1)
|
||||||
|
|
||||||
Default: 0
|
Default: 1
|
||||||
|
|
||||||
#### 1.1.10 `ace_vehicle_damage_slatHitpoints`
|
#### 1.1.10 `ace_vehicle_damage_slatHitpoints`
|
||||||
|
|
||||||
@ -89,9 +89,9 @@ Default: {}
|
|||||||
|
|
||||||
#### 1.1.12 `ace_vehicle_damage_turret`
|
#### 1.1.12 `ace_vehicle_damage_turret`
|
||||||
|
|
||||||
String for turret classname to spawn when catastrophically destroyed. Turret will pop-off and this is the class spawned
|
String for turret classname to spawn when catastrophically destroyed, followed by offset the object should spawn with. Turret will pop-off and this is the class spawned
|
||||||
|
|
||||||
Default: ""
|
Default: {}
|
||||||
|
|
||||||
### 1.2 Defined Hitpoints
|
### 1.2 Defined Hitpoints
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user