diff --git a/addons/houseLightSwitch/$PBOPREFIX$ b/addons/houseLightSwitch/$PBOPREFIX$ new file mode 100644 index 0000000..cbb9216 --- /dev/null +++ b/addons/houseLightSwitch/$PBOPREFIX$ @@ -0,0 +1 @@ +x\grad\addons\houseLightSwitch diff --git a/addons/houseLightSwitch/CfgEventHandlers.hpp b/addons/houseLightSwitch/CfgEventHandlers.hpp new file mode 100644 index 0000000..0d3301d --- /dev/null +++ b/addons/houseLightSwitch/CfgEventHandlers.hpp @@ -0,0 +1,17 @@ +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/houseLightSwitch/CfgVehicles.hpp b/addons/houseLightSwitch/CfgVehicles.hpp new file mode 100644 index 0000000..b15bcec --- /dev/null +++ b/addons/houseLightSwitch/CfgVehicles.hpp @@ -0,0 +1,16 @@ +class CfgVehicles { + class Man; + class CAManBase: Man { + class ACE_SelfActions { + class ACE_Equipment { + class GRAD_houseLightSwitch_fusebox { + displayName = "Locate fuse box"; + condition = QUOTE(call FUNC(condition_fusebox)); + exceptions[] = {}; + statement = QUOTE(call FUNC(action_fusebox)); + icon = "\x\grad\addons\houseLightSwitch\ui\bulb-question.paa"; + }; + }; + }; + }; +}; diff --git a/addons/houseLightSwitch/README.md b/addons/houseLightSwitch/README.md new file mode 100644 index 0000000..2f4fbc6 --- /dev/null +++ b/addons/houseLightSwitch/README.md @@ -0,0 +1,9 @@ +### houseLightSwitch + +ACE self interact menu to switch all lights in a house. Requires player to be in and reasonably close to the house center. + +To test, move into a house that has lights - for example "Land_House_C_3_EP1" or "Land_House_C_9_EP1". Terrains containing these buildings are Zargabad or Uzbin_Valley . Be close to the center of the house. Self interact should now contain a "switch house lights off" entry. + +#### Maintainer(s) + +* Fusselwurm diff --git a/addons/houseLightSwitch/XEH_PREP.hpp b/addons/houseLightSwitch/XEH_PREP.hpp new file mode 100644 index 0000000..eda0c71 --- /dev/null +++ b/addons/houseLightSwitch/XEH_PREP.hpp @@ -0,0 +1,9 @@ +PREP(action_fusebox); +PREP(createFuseboxActions); +PREP(condition); +PREP(condition_fusebox); +PREP(condition_off); +PREP(condition_on); +PREP(ensureFuseboxHelper); +PREP(fadeFuseboxHelper); +PREP(server_setBuildingMainSwitch); diff --git a/addons/houseLightSwitch/XEH_postInit.sqf b/addons/houseLightSwitch/XEH_postInit.sqf new file mode 100644 index 0000000..24075fd --- /dev/null +++ b/addons/houseLightSwitch/XEH_postInit.sqf @@ -0,0 +1,5 @@ +#include "script_component.hpp" + +if (isServer) then { + [QGVAR(setBuildingMainSwitch),FUNC(server_setBuildingMainSwitch)] call CBA_fnc_addEventHandler; +}; diff --git a/addons/houseLightSwitch/XEH_preInit.sqf b/addons/houseLightSwitch/XEH_preInit.sqf new file mode 100644 index 0000000..b47cf66 --- /dev/null +++ b/addons/houseLightSwitch/XEH_preInit.sqf @@ -0,0 +1,9 @@ +#include "script_component.hpp" + +ADDON = false; + +PREP_RECOMPILE_START; +#include "XEH_PREP.hpp" +PREP_RECOMPILE_END; + +ADDON = true; diff --git a/addons/houseLightSwitch/XEH_preStart.sqf b/addons/houseLightSwitch/XEH_preStart.sqf new file mode 100644 index 0000000..0228885 --- /dev/null +++ b/addons/houseLightSwitch/XEH_preStart.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +#include "XEH_PREP.hpp" diff --git a/addons/houseLightSwitch/config.cpp b/addons/houseLightSwitch/config.cpp new file mode 100644 index 0000000..92740c1 --- /dev/null +++ b/addons/houseLightSwitch/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + author = "$STR_grad_Author"; + name = QUOTE(ADDON); + url = "$STR_grad_URL"; + requiredVersion = 1.0; + requiredAddons[] = {"grad_main", "ace_interact_menu"}; + units[] = {}; + weapons[] = {}; + VERSION_CONFIG; + authors[] = {"Fusselwurm"}; + }; +}; + +#include "CfgVehicles.hpp" +#include "CfgEventHandlers.hpp" diff --git a/addons/houseLightSwitch/functions/fnc_action_fusebox.sqf b/addons/houseLightSwitch/functions/fnc_action_fusebox.sqf new file mode 100644 index 0000000..231d6d3 --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_action_fusebox.sqf @@ -0,0 +1,23 @@ +#include "script_component.hpp" + +private _building = GVAR(house); +private _hasFuseboxActions = _building getVariable [QGVAR(hasFuseboxActions), false]; + +if (_hasFuseboxActions) exitWith { + [_building] call FUNC(ensureFuseboxHelper); +}; + +[ + ACE_player distance _building, + [_building], + { + params ["_args"]; + _args params ["_building"]; + assert(!isNull(_building)); + hint "Found the fuse box. Look for a bright helper object!"; + [_building] call FUNC(ensureFuseboxHelper); + [_building] call FUNC(createFuseboxActions); + }, + {hint "Failure"}, + "Searching fuse box..." +] call ace_common_fnc_progressBar; diff --git a/addons/houseLightSwitch/functions/fnc_condition.sqf b/addons/houseLightSwitch/functions/fnc_condition.sqf new file mode 100644 index 0000000..c9f0c7a --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_condition.sqf @@ -0,0 +1,13 @@ +#include "script_component.hpp" + +private _cursorTarget = cursorTarget; + +private _isUnderSomething = lineIntersectsObjs [getposASL ace_player, getposASL ace_player vectorAdd [0, 0, 20]] isNotEqualTo []; +private _pointsAtHouse = _cursorTarget isKindOf "House" || {_cursorTarget isKindOf "Building"}; + +if (_pointsAtHouse && {_isUnderSomething}) then { + GVAR(house) = _cursorTarget; + true +} else { + false +}; diff --git a/addons/houseLightSwitch/functions/fnc_condition_fusebox.sqf b/addons/houseLightSwitch/functions/fnc_condition_fusebox.sqf new file mode 100644 index 0000000..11bb8de --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_condition_fusebox.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +call FUNC(condition) diff --git a/addons/houseLightSwitch/functions/fnc_condition_off.sqf b/addons/houseLightSwitch/functions/fnc_condition_off.sqf new file mode 100644 index 0000000..8a3f51d --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_condition_off.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +[] call FUNC(condition) && {GVAR(house) getVariable [QGVAR(mainSwitchState), true] isEqualTo true}; diff --git a/addons/houseLightSwitch/functions/fnc_condition_on.sqf b/addons/houseLightSwitch/functions/fnc_condition_on.sqf new file mode 100644 index 0000000..c500864 --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_condition_on.sqf @@ -0,0 +1,3 @@ +#include "script_component.hpp" + +[] call FUNC(condition) && {GVAR(house) getVariable [QGVAR(mainSwitchState), true] isEqualTo false}; diff --git a/addons/houseLightSwitch/functions/fnc_createFuseboxActions.sqf b/addons/houseLightSwitch/functions/fnc_createFuseboxActions.sqf new file mode 100644 index 0000000..77f9171 --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_createFuseboxActions.sqf @@ -0,0 +1,44 @@ +#include "script_component.hpp" + +params [ + ["_building", objNull, [objNull]] +]; + +assert(!(isNull _building)); + +if (_building getVariable [QGVAR(hasFuseboxActions), false]) exitWith { + WARNING_1("fusebox actions already added for %1", _building); +}; +_building setVariable [QGVAR(hasFuseboxActions), true]; + +private _onAction = [ + QGVAR(on), + "Turn on house lights", + "x\grad\addons\houseLightSwitch\ui\bulb-on.paa", + { + params ["", "", "_args"]; + _args params [["_building", objNull, [objNull]]]; + [QGVAR(setBuildingMainSwitch), [GVAR(house), true]] call CBA_fnc_serverEvent; + [_building] call FUNC(fadeFuseboxHelper); + }, + {call FUNC(condition_on)}, + {[]}, + [_building] +] call ace_interact_menu_fnc_createAction; +[_building, 0, [], _onAction] call ace_interact_menu_fnc_addActionToObject; + +private _offAction = [ + QGVAR(off), + "Turn off house lights", + "\x\grad\addons\houseLightSwitch\ui\bulb-off.paa", + { + params ["", "", "_args"]; + _args params [["_building", objNull, [objNull]]]; + [QGVAR(setBuildingMainSwitch), [GVAR(house), false]] call CBA_fnc_serverEvent; + [_building] call FUNC(fadeFuseboxHelper); + }, + {call FUNC(condition_off)}, + {[]}, + [_building] +] call ace_interact_menu_fnc_createAction; +[_building, 0, [], _offAction] call ace_interact_menu_fnc_addActionToObject; diff --git a/addons/houseLightSwitch/functions/fnc_ensureFuseboxHelper.sqf b/addons/houseLightSwitch/functions/fnc_ensureFuseboxHelper.sqf new file mode 100644 index 0000000..46c1a86 --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_ensureFuseboxHelper.sqf @@ -0,0 +1,21 @@ +#include "script_component.hpp" + +params [ + ["_building", objNull, [objNull]] +]; +assert(!(isNull _building)); + +private _helper = _building getVariable [QGVAR(fuseboxHelper), objNull]; +if (_helper isNotEqualTo objNull) exitWith { + TRACE_1("helper for %1 exists already!", _building); +}; + +private _helperPos = _building modelToWorld [0, 0, 0]; +TRACE_2("creating helper for building %1 at %2", _building, _helperPos); + +// NOTE: cannot use createSimpleObject, as these cannot hold ACE actions +// NOTE: createVehicleLocal will avoid collisions! hence setpos later +_helper = "Sign_Sphere25cm_F" createVehicleLocal [0, 0, 0]; +_helper setPos _helperPos; + +_building setVariable [QGVAR(fuseboxHelper), _helper]; diff --git a/addons/houseLightSwitch/functions/fnc_fadeFuseboxHelper.sqf b/addons/houseLightSwitch/functions/fnc_fadeFuseboxHelper.sqf new file mode 100644 index 0000000..4cc9f7a --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_fadeFuseboxHelper.sqf @@ -0,0 +1,42 @@ +#include "script_component.hpp" + +params [ + ["_building", objNull, [objNull]] +]; +assert(!(isNull _building)); + +private _helper = _building getVariable [QGVAR(fuseboxHelper), objNull]; +private _existingOpacity = _helper getVariable [QGVAR(opaqueness), -1]; +if (_existingOpacity != -1) exitWith { + WARNING_1("helper already has non-default opacity %1 , will not add another handler", _existingOpacity); +}; +_helper setVariable [QGVAR(opaqueness), 1]; + +[ + { + params [ + ["_args", [], [[]]], + ["_handle", 0, [0]] + ]; + _args params [ + ["_building", objNull, [objNull]] + ]; + assert(!(isNull _building)); + private _helper = _building getVariable [QGVAR(fuseboxHelper), objNull]; + private _opaqueness = _helper getVariable [QGVAR(opaqueness), 0]; + _helper setVariable [QGVAR(opaqueness), _opaqueness - 0.05]; + if (isNull _helper) exitWith { + [_handle] call CBA_fnc_removePerFrameHandler; + _building setVariable [QGVAR(fuseboxHelper), nil]; + WARNING_1("null helper in loop for building %1!", _building); + }; + if (_opaqueness <= 0) exitWith { + [_handle] call CBA_fnc_removePerFrameHandler; + _building setVariable [QGVAR(fuseboxHelper), nil]; + deleteVehicle _helper; + }; + _helper setObjectTexture [0, format ["#(argb,8,8,3)color(1,0.6,0.1,%1,ca)", _opaqueness]]; + }, + 0.1, + [_building] +] call CBA_fnc_addPerFrameHandler; diff --git a/addons/houseLightSwitch/functions/fnc_server_setBuildingMainSwitch.sqf b/addons/houseLightSwitch/functions/fnc_server_setBuildingMainSwitch.sqf new file mode 100644 index 0000000..c9f69ca --- /dev/null +++ b/addons/houseLightSwitch/functions/fnc_server_setBuildingMainSwitch.sqf @@ -0,0 +1,35 @@ +#include "script_component.hpp" +// assumption: any damage to a light source should be enough to kill it. +// therefore, I can use a magic damage (< 1) to mark as light as "switched off" as opposed to "destroyed" +#define MAGIC_DAMAGE_LIGHT_OFF 0.9 + +params [ + ["_building", objNull, [objNull]], + ["_newState", false, [false]] +]; + +assert(isServer); // terrain objects are local *everywhere*. therefore, force server to have a single point of truth. + +private _isOn = _building getVariable [QGVAR(mainSwitchState), true]; +if (_newState isEqualTo _isOn) exitWith { + TRACE_2("someone tried to switch lights on building %1 to pre-existing state %2", _building, _newState); +}; +_building setVariable [QGVAR(mainSwitchState), _newState, true]; + +private _existingDmg = getAllHitPointsDamage _building; + +{ + if (_x find "#" == 0) then { // assume indices starting with "#" to be lights + private _prevLightDmg = (_existingDmg#2#_forEachIndex); + // using setHitIndex over setHitPointDamage as there are buildings - looking at you, Land_House_C_2_EP1 - where hitpointnames are not unique + _building setHitIndex [ + _forEachIndex, + if (_newState) then { + if (_prevLightDmg isEqualTo MAGIC_DAMAGE_LIGHT_OFF) then {0} else {_prevLightDmg} + } else { + _prevLightDmg max MAGIC_DAMAGE_LIGHT_OFF + }, + false + ]; + }; +} forEach _existingDmg#0; diff --git a/addons/houseLightSwitch/functions/script_component.hpp b/addons/houseLightSwitch/functions/script_component.hpp new file mode 100644 index 0000000..fcf9da9 --- /dev/null +++ b/addons/houseLightSwitch/functions/script_component.hpp @@ -0,0 +1 @@ +#include "..\script_component.hpp" diff --git a/addons/houseLightSwitch/script_component.hpp b/addons/houseLightSwitch/script_component.hpp new file mode 100644 index 0000000..002916c --- /dev/null +++ b/addons/houseLightSwitch/script_component.hpp @@ -0,0 +1,4 @@ +#define COMPONENT houseLightSwitch + +#include "\x\grad\addons\main\script_mod.hpp" +#include "\x\grad\addons\main\script_macros.hpp" diff --git a/addons/houseLightSwitch/ui/bulb-off.paa b/addons/houseLightSwitch/ui/bulb-off.paa new file mode 100644 index 0000000..407331c Binary files /dev/null and b/addons/houseLightSwitch/ui/bulb-off.paa differ diff --git a/addons/houseLightSwitch/ui/bulb-on.paa b/addons/houseLightSwitch/ui/bulb-on.paa new file mode 100644 index 0000000..09e35ab Binary files /dev/null and b/addons/houseLightSwitch/ui/bulb-on.paa differ diff --git a/addons/houseLightSwitch/ui/bulb-question.paa b/addons/houseLightSwitch/ui/bulb-question.paa new file mode 100644 index 0000000..415e87e Binary files /dev/null and b/addons/houseLightSwitch/ui/bulb-question.paa differ