diff --git a/addons/cookoff/$PBOPREFIX$ b/addons/cookoff/$PBOPREFIX$ new file mode 100644 index 0000000000..1e1ddfc8d2 --- /dev/null +++ b/addons/cookoff/$PBOPREFIX$ @@ -0,0 +1 @@ +z\ace\addons\cookoff diff --git a/addons/cookoff/CfgCloudlets.hpp b/addons/cookoff/CfgCloudlets.hpp new file mode 100644 index 0000000000..9b262c75c1 --- /dev/null +++ b/addons/cookoff/CfgCloudlets.hpp @@ -0,0 +1,54 @@ + +class CfgCloudlets { + class GVAR(CookOff) { + interval = 0.004; + circleRadius = 0; + circleVelocity[] = {2,2,2}; + particleShape = "\A3\data_f\ParticleEffects\Universal\Universal"; + particleFSNtieth = 16; + particleFSIndex = 0; + particleFSFrameCount = 32; + particleFSLoop = 0; + angle = 0; + angleVar = 0; + animationName = ""; + particleType = "Billboard"; + timerPeriod = 1; + lifeTime = 1; + moveVelocity[] = {0,4,0}; + rotationVelocity = 1; + weight = 0.4; + volume = 0.45; + rubbing = 0; + size[] = {0.01,0.5,1,1,1.5,0.01,0.001}; + color[] = {{1,1,1,-4},{1,1,1,-3},{1,1,1,-2},{1,1,1,-1},{1,1,1,0}}; + animationSpeed[] = {1}; + randomDirectionPeriod = 5; + randomDirectionIntensity = 1; + onTimerScript = ""; + beforeDestroyScript = ""; + position[] = {0,0,0}; + lifeTimeVar = 0; + positionVar[] = {0,0,0}; + positionVarConst[] = {0,0,0}; + moveVelocityVar[] = {1,2,1}; + moveVelocityVarConst[] = {0,0,0}; + rotationVelocityVar = 3; + sizeVar = 0.1; + colorVar[] = {0,0,0,2}; + randomDirectionPeriodVar = 1; + randomDirectionIntensityVar = 2; + colorCoef[] = {1,1,1,1}; + sizeCoef = 1; + animationSpeedCoef = 1; + particleEffects = ""; + postEffects = ""; + onSurface = 1; + surfaceOffset = 0; + keepOnSurface = 0; + bounceOnSurface = 0.6; + bounceOnSurfaceVar = 0; + destroyOnWaterSurface = 0; + destroyOnWaterSurfaceOffset = 0; + }; +}; diff --git a/addons/cookoff/CfgEventHandlers.hpp b/addons/cookoff/CfgEventHandlers.hpp new file mode 100644 index 0000000000..becf395052 --- /dev/null +++ b/addons/cookoff/CfgEventHandlers.hpp @@ -0,0 +1,18 @@ + +class Extended_PreStart_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preStart)); + }; +}; + +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_preInit)); + }; +}; + +class Extended_PostInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_FILE(XEH_postInit)); + }; +}; diff --git a/addons/cookoff/CfgSFX.hpp b/addons/cookoff/CfgSFX.hpp new file mode 100644 index 0000000000..0e10644729 --- /dev/null +++ b/addons/cookoff/CfgSFX.hpp @@ -0,0 +1,9 @@ + +class CfgSFX { + class GVAR(CookOff) { + name = QGVAR(cookoff); + sounds[] = {QGVAR(cookoff)}; + GVAR(cookoff)[] = {PATHTOF(sounds\cookoff.wss),6,1.8,400,1,0,0,0}; + empty[] = {"",0,0,0,0,0,0,0}; + }; +}; diff --git a/addons/cookoff/CfgVehicles.hpp b/addons/cookoff/CfgVehicles.hpp new file mode 100644 index 0000000000..845eb55d94 --- /dev/null +++ b/addons/cookoff/CfgVehicles.hpp @@ -0,0 +1,56 @@ + +class CfgVehicles { + class Sound; + class GVAR(Sound): Sound { + author = ECSTRING(common,ACETeam); + _generalMacro = QGVAR(Sound); + scope = 1; + sound = QGVAR(CookOff); + }; + + class ThingX; + class GVAR(Turret_MBT_01): ThingX { + author = ECSTRING(common,ACETeam); + _generalMacro = QGVAR(TurretDummy); + scope = 1; + model = "\A3\Structures_F\Wrecks\Wreck_Slammer_turret_F.p3d"; + }; + class GVAR(Turret_MBT_02): ThingX { + author = ECSTRING(common,ACETeam); + _generalMacro = QGVAR(TurretDummy); + scope = 1; + model = "\A3\Structures_F\Wrecks\Wreck_T72_turret_F.p3d"; + }; + + class Tank; + class Tank_F: Tank { + GVAR(ammoLocation) = "HitTurret"; + GVAR(cookoffSelections)[] = {"poklop_gunner","poklop_commander"}; + }; + + class MBT_01_base_F: Tank_F { + GVAR(ammoLocation) = "HitHull"; + }; + class APC_Tracked_01_base_F: Tank_F { + GVAR(ammoLocation) = "HitHull"; + }; + + class Car_F; + class Wheeled_APC_F: Car_F { + GVAR(ammoLocation) = "HitTurret"; + GVAR(cookoffSelections)[] = {"poklop_gunner","poklop_commander"}; + + // big explosions for wheeled APCs (same as for tanks) + explosionEffect = "FuelExplosionBig"; + }; + + class B_MBT_01_base_F; + class B_MBT_01_cannon_F: B_MBT_01_base_F { + GVAR(turret)[] = {QGVAR(Turret_MBT_01),{0,-1,0.5}}; + }; + + class O_MBT_02_base_F; + class O_MBT_02_cannon_F: O_MBT_02_base_F { + GVAR(turret)[] = {QGVAR(Turret_MBT_02),{0,-1,0}}; + }; +}; diff --git a/addons/cookoff/XEH_PREP.hpp b/addons/cookoff/XEH_PREP.hpp new file mode 100644 index 0000000000..5b744f9221 --- /dev/null +++ b/addons/cookoff/XEH_PREP.hpp @@ -0,0 +1,6 @@ + +PREP(handleDamage); +PREP(engineFire); +PREP(cookOff); +PREP(blowOffTurret); +PREP(secondaryExplosions); diff --git a/addons/cookoff/XEH_postInit.sqf b/addons/cookoff/XEH_postInit.sqf new file mode 100644 index 0000000000..afcd8e1a05 --- /dev/null +++ b/addons/cookoff/XEH_postInit.sqf @@ -0,0 +1,31 @@ +#include "script_component.hpp" + +[QGVAR(engineFire), FUNC(engineFire)] call CBA_fnc_addEventHandler; +[QGVAR(cookOff), FUNC(cookOff)] call CBA_fnc_addEventHandler; + +// cookoff and burning engine +["Tank", "init", { + (_this select 0) addEventHandler ["HandleDamage", { + ["tank", _this] call FUNC(handleDamage); + }]; +}, nil, nil, true] call CBA_fnc_addClassEventHandler; + +["Wheeled_APC_F", "init", { + (_this select 0) addEventHandler ["HandleDamage", { + ["tank", _this] call FUNC(handleDamage); + }]; +}, nil, nil, true] call CBA_fnc_addClassEventHandler; + +["Car", "init", { + (_this select 0) addEventHandler ["HandleDamage", { + ["car", _this] call FUNC(handleDamage); + }]; +}, nil, ["Wheeled_APC_F"], true] call CBA_fnc_addClassEventHandler; + +// secondary explosions +["AllVehicles", "killed", {(_this select 0) call FUNC(secondaryExplosions)}, nil, ["Man"]] call CBA_fnc_addClassEventHandler; + +// blow off turret effect +["Tank", "killed", {(_this select 0) call FUNC(blowOffTurret)}] call CBA_fnc_addClassEventHandler; + +//Reammobox_F diff --git a/addons/cookoff/XEH_preInit.sqf b/addons/cookoff/XEH_preInit.sqf new file mode 100644 index 0000000000..a7feade1c3 --- /dev/null +++ b/addons/cookoff/XEH_preInit.sqf @@ -0,0 +1,7 @@ +#include "script_component.hpp" + +ADDON = false; + +#include "XEH_PREP.hpp" + +ADDON = true; diff --git a/addons/cookoff/XEH_preStart.sqf b/addons/cookoff/XEH_preStart.sqf new file mode 100644 index 0000000000..022888575e --- /dev/null +++ b/addons/cookoff/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/cookoff/config.cpp b/addons/cookoff/config.cpp new file mode 100644 index 0000000000..8606dfa755 --- /dev/null +++ b/addons/cookoff/config.cpp @@ -0,0 +1,21 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = COMPONENT_NAME; + units[] = {QGVAR(Sound),QGVAR(Turret_MBT_01),QGVAR(Turret_MBT_02)}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"ace_common"}; + author = ECSTRING(common,ACETeam); + authors[] = {"commy2"}; + url = ECSTRING(main,URL); + VERSION_CONFIG; + }; +}; + +#include "CfgEventHandlers.hpp" + +#include "CfgCloudlets.hpp" +#include "CfgSFX.hpp" +#include "CfgVehicles.hpp" diff --git a/addons/cookoff/functions/fnc_blowOffTurret.sqf b/addons/cookoff/functions/fnc_blowOffTurret.sqf new file mode 100644 index 0000000000..1ff505f7ef --- /dev/null +++ b/addons/cookoff/functions/fnc_blowOffTurret.sqf @@ -0,0 +1,33 @@ +/* + * Author: commy2 + * Blow off turret effect. + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * None + * + * Example: + * (vehicle player) call ace_cookoff_fnc_blowOffTurret + * + * Public: No + */ +#include "script_component.hpp" + +// delayed so the object is spawned after the model changes to a wreck +// the sudden change in the model would cause nearby physx objects to get stuck +[{ + params ["_vehicle"]; + + private _config = _vehicle call CBA_fnc_getObjectConfig; + getArray (_config >> QGVAR(turret)) params [["_model", "", [""]], ["_offset", [0,0,0], [[]], 3]]; + + if (_model isEqualTo "") exitWith {}; + + private _position = _vehicle modelToWorld _offset; + private _turret = createVehicle [_model, _position, [], 0, "CAN_COLLIDE"]; + + _turret setVectorUp [random 1, random 1, 1]; + _turret setVelocity [random 7, random 7, 8 + random 5]; +}, _this, 1] call CBA_fnc_waitAndExecute; diff --git a/addons/cookoff/functions/fnc_cookOff.sqf b/addons/cookoff/functions/fnc_cookOff.sqf new file mode 100644 index 0000000000..823b8aadb3 --- /dev/null +++ b/addons/cookoff/functions/fnc_cookOff.sqf @@ -0,0 +1,126 @@ +/* + * Author: KoffeinFlummi, commy2 + * Start a cook-off in the given vehicle. + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * None + * + * Example: + * (vehicle player) call ace_cookoff_fnc_cookOff + * + * Public: No + */ +#include "script_component.hpp" + +params ["_vehicle"]; + +if (_vehicle getVariable [QGVAR(isCookingOff), false]) exitWith {}; +_vehicle setVariable [QGVAR(isCookingOff), true]; + +[QGVAR(cookOff), _vehicle] call CBA_fnc_remoteEvent; + +[{ + params ["_vehicle"]; + + private _config = _vehicle call CBA_fnc_getObjectConfig; + private _positions = getArray (_config >> QGVAR(cookoffSelections)) select {!((_vehicle selectionPosition _x) isEqualTo [0,0,0])}; + + if (_positions isEqualTo []) then { + ACE_LOGWARNING_1("no valid selection for cookoff found. %1", typeOf _vehicle); + _positions pushBack "#noselection"; + }; + + private _turretConfig = [_vehicle, [0]] call CBA_fnc_getTurret; + private _positionBarrelEnd = getText (_turretConfig >> "gunBeg"); + + // smoke out of cannon and hatches + private _smokeBarrel = "#particlesource" createVehicleLocal [0,0,0]; + _smokeBarrel setParticleClass "MediumDestructionSmoke"; + _smokeBarrel attachTo [_vehicle, [0,0,0], _positionBarrelEnd]; + + private _effects = [_smokeBarrel]; + + { + private _position = [0,-2,0]; + + if !(_x isEqualTo "#noselection") then { + _position = _vehicle selectionPosition _x; + }; + + private _smoke = "#particlesource" createVehicleLocal [0,0,0]; + _smoke setParticleClass "ObjectDestructionSmoke1_2Smallx"; + _smoke attachTo [_vehicle, _position]; + + _effects pushBack _smoke; + } forEach _positions; + + [{ + params ["_vehicle", "_effects", "_positions"]; + + // this shit is busy being on fire, can't go driving around all over the place + if (local _vehicle) then { + _vehicle setFuel 0; + }; + + private _light = "#lightpoint" createVehicleLocal [0,0,0]; + _light setLightBrightness 0.7; + _light setLightAmbient [1,0.4,0.15]; + _light setLightColor [1,0.4,0.15]; + _light lightAttachObject [_vehicle, [0,0,4]]; + + _effects pushBack _light; + + // cookoffs + { + private _position = [0,-2,0]; + + if !(_x isEqualTo "#noselection") then { + _position = _vehicle selectionPosition _x; + }; + + private _fire = "#particlesource" createVehicleLocal [0,0,0]; + _fire setParticleClass QGVAR(CookOff); + _fire attachTo [_vehicle, _position]; + + _effects pushBack _fire; + } forEach _positions; + + if (isServer) then { + private _sound = createSoundSource [QGVAR(Sound), position _vehicle, [], 0]; + + _effects pushBack _sound; + }; + + // indicator for the crew - yo, your shit's on fire + private _fnc_FlameEffect = { + params ["_vehicle", "_fnc_FlameEffect", "_counter"]; + + if (_vehicle == cameraOn) then { + [] call BIS_fnc_flamesEffect; + }; + + DEC(_counter); + + if (_counter > 0) then { + [_fnc_FlameEffect, [_vehicle, _fnc_FlameEffect, _counter], 0.4] call CBA_fnc_waitAndExecute + }; + }; + + [_vehicle, _fnc_FlameEffect, 12] call _fnc_FlameEffect; // recursive function + + [{ + params ["_vehicle", "_effects"]; + + { + deleteVehicle _x; + } forEach _effects; + + if (local _vehicle) then { + _vehicle setDamage 1; + }; + }, [_vehicle, _effects], 4 + random 1] call CBA_fnc_waitAndExecute; + }, [_vehicle, _effects, _positions], 3 + random 2] call CBA_fnc_waitAndExecute; +}, _vehicle, 0.5 + random 0.3] call CBA_fnc_waitAndExecute; diff --git a/addons/cookoff/functions/fnc_engineFire.sqf b/addons/cookoff/functions/fnc_engineFire.sqf new file mode 100644 index 0000000000..a79e24eb00 --- /dev/null +++ b/addons/cookoff/functions/fnc_engineFire.sqf @@ -0,0 +1,43 @@ +/* + * Author: KoffeinFlummi, commy2 + * Start fire in engine block of a car. + * + * Arguments: + * 0: Vehicle + * + * Return Value: + * None + * + * Example: + * (vehicle player) call ace_cookoff_fnc_engineFire + * + * Public: No + */ +#include "script_component.hpp" + +params ["_vehicle"]; + +if (_vehicle getVariable [QGVAR(isEngineSmoking), false]) exitWith {}; +_vehicle setVariable [QGVAR(isEngineSmoking), true]; + +[QGVAR(engineFire), _vehicle] call CBA_fnc_remoteEvent; + +private _position = [ + 0, + (boundingBoxReal _vehicle select 1 select 1) - 4, + (boundingBoxReal _vehicle select 0 select 2) + 2 +]; + +private _smoke = "#particlesource" createVehicleLocal [0,0,0]; +_smoke setParticleClass "ObjectDestructionSmoke1_2Smallx"; +_smoke attachTo [_vehicle, _position]; + +[{ + (_this select 0) params ["_vehicle", "_smoke", "_time"]; + + if (!alive _vehicle || {_vehicle getHitPointDamage "HitEngine" < 0.9} || {CBA_missionTime > _time}) then { + deleteVehicle _smoke; + _vehicle setVariable [QGVAR(isEngineSmoking), false]; + [_this select 1] call CBA_fnc_removePerFrameHandler; + }; +}, 5, [_vehicle, _smoke, CBA_missionTime + 240]] call CBA_fnc_addPerFrameHandler; diff --git a/addons/cookoff/functions/fnc_handleDamage.sqf b/addons/cookoff/functions/fnc_handleDamage.sqf new file mode 100644 index 0000000000..f1eb8542d9 --- /dev/null +++ b/addons/cookoff/functions/fnc_handleDamage.sqf @@ -0,0 +1,80 @@ +/* + * Author: KoffeinFlummi, commy2 + * Handles all incoming damage for tanks (including wheeled APCs). + * + * Arguments: + * HandleDamage EH + * + * Return Value: + * Damage to be inflicted. + * + * Example: + * _this call ace_cookoff_fnc_handleDamage + * + * Public: No + */ +#include "script_component.hpp" + +params ["_simulationType", "_thisHandleDamage"]; +_thisHandleDamage params ["_vehicle", "", "_damage", "", "_ammo", "_hitIndex"]; + +// it's already dead, who cares? +if (damage _vehicle >= 1) exitWith {}; + +// get hitpoint name +private _hitpoint = "#structural"; + +if (_hitIndex != -1) then { + _hitpoint = toLower ((getAllHitPointsDamage _vehicle param [0, []]) select _hitIndex); +}; + +// get change in damage +private "_oldDamage"; + +if (_hitpoint isEqualTo "#structural") then { + _oldDamage = damage _vehicle; +} else { + _oldDamage = _vehicle getHitIndex _hitIndex; +}; + +private _newDamage = _damage - _oldDamage; + +// handle different types of vehicles +// note: exitWith only works here, because this is not the main scope of handleDamage +// you cannot use the return value together with exitWith in the main scope, it's a bug +// also, we add this event handler with the addEventHandler SQF command, +// because the config version ignores the return value completely +if (_simulationType == "car") exitWith { + // prevent destruction, let cook-off handle it if necessary + if (_hitpoint in ["hithull", "hitfuel", "#structural"] && {!IS_EXPLOSIVE_AMMO(_ammo)}) then { + _damage min 0.89 + } else { + if (_hitpoint isEqualTo "hitengine" && {_damage > 0.9}) then { + _vehicle call FUNC(engineFire); + }; + _damage + }; +}; + +if (_simulationType == "tank") exitWith { + // determine ammo storage location + private _ammoLocationHitpoint = getText (_vehicle call CBA_fnc_getObjectConfig >> QGVAR(ammoLocation)); + + // ammo was hit, high chance for cook-off + if (_hitpoint == _ammoLocationHitpoint) then { + if (_damage > 0.5 && {random 1 < 0.7}) then { + _vehicle call FUNC(cookOff); + }; + } else { + if (_hitpoint in ["hitbody", "hitturret", "#structural"] && {_newDamage > 0.6 + random 0.3}) then { + _vehicle call FUNC(cookOff); + }; + }; + + // prevent destruction, let cook-off handle it if necessary + if (_hitpoint in ["hithull", "hitfuel", "#structural"]) then { + _damage min 0.89 + } else { + _damage + }; +}; diff --git a/addons/cookoff/functions/fnc_secondaryExplosions.sqf b/addons/cookoff/functions/fnc_secondaryExplosions.sqf new file mode 100644 index 0000000000..01a2fa3b3f --- /dev/null +++ b/addons/cookoff/functions/fnc_secondaryExplosions.sqf @@ -0,0 +1,64 @@ +/* + * Author: Maddmatt, commy2 + * Generate an amount of secondary explosions + * + * Arguments: + * 0: Vehicle + * 1: Amount + * + * Return Value: + * None + * + * Public: No + */ +#include "script_component.hpp" + +#define SECONDARIES_DELAY (1 + random 45) + +params ["_vehicle", "_amount"]; + +if (isNil "_amount") then { + // calculate amount of secondary explosions if not specified + _amount = 0; + + { + _x params ["_magazine", "_count"]; + + private _ammo = getText (_magazine call CBA_fnc_getItemConfig >> "ammo"); + + if (IS_EXPLOSIVE_AMMO(_ammo)) then { + if (_ammo isKindOf "ShellBase") then { + ADD(_amount,_count); + } else { + ADD(_amount,_count/50); + }; + }; + } forEach magazinesAmmo _vehicle; +}; + +if (_amount <= 0) exitWith {}; + +private _fnc_secondaryExplosion = { + params ["_vehicle", "_amount", "_fnc_secondaryExplosion"]; + + private _position = _vehicle modelToWorld (_vehicle selectionPosition "destructionEffect2"); + + // these CfgAmmo objects are always global + "SmallSecondary" createVehicle _position; + + DEC(_amount); + + if (!isNull _vehicle && {_amount > 0}) then { + [_fnc_secondaryExplosion, [_vehicle, _amount, _fnc_secondaryExplosion], SECONDARIES_DELAY] call CBA_fnc_waitAndExecute; + }; +}; + +[_fnc_secondaryExplosion, [_vehicle, _amount, _fnc_secondaryExplosion], SECONDARIES_DELAY] call CBA_fnc_waitAndExecute; + +nil + +/*SencondaryExplosion + SecondaryExp + SecondarySmoke + GrenadeExploLight +*/ diff --git a/addons/cookoff/functions/script_component.hpp b/addons/cookoff/functions/script_component.hpp new file mode 100644 index 0000000000..d72f77978f --- /dev/null +++ b/addons/cookoff/functions/script_component.hpp @@ -0,0 +1 @@ +#include "\z\ace\addons\cookoff\script_component.hpp" diff --git a/addons/cookoff/script_component.hpp b/addons/cookoff/script_component.hpp new file mode 100644 index 0000000000..91afa5df3c --- /dev/null +++ b/addons/cookoff/script_component.hpp @@ -0,0 +1,20 @@ +#define COMPONENT cookoff +#define COMPONENT_BEAUTIFIED Cook off +#include "\z\ace\addons\main\script_mod.hpp" + +// #define DEBUG_MODE_FULL +// #define DISABLE_COMPILE_CACHE +// #define CBA_DEBUG_SYNCHRONOUS +// #define ENABLE_PERFORMANCE_COUNTERS + +#ifdef DEBUG_ENABLED_COOKOFF + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_COOKOFF + #define DEBUG_SETTINGS DEBUG_SETTINGS_COOKOFF +#endif + +#include "\z\ace\addons\main\script_macros.hpp" + +#define IS_EXPLOSIVE_AMMO(ammo) (getNumber (ammo call CBA_fnc_getObjectConfig >> "explosive") > 0.5) diff --git a/addons/cookoff/sounds/cookoff.wss b/addons/cookoff/sounds/cookoff.wss new file mode 100644 index 0000000000..11b9d55194 Binary files /dev/null and b/addons/cookoff/sounds/cookoff.wss differ