Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added: QTE Framework #1649

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ea657b5
Added: QTE Framework
john681611 Mar 19, 2024
964cefe
Update addons/common/fnc_generateQTESequence.sqf
john681611 Mar 21, 2024
45929cd
refactor to use Keybinds
john681611 Mar 23, 2024
bfa6ea8
Merge branch 'quickTimeEvents' of github.com:john681611/CBA_A3 into q…
john681611 Mar 23, 2024
3576e8e
Fix null issue on key press
john681611 Mar 23, 2024
dbc5abe
review improvements
john681611 Mar 23, 2024
d35bfb8
Support localization
john681611 Mar 23, 2024
986d828
Update addons/common/XEH_preInit.sqf
john681611 Mar 26, 2024
26529cc
Update addons/common/fnc_generateQTESequence.sqf
john681611 Mar 26, 2024
5255969
Update addons/common/fnc_keyPressedQTE.sqf
john681611 Mar 26, 2024
96806a9
Update addons/common/fnc_runQTE.sqf
john681611 Mar 26, 2024
6597fc8
Update addons/common/stringtable.xml
john681611 Mar 26, 2024
9feffc8
Update addons/common/fnc_keyPressedQTE.sqf
john681611 Mar 26, 2024
c851040
Update addons/common/fnc_keyPressedQTE.sqf
john681611 Mar 26, 2024
68c586b
Update addons/common/fnc_keyPressedQTE.sqf
john681611 Mar 26, 2024
f48ebaa
review comments
john681611 Mar 26, 2024
d99bb4f
minor improvements
john681611 Mar 27, 2024
97fc243
Update addons/common/fnc_keyPressedQTE.sqf
john681611 Mar 27, 2024
29f9f11
Update addons/common/fnc_runQTE.sqf
john681611 Mar 27, 2024
1fbb063
Update addons/common/fnc_runQTE.sqf
john681611 Apr 2, 2024
c8e951b
Update addons/common/fnc_runQTE.sqf
john681611 Apr 2, 2024
24bf821
Update addons/common/fnc_runQTE.sqf
john681611 Apr 2, 2024
9eb7b18
format: camelcasing
john681611 Apr 30, 2024
7dc983f
Merge branch 'quickTimeEvents' of github.com:john681611/CBA_A3 into q…
john681611 Apr 30, 2024
a22d373
Update addons/common/XEH_preInit.sqf
john681611 Apr 30, 2024
9a6cfb2
migrate to quicktime component
john681611 Apr 30, 2024
976eca3
Merge branch 'quickTimeEvents' of github.com:john681611/CBA_A3 into q…
john681611 Apr 30, 2024
6d2f3fe
minor fixes
john681611 Apr 30, 2024
6024704
Fix sneaky keybind error
john681611 Apr 30, 2024
8e236f2
Review comment improvements
john681611 May 5, 2024
83ca39f
Use more generic condition and reset counter
john681611 May 5, 2024
46d200d
Update addons/quicktime/fnc_runQTE.sqf
john681611 Jun 24, 2024
91e2722
Implement Single Key press as Accessability option
john681611 Dec 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions addons/common/CfgFunctions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,12 @@ class CfgFunctions {
class Broken {
PATHTO_FNC(actionArgument);
};

class QuickTimeEvent {
PATHTO_FNC(generateQTESequence);
PATHTO_FNC(getFormattedQTESequence);
PATHTO_FNC(runQTE);
PATHTO_FNC(keyPressedQTE);
};
};
};
17 changes: 17 additions & 0 deletions addons/common/XEH_preInit.sqf
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//#define DEBUG_MODE_FULL
#include "script_component.hpp"
#include "\a3\ui_f\hpp\defineDIKCodes.inc"
SCRIPT(XEH_preInit);

LOG(MSG_INIT);
Expand Down Expand Up @@ -78,3 +79,19 @@ activateAddons GVAR(addons);
["CAManBase", "InitPost", CBA_fnc_randomizeFacewear] call CBA_fnc_addClassEventHandler;

ADDON = true;
Copy link
Contributor

@johnb432 johnb432 Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the code should be added before this line.

However, more importantly adding keybinds in common doesn't work. keybinding depends on common, meaning the code below is called when CBA_fnc_addKeybind is not defined.

This means that this code needs to be moved to another component. I'm not sure if events is the right place or if we should add another component, just for this.


[ELSTRING(QTEKeybindGroup), "QTE_Up_Key", ["↑", LSTRING(QTEKeybindUpTooltip)], {}, {
["↑"] call CBA_fnc_keyPressedQTE;
}, [DIK_UP, [false, true, false]]] call CBA_fnc_addKeybind;

[ELSTRING(QTEKeybindGroup), "QTE_Down_Key", ["↓", LSTRING(QTEKeybindDownTooltip)], {}, {
["↓"] call CBA_fnc_keyPressedQTE;
}, [DIK_DOWN, [false, true, false]]] call CBA_fnc_addKeybind;

[ELSTRING(QTEKeybindGroup), "QTE_Left_Key", ["←", LSTRING(QTEKeybindLeftTooltip)], {}, {
["←"] call CBA_fnc_keyPressedQTE;
}, [DIK_LEFT, [false, true, false]]] call CBA_fnc_addKeybind;

[ELSTRING(QTEKeybindGroup), "QTE_Right_Key", ["→", LSTRING(QTEKeybindRightTooltip)], {}, {
["→"] call CBA_fnc_keyPressedQTE;
}, [DIK_RIGHT, [false, true, false]]] call CBA_fnc_addKeybind;
john681611 marked this conversation as resolved.
Show resolved Hide resolved
32 changes: 32 additions & 0 deletions addons/common/fnc_generateQTESequence.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "script_component.hpp"
/* ----------------------------------------------------------------------------
Function: CBA_fnc_generateQTESequence

Description:
Generate a Quick-Time sequence of a given length.

Parameters:
_length - <NUMBER>

john681611 marked this conversation as resolved.
Show resolved Hide resolved

Example:
[5] call CBA_fnc_generateQTESequence;

Returns:
Quick-Time sequence of requested length made up of ["↑", "↓", "→", "←"] <ARRAY>

Author:
john681611
---------------------------------------------------------------------------- */

params [["_length", 0, [0]]];

if (_length <= 0) exitWith {[]};

private _code = [];

for "_i" from 0 to _length do {
_code pushBack (selectRandom ["↑", "↓", "→", "←"]);
};

_code
24 changes: 24 additions & 0 deletions addons/common/fnc_getFormattedQTESequence.sqf
Original file line number Diff line number Diff line change
@@ -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 <ARRAY>


Example:
[["↑", "↓", "→", "←"]] call CBA_fnc_getFormattedQTESequence;

Returns:
Formatted Quick-Time sequence <STRING>

Author:
john681611
---------------------------------------------------------------------------- */

params ["_code"];

_code joinString " " // Arma doesn't know how to space ↑ so we need loads of spaces between
62 changes: 62 additions & 0 deletions addons/common/fnc_keyPressedQTE.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include "script_component.hpp"
/* ----------------------------------------------------------------------------
Function: CBA_fnc_keyPressedQTE

Description:
Process Quick-Time Key Press

Parameters:
_eventQTE - <STRING>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argument needs description.


john681611 marked this conversation as resolved.
Show resolved Hide resolved

Example:
["↑"] call CBA_fnc_keyPressedQTE;

Returns:
Nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be None, but the whole point of using a function over an event is so that you can return something.

We want to "override" input if it's a valid QTE keypress, meaning that e.g. if you have bound your arrow up key to move forwards, you wouldn't move forwards while you are doing a QTE.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this where we return true/false in terms of input override?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep


Author:
john681611
---------------------------------------------------------------------------- */


params ["_eventQTE"];
GVAR(QTERunning) = RETDEF(GVAR(QTERunning),false);
if!(GVAR(QTERunning)) exitWith {};
if!(_eventQTE in ["↑", "↓", "→", "←"]) exitWith {};

john681611 marked this conversation as resolved.
Show resolved Hide resolved

private _object = GVAR(QTEArgs) get "object";
private _args = GVAR(QTEArgs) get "args";
private _onDisplay = GVAR(QTEArgs) get "onDisplay";
private _onFinish = GVAR(QTEArgs) get "onFinish";
private _onFail = GVAR(QTEArgs) get "onFail";
private _max_distance = GVAR(QTEArgs) get "max_distance";
private _qte_sequence = GVAR(QTEArgs) get "qte_seqence";
private _start_time = GVAR(QTEArgs) get "start_time";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use camel case to make it consistent with CBA. You'll need to adjust the names accordingly.

Suggested change
private _max_distance = GVAR(QTEArgs) get "max_distance";
private _qte_sequence = GVAR(QTEArgs) get "qte_seqence";
private _start_time = GVAR(QTEArgs) get "start_time";
private _maxDistance = GVAR(QTEArgs) get "maxDistance";
private _qteSequence = GVAR(QTEArgs) get "qteSequence";
private _startTime = GVAR(QTEArgs) get "startTime";

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo it's wasteful to unpack arguments that aren't necessarily going to be used. Only get arguments that you need where you need them.


private _elapsedTime = CBA_missionTime - _start_time;

GVAR(QTEHistory) pushBack _eventQTE;


if (GVAR(QTEHistory) isEqualTo _qte_sequence) exitWith {
GVAR(QTEHistory) = [];
GVAR(QTERunning) = false;
TRACE_1("QTE Completed",_elapsedTime);
if (_onFinish isEqualType "") then {
[_onFinish, [_args, _elapsedTime]] call CBA_fnc_localEvent;
} else {
[_args, _elapsedTime] call _onFinish;
};
};

if !(GVAR(QTEHistory) isEqualTo (_qte_sequence select [0, count GVAR(QTEHistory)])) then {
john681611 marked this conversation as resolved.
Show resolved Hide resolved
GVAR(QTEHistory) = [];
};

if (_onDisplay isEqualType "") then {
[_onDisplay, [_args, _qte_sequence, GVAR(QTEHistory)]] call CBA_fnc_localEvent;
} else {
[_args, _qte_sequence, GVAR(QTEHistory)] call _onDisplay;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[_onDisplay, [_args, _qte_sequence, GVAR(QTEHistory)]] call CBA_fnc_localEvent;
} else {
[_args, _qte_sequence, GVAR(QTEHistory)] call _onDisplay;
[_onDisplay, [_args, _qte_sequence, GVAR(QTEHistory)]] call CBA_fnc_localEvent;
} else {
[_args, _qte_sequence, GVAR(QTEHistory)] call _onDisplay;

};
john681611 marked this conversation as resolved.
Show resolved Hide resolved
97 changes: 97 additions & 0 deletions addons/common/fnc_runQTE.sqf
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "script_component.hpp"
/* ----------------------------------------------------------------------------
Function: CBA_fnc_runQTE

Description:
Runs a Quick time Event.

Parameters:
_object - <OBJECT>
_args - Extra arguments passed to the _on... functions<ARRAY>
_onDisplay - Code callback on displayable event passed [_args, _qte_sequence, _qte_history]. <CODE, STRING>
_onFinish - Code callback on Quick-Time Event completed passed [_args, _elapsedTime]. <CODE, STRING>
_onFinish - Code callback on Quick-Time Event timeout/outranged passed [_args, _elapsedTime]. <CODE, STRING>
_qte_sequence - Quick-Time sequence made up of ["↑", "↓", "→", "←"] <ARRAY>
_max_distance - max interaction distance from attached object <NUMBER> (default: 10)
_timeout - ingame timeout <NUMBER> (default: 30)

Example:
[car,
[],
{
hint format [
"%1 \n %2",
[_this select 1] call CBA_fnc_getFormattedQTESequence,
[_this select 2] call CBA_fnc_getFormattedQTESequence
]
},
{
hint "Finished!";
},
{
hint "Failure!";
},
["↑", "↓", "→", "←"]] call CBA_fnc_runQTE

Returns:
Nil

Author:
john681611
---------------------------------------------------------------------------- */


params ["_object", "_args", "_onDisplay", "_onFinish", "_onFail", "_qte_sequence", ["_max_distance", 10], ["_timeout", 30]];
if (GVAR(QTERunning)) exitWith {
TRACE_1("QTE already running qeueing up",GVAR(QTERunning));
[{
!GVAR(QTERunning)
}, {
_this call FUNC(runQTE);
}, _this] call CBA_fnc_waitUntilAndExecute;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not a fan of this. Depending, we might have to wait indefinitely. It also means that multiple QTE can queue up, which could cause unforeseen headaches, albeit unlikely.

I think we'd be better off returning a boolean telling the caller if the QTE was successfully run or not.

};

GVAR(QTEHistory) = [];
GVAR(QTERunning) = true;
private _start_time = CBA_missionTime;
private _qteArgsArray = [
["object", _object],
["args", _args],
["onDisplay", _onDisplay],
["onFinish", _onFinish],
["onFail", _onFail],
["max_distance", _max_distance],
["qte_seqence", _qte_sequence],
["start_time", _start_time],
["timeout", _timeout]
];
GVAR(QTEArgs) = createHashMapObject [_qteArgsArray];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, there is no reason to use a hashmap object.

Suggested change
GVAR(QTEArgs) = createHashMapObject [_qteArgsArray];
GVAR(QTEArgs) = createHashMapFromArray [_qteArgsArray];


// Setup
[{
private _timeout = GVAR(QTEArgs) get "timeout";
private _object = GVAR(QTEArgs) get "object";
private _max_distance = GVAR(QTEArgs) get "max_distance";
private _elapsedTime = CBA_missionTime - (GVAR(QTEArgs) get "start_time");

!GVAR(QTERunning) || player distance _object > _max_distance || _elapsedTime > _timeout;
}, {
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");
TRACE_1("QTE Failed",_args);
if (_onFail isEqualType "") then {
[_onFail, [_args, _elapsedTime]] call CBA_fnc_localEvent;
} else {
[_args, _elapsedTime] call _onFail;
};
}, _this] call CBA_fnc_waitUntilAndExecute;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't pass _this when using default arguments. The default arguments are not inserted into _this, you'll have to pass each argument individually in an array.

Regardless, _this here does not make sense. Pass [_object, _start_time, _timeout, _max_distance] and read those in the loop instead - unless reading from GVAR(QTEArgs) is faster?


if (_onDisplay isEqualType "") then {
[_onDisplay, [_args, _qte_sequence, []]] call CBA_fnc_localEvent;
} else {
[_args, _qte_sequence, []] call _onDisplay;
};
john681611 marked this conversation as resolved.
Show resolved Hide resolved
16 changes: 16 additions & 0 deletions addons/common/stringtable.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,21 @@
<Russian>CBA Оружие</Russian>
<Korean>CBA 무기</Korean>
</Key>
<Key ID="STR_cba_common_QTEKeybindGroup">
<English>CBA Quick-Time Events</English>
</Key>
<Key ID="STR_cba_common_QTEKeybindUpTooltip">
<English>Up key used in Quick-Time Events.</English>
</Key>
<Key ID="STR_cba_common_QTEKeybindDownTooltip">
<English>Down key used in Quick-Time Events.</English>
</Key>
<Key ID="STR_cba_common_QTEKeybindLeftTooltip">
<English>Left key used in Quick-Time Events.</English>
</Key>
<Key ID="STR_cba_common_QTEKeybindRightTooltip">
<English>Right key used in Quick-Time Events.</English>
</Key>

john681611 marked this conversation as resolved.
Show resolved Hide resolved
</Package>
</Project>