diff --git a/addons/main/config.cpp b/addons/main/config.cpp index f753e1b55..bc04591e6 100644 --- a/addons/main/config.cpp +++ b/addons/main/config.cpp @@ -31,7 +31,8 @@ class CfgPatches { "cba_ui", "cba_versioning", "cba_optics", - "cba_disposable" + "cba_disposable", + "cba_quicktime" }; author = "$STR_CBA_Author"; authors[] = {}; diff --git a/addons/quicktime/$PBOPREFIX$ b/addons/quicktime/$PBOPREFIX$ new file mode 100644 index 000000000..d8afc5cdf --- /dev/null +++ b/addons/quicktime/$PBOPREFIX$ @@ -0,0 +1 @@ +x\cba\addons\quicktime diff --git a/addons/quicktime/CfgEventHandlers.hpp b/addons/quicktime/CfgEventHandlers.hpp new file mode 100644 index 000000000..d863ae661 --- /dev/null +++ b/addons/quicktime/CfgEventHandlers.hpp @@ -0,0 +1,6 @@ +class Extended_PreInit_EventHandlers { + class ADDON { + init = QUOTE(call COMPILE_SCRIPT(XEH_preInit)); + }; +}; + diff --git a/addons/quicktime/CfgFunctions.hpp b/addons/quicktime/CfgFunctions.hpp new file mode 100644 index 000000000..6e3f0ca67 --- /dev/null +++ b/addons/quicktime/CfgFunctions.hpp @@ -0,0 +1,10 @@ +class CfgFunctions { + class CBA { + class QuickTimeEvent { + PATHTO_FNC(generateQTESequence); + PATHTO_FNC(getFormattedQTESequence); + PATHTO_FNC(keyPressedQTE); + PATHTO_FNC(runQTE); + }; + }; +}; diff --git a/addons/quicktime/XEH_preInit.sqf b/addons/quicktime/XEH_preInit.sqf new file mode 100644 index 000000000..028c6737d --- /dev/null +++ b/addons/quicktime/XEH_preInit.sqf @@ -0,0 +1,26 @@ +#include "script_component.hpp" +#include "\a3\ui_f\hpp\defineDIKCodes.inc" + +SCRIPT(XEH_preInit); + +ADDON = false; + +#include "initSettings.inc.sqf" + +[LSTRING(QTEKeybindGroup), QGVAR(qteUpKey), ["↑", LSTRING(QTEKeybindUpTooltip)], { + ["↑"] call CBA_fnc_keyPressedQTE // return +}, {}, [DIK_UP, [false, true, false]]] call CBA_fnc_addKeybind; + +[LSTRING(QTEKeybindGroup), QGVAR(qteDownKey), ["↓", LSTRING(QTEKeybindDownTooltip)], { + ["↓"] call CBA_fnc_keyPressedQTE // return +}, {}, [DIK_DOWN, [false, true, false]]] call CBA_fnc_addKeybind; + +[LSTRING(QTEKeybindGroup), QGVAR(qteLeftKey), ["←", LSTRING(QTEKeybindLeftTooltip)], { + ["←"] call CBA_fnc_keyPressedQTE // return +}, {}, [DIK_LEFT, [false, true, false]]] call CBA_fnc_addKeybind; + +[LSTRING(QTEKeybindGroup), QGVAR(qteRightKey), ["→", LSTRING(QTEKeybindRightTooltip)], { + ["→"] call CBA_fnc_keyPressedQTE // return +}, {}, [DIK_RIGHT, [false, true, false]]] call CBA_fnc_addKeybind; + +ADDON = true; diff --git a/addons/quicktime/config.cpp b/addons/quicktime/config.cpp new file mode 100644 index 000000000..2c732eb0a --- /dev/null +++ b/addons/quicktime/config.cpp @@ -0,0 +1,18 @@ +#include "script_component.hpp" + +class CfgPatches { + class ADDON { + name = CSTRING(component); + units[] = {}; + weapons[] = {}; + requiredVersion = REQUIRED_VERSION; + requiredAddons[] = {"cba_common","cba_events"}; + author = "$STR_CBA_Author"; + authors[] = {"john681611"}; + url = "$STR_CBA_URL"; + VERSION_CONFIG; + }; +}; + +#include "CfgFunctions.hpp" +#include "CfgEventHandlers.hpp" diff --git a/addons/quicktime/fnc_generateQTESequence.sqf b/addons/quicktime/fnc_generateQTESequence.sqf new file mode 100644 index 000000000..31a92e80e --- /dev/null +++ b/addons/quicktime/fnc_generateQTESequence.sqf @@ -0,0 +1,31 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_generateQTESequence + +Description: + Generate a Quick-Time sequence of a given length. + +Parameters: + _length - Length of QTE sequence + +Example: + [5] call CBA_fnc_generateQTESequence; + +Returns: + Quick-Time sequence of requested length made up of ["↑", "↓", "→", "←"] + +Author: + john681611 +---------------------------------------------------------------------------- */ + +params [["_length", 0, [0]]]; + +if (_length <= 0) exitWith {[]}; + +private _code = []; + +for "_i" from 0 to _length do { + _code pushBack (selectRandom ["↑", "↓", "→", "←"]); +}; + +_code diff --git a/addons/quicktime/fnc_getFormattedQTESequence.sqf b/addons/quicktime/fnc_getFormattedQTESequence.sqf new file mode 100644 index 000000000..a7b88419e --- /dev/null +++ b/addons/quicktime/fnc_getFormattedQTESequence.sqf @@ -0,0 +1,24 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_getFormattedQTESequence + +Description: + Formats Quick-Time sequence into a displayable string. + +Parameters: + _code - Quick-Time sequence + + +Example: + [["↑", "↓", "→", "←"]] call CBA_fnc_getFormattedQTESequence; + +Returns: + Formatted Quick-Time sequence + +Author: + john681611 +---------------------------------------------------------------------------- */ + +params ["_code"]; + +_code joinString " " // Arma doesn't know how to space ↑ so we need loads of spaces between diff --git a/addons/quicktime/fnc_keyPressedQTE.sqf b/addons/quicktime/fnc_keyPressedQTE.sqf new file mode 100644 index 000000000..b9f041823 --- /dev/null +++ b/addons/quicktime/fnc_keyPressedQTE.sqf @@ -0,0 +1,62 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_keyPressedQTE + +Description: + Process Quick-Time Key Press + +Parameters: + _eventQTE - Character to test against Quick-Time Event + +Example: + ["↑"] call CBA_fnc_keyPressedQTE; + +Returns: + True if QTE is running + +Author: + john681611 +---------------------------------------------------------------------------- */ + + +params ["_eventQTE"]; + +if !(missionNamespace getVariable [QGVAR(QTERunning), false]) exitWith { + false +}; + + +private _args = GVAR(QTEArgs) get "args"; +private _qteSequence = GVAR(QTEArgs) get "qteSequence"; +private _elapsedTime = CBA_missionTime - (GVAR(QTEArgs) get "startTime"); + +GVAR(QTEHistory) pushBack _eventQTE; + +// Check if the input corresponds to the sequence +if (GVAR(QTEHistory) isEqualTo _qteSequence) exitWith { + GVAR(QTEHistory) = []; + GVAR(QTERunning) = false; + TRACE_1("QTE Completed",_elapsedTime); + private _onFinish = GVAR(QTEArgs) get "onFinish"; + if (_onFinish isEqualType "") then { + [_onFinish, [_args, _elapsedTime, GVAR(QTEResetCount)]] call CBA_fnc_localEvent; + } else { + [_args, _elapsedTime, GVAR(QTEResetCount)] call _onFinish; + }; + true +}; + +// If the user failed an input, wipe the previous input from memory +if (GVAR(QTEHistory) isNotEqualTo (_qteSequence select [0, count GVAR(QTEHistory)])) then { + GVAR(QTEHistory) = []; + GVAR(QTEResetCount) = GVAR(QTEResetCount) + 1; +}; + +private _onDisplay = GVAR(QTEArgs) get "onDisplay"; +if (_onDisplay isEqualType "") then { + [_onDisplay, [_args, _qteSequence, GVAR(QTEHistory), GVAR(QTEResetCount)]] call CBA_fnc_localEvent; +} else { + [_args, _qteSequence, GVAR(QTEHistory), GVAR(QTEResetCount)] call _onDisplay; +}; + +true diff --git a/addons/quicktime/fnc_runQTE.sqf b/addons/quicktime/fnc_runQTE.sqf new file mode 100644 index 000000000..1a51c6356 --- /dev/null +++ b/addons/quicktime/fnc_runQTE.sqf @@ -0,0 +1,108 @@ +#include "script_component.hpp" +/* ---------------------------------------------------------------------------- +Function: CBA_fnc_runQTE + +Description: + Runs a Quick-Time Event. + +Parameters: + _args - Extra arguments passed to the _on... functions + _failCondition - Code condition to fail the Quick-Time Event passed [_args, _elapsedTime, _resetCount]. (default: {false}) + _onDisplay - Code callback on displayable event passed [_args, _qteSequence, _qteHistory, _resetCount]. + _onFinish - Code callback on Quick-Time Event completed passed [_args, _elapsedTime, _resetCount]. + _onFail - Code callback on Quick-Time Event timeout/outranged passed [_args, _elapsedTime, _resetCount]. + _qteSequence - Quick-Time sequence made up of ["↑", "↓", "→", "←"] + +Example: + [car, + { + params ["_args", "_elapsedTime", "_resetCount"]; + player distance _args > 10 || _elapsedTime > 10 || _resetCount > 3; + }, + { + params ["_args", "_qteSequence", "_qteHistory", "_resetCount"]; + hint format [ + "%3/3 \n %1 \n %2", + [_qteSequence] call CBA_fnc_getFormattedQTESequence, + [_qteHistory] call CBA_fnc_getFormattedQTESequence, + _resetCount + ] + }, + { + params ["_args", "_elapsedTime", "_resetCount"]; + hint format ["Finished! %1s %2", _elapsedTime, _resetCount]; + }, + { + params ["_args", "_elapsedTime", "_resetCount"]; + hint format ["Failure! %1s %2", _elapsedTime, _resetCount]; + }, + ["↑", "↓", "→", "←"]] call CBA_fnc_runQTE + +Returns: + True if the QTE was started, false if it was already running + +Author: + john681611 +---------------------------------------------------------------------------- */ +if (missionNamespace getVariable [QGVAR(QTERunning), false]) exitWith { + false +}; + +params [ + "_args", + ["_failCondition",{false}, ["", {}]], + ["_onDisplay",{}, ["", {}]], + ["_onFinish",{}, ["", {}]], + ["_onFail",{}, ["", {}]], + ["_qteSequence", [], [[]]] +]; + +GVAR(QTEHistory) = []; +GVAR(QTEResetCount) = 0; +GVAR(QTERunning) = true; +private _startTime = CBA_missionTime; +if(GVAR(qteShorten)) then { + _qteSequence = _qteSequence select [0, 1]; +}; +private _qteArgsArray = [ + ["args", _args], + ["failCondition", _failCondition], + ["onDisplay", _onDisplay], + ["onFinish", _onFinish], + ["onFail", _onFail], + ["maxDistance", _maxDistance], + ["qteSequence", _qteSequence], + ["startTime", _startTime] +]; +GVAR(QTEArgs) = createHashMapFromArray _qteArgsArray; + +// Setup +[{ + private _args = GVAR(QTEArgs) get "args"; + private _failCondition = GVAR(QTEArgs) get "failCondition"; + private _elapsedTime = CBA_missionTime - (GVAR(QTEArgs) get "startTime"); + + !GVAR(QTERunning) || [_args, _elapsedTime, GVAR(QTEResetCount)] call _failCondition; +}, { + TRACE_1("QTE ended",GVAR(QTERunning)); + if(!GVAR(QTERunning)) exitWith {}; + GVAR(QTERunning) = false; + GVAR(QTEHistory) = []; + private _onFail = GVAR(QTEArgs) get "onFail"; + private _args = GVAR(QTEArgs) get "args"; + private _elapsedTime = CBA_missionTime - (GVAR(QTEArgs) get "startTime"); + TRACE_1("QTE Failed",_args); + if (_onFail isEqualType "") then { + [_onFail, [_args, _elapsedTime, GVAR(QTEResetCount)]] call CBA_fnc_localEvent; + } else { + [_args, _elapsedTime, GVAR(QTEResetCount)] call _onFail; + }; +}, []] call CBA_fnc_waitUntilAndExecute; + +if (_onDisplay isEqualType "") then { + [_onDisplay, [_args, _qteSequence, [], GVAR(QTEResetCount)]] call CBA_fnc_localEvent; +} else { + [_args, _qteSequence, [], GVAR(QTEResetCount)] call _onDisplay; +}; + +true diff --git a/addons/quicktime/initSettings.inc.sqf b/addons/quicktime/initSettings.inc.sqf new file mode 100644 index 000000000..6d1826811 --- /dev/null +++ b/addons/quicktime/initSettings.inc.sqf @@ -0,0 +1,9 @@ +[ + QGVAR(qteShorten), + "CHECKBOX", + [LLSTRING(QTEAccessabilitySingleKey), LLSTRING(QTEAccessabilitySingleKeyTooltip)], + [LELSTRING(main,DisplayName), LLSTRING(QTETitle)], + false, // default value + 0 // isGlobal +] call CBA_fnc_addSetting; + diff --git a/addons/quicktime/script_component.hpp b/addons/quicktime/script_component.hpp new file mode 100644 index 000000000..50e9e57e9 --- /dev/null +++ b/addons/quicktime/script_component.hpp @@ -0,0 +1,20 @@ +#define COMPONENT quicktime +#include "\x\cba\addons\main\script_mod.hpp" + +//#define DEBUG_MODE_FULL +//#define DISABLE_COMPILE_CACHE +//#define DEBUG_ENABLED_quicktime + +#ifdef DEBUG_ENABLED_QUICKTIME + #define DEBUG_MODE_FULL +#endif + +#ifdef DEBUG_SETTINGS_QUICKTIME + #define DEBUG_SETTINGS DEBUG_SETTINGS_QUICKTIME +#endif + +#define DEBUG_SYNCHRONOUS +#include "\x\cba\addons\main\script_macros.hpp" + +#include "\a3\ui_f\hpp\defineResincl.inc" + diff --git a/addons/quicktime/stringtable.xml b/addons/quicktime/stringtable.xml new file mode 100644 index 000000000..e784c5489 --- /dev/null +++ b/addons/quicktime/stringtable.xml @@ -0,0 +1,29 @@ + + + + + Quick-Time Events + + + CBA Quick-Time Events + + + Up key used in Quick-Time Events. + + + Down key used in Quick-Time Events. + + + Left key used in Quick-Time Events. + + + Right key used in Quick-Time Events. + + + Single Key press + + + When enabled, all Quick-Time Events will be shortened to a single key press. + + +