Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* FHQ TaskTracker with disabledAi=1; support
- *
- * Will work with any type of respawn.
- *
- * Filters are now saved instead of filtered units.
- * One drawback is, filters are now not complementing each other,
- * so in the example mission you would have to change west filter to
- * { playerside == west && ! (player in units PlayerGroup) }
- *
- */
- /* FHQ TaskTracker for the FHQ Multiplayer framework
- *
- * This scriptset is used to create briefings and tasks, and keep track of
- * task states.
- *
- * In general, briefings and tasks can be created for individual players, for
- * groups of players, and specific to the side or faction of the player.
- *
- * Unit filters:
- * Whenever a unit filter is asked for, there are several possibilities to
- * define what you need to assign to:
- * single object: A single player
- * group: All players of a group
- * side: All players of a side
- * faction (string): All players of a certain faction
- * code: The piece of code is called for every playable character. Return true if you want
- * the character to be selected, or false otherwise. The only parameter is the playable
- * object to be tested
- *
- * When calling a function that assigns briefings or tasks, a pool of all playable units is created.
- * The filter is tested against those units, and all units matching the filter will have the tasks/briefing
- * assigned to them. Subsequently, these units (that mached the filter) are removed from the pool. Further
- * filtering is done on the remaining units.
- *
- * This essentially means that you should define tasks/briefing entries from specific to general. For example,
- * assuming one player group is west (whith special tasks), and the rest of the players share another set of tasks,
- * you would first use the specific group as filter value, followed by west to assign the following tasks to all
- * remaining west players.
- *
- * Examples:
- * {(side _this) != west): All playable characters that are not BLUFOR
- * player: the player on the current client
- * group westMan1_1: All units in westMan1_1's group
- * east: All playable characters on the OPFOR side
- * "BIS_BAF": All playable british soliders
- *
- *
- * Briefing entries:
- * Briefing entries are defined as an array of two strings. The first string is the title as it
- * will appear in the middle colum when the "Notes" section is highlighted in the left colum.
- * The second string is a text that can contains links to markers, code, and some html formatting
- * and will be displayed on the right column when the title in the center column is highlited.
- *
- *
- * Task entries:
- * A single task entry is an array. The elements in the array are as follows:
- * String: task name
- * String: Task text (the text that will appear in the right colum)
- * String: Task title (it will appear in the center column when "Tasks" is highlited in the left column).
- * String: optional Waypoint title (Will appear on the waypoint marker in the player's main view).
- * Object or position: The destination for this task, either an object, or a position.
- * String: Optional initial state ("created" if nothing given)
- *
- *
- * Commonly used examples:
- *
- * 1. Assign a task as current task:
- * ["taskDestroy", "assigned"] call FHQ_TT_setTaskState;
- *
- *
- * 2. Check if a task is completed (Note, might be successful, failed or cancelled)
- * if (["taskInsert"] call FHQ_TT_isTaskCompleted) then {hint "yes";};
- *
- *
- * 3. Check if a task is successful
- * if (["taskDestroy"] call FHQ_TT_isTaskSuccessful) then {hint "yay";};
- *
- *
- * 4. Mark a task and select another task that is not completed yet.
- * ["taskDestroySecondary", "succeeded", "taskDestroyPrimary", "taskDestroySecondary", "taskExfiltrate"]
- * call FHQ_TT_markTaskAndNext;
- *
- * This example marks taskDestroySecondary as succesful, and then checks if taskDestroyPrimary is completed.
- * If not, it is set to assigned. If it is completed, it continues with the taskDestroySecondary and eventually
- * taskExfiltrate.
- *
- *
- *
- *
- * TODO: Add possibility to change waypoint position
- */
- FHQ_TT_init =
- {
- FHQ_TT_supressTaskHints = true;
- /* Check for Arma 3 or 2 */
- FHQ_TT_is_arma3 = false;
- if (isClass (configfile >> "CfgAddons" >> "PreloadAddons" >> "A3")) then {
- FHQ_TT_is_arma3 = true;
- };
- if (isServer) then
- {
- // Global list of tasks kept on the server. Always contains full info:
- // [unit filter, description, state]
- FHQ_TT_TaskList = [];
- };
- if (!isDedicated) then
- {
- // Local version of the client
- // I wonder, though, why this is necessary, since according to the documentation,
- // the effects of createSimpleTask are global
- // Anyway, [name, state, list of objects]
- FHQ_TT_ClientTaskList = [];
- if (isNil {player} || isNull player) then
- {
- FHQ_TT_isJIPPlayer = true;
- };
- [] spawn
- {
- // Wait for join in progress
- waitUntil {!isNil {player}};
- waitUntil {!isNull player};
- // Wait until the task list is ready.
- waitUntil {!isNil "FHQ_TT_initialized"};
- FHQ_TT_TaskList call FHQ_TT_UpdateTaskList;
- FHQ_TT_supressTaskHints = false;
- "FHQ_TT_TaskList" addPublicVariableEventHandler {(_this select 1) call FHQ_TT_UpdateTaskList};
- };
- };
- };
- FHQ_TT_filterUnits =
- {
- private ["_unitsArray", "_inputArray", "_outputArray"];
- _unitsArray = _this select 1;
- _inputArray = _this select 0;
- _outputArray = [];
- switch (typename _inputArray) do
- {
- case "CODE":
- {
- // Filter all playable units by comparing them with the code
- {if (_x call _inputArray) then {_outputArray = _outputArray + [_x];};} forEach _unitsArray;
- };
- case "GROUP":
- {
- // Filter out all objects not in group
- {if (_x in units _inputArray) then {_outputArray = _outputArray + [_x];};} forEach _unitsArray;
- };
- case "OBJECT":
- {
- // Result is only the array containing the object
- _outputArray = [_inputArray];
- };
- case "SIDE":
- {
- // Filter out all objects not belonging to side
- {if (side _x == _inputArray) then {_outputArray = _outputArray + [_x];};} forEach _unitsArray;
- };
- case "STRING":
- {
- // Filer out all objects not belonging to the faction
- {if (faction _x == _inputArray) then {_outputArray = _outputArray + [_x];};} forEach _unitsArray;
- };
- };
- _outputArray;
- };
- /* FHQ_TT_addBriefingEntry: Add a briefing entry for the given entities
- *
- * This function adds a briefing entry for the given units. The units can be
- * supplied as either a player, a group, a side, a faction, or a piece of code.
- * All playable units will receive the given entries if they match the condition.
- *
- * [_units, _topic, _text] call FHQ_TT_addBriefingEntry;
- * [_units, _subject, _topic, _text] call FHQ_TT_addBriefingEntry; (NOT YET IMPLEMENTED)
- *
- * Parameters:
- * _units: A single unit, a group, side faction, or piece of code that will
- * be run on all playable units.
- * _topic: topic to add to
- * _text: text for this subject
- * _subject: Subject to file this under. A new subject is created if it does not exist yet.
- * (optional, not yet implemented)
- *
- */
- FHQ_TT_addBriefingEntry =
- {
- private ["_units", "_subject", "_topic", "_text", "_unitsArray", "_unitPool"];
- _units = _this select 0;
- _subject = "Diary";
- _topic = _this select 1;
- _text = _this select 2;
- _unitPool = (if (isMultiplayer) then {playableUnits} else {switchableUnits});
- _unitsArray = [_units, _unitPool] call FHQ_TT_filterUnits;
- {_x createDiaryRecord [_subject, [_topic, _text]]} forEach _unitsArray;
- };
- /* Internally used to add topics to units in reversed order */
- FHQ_TT_addBriefingEntries =
- {
- private ["_units", "_subject", "_topics", "_count", "_i", "_topic", "_text"];
- _units = _this select 0;
- _subject = "Diary";
- _topics = _this select 1;
- _count = count _topics;
- if (_count > 0) then
- {
- for [ {_i = _count - 1}, {_i >= 0}, {_i = _i - 1}] do
- {
- _topic = (_topics select _i) select 0;
- _text = (_topics select _i) select 1;
- {_x createDiaryRecord [_subject, [_topic, _text]]} forEach _units;
- };
- };
- };
- /* FHQ_TT_addBriefing: Add a full briefing to the selected units.
- *
- * This functions receives an array as input. The elements of the input array
- * are interpreted as follows:
- * If the element is a two-element array consisting of two strings, the entry is
- * interpreted as a new briefing topic.
- * If the element is anything else, the following topics will only be presented to
- * the units matching the element. For example, if the element is a group, the following
- * entries are added to this group only.
- * If a new unit match is encountered, the units that have been assigned targets before
- * will be removed from the pool of units being considered for future topics.
- *
- * In other words, you can define briefings from bottom up. If you first define briefing topics
- * for a group of players, and then for a side, the side specific topics will not be added to the
- * group. This is meant to enable you to go from specific units up to general.
- *
- * In normal circumstances, you will most likely only define one briefing for a single group of
- * players, and thus passing only an array of string pairs.
- */
- FHQ_TT_addBriefing =
- {
- private ["_unitPool", "_numEntries", "_currentUnits", "_currentTopicList", "_current"];
- _unitPool = (if (isMultiplayer) then {playableUnits} else {switchableUnits});
- _numEntries = count _this;
- _currentUnits = _unitPool;
- _currentTopicList = [];
- for "_i" from 0 to (_numEntries - 1) do
- {
- _current = _this select _i;
- if (typename _current == "ARRAY") then
- {
- // Parameter is an entry for the briefing, apply it to the _currentUnits pool
- // {_x createDiaryRecord ["Diary", [_current select 0, _current select 1]];} forEach _currentUnits;
- _currentTopicList = _currentTopicList + [[_current select 0, _current select 1]];
- }
- else
- {
- // Parameter is a filter for the units. Remove the _currentUnits from the pool and select
- // units according to the filter. Note: not removing anything on _i = 0
- if (_i != 0) then
- {
- _unitPool = _unitPool - _currentUnits;
- };
- if (count _currentTopicList > 0) then
- {
- [_currentUnits, _currentTopicList] call FHQ_TT_addBriefingEntries;
- _currentTopicList = [];
- };
- _currentUnits = [_current, _unitPool] call FHQ_TT_filterUnits;
- };
- };
- // Add any leftovers
- if (count _currentTopicList > 0) then
- {
- [_currentUnits, _currentTopicList] call FHQ_TT_addBriefingEntries;
- _currentTopicList = [];
- };
- };
- /* FHQ_TT_getTaskName
- * Internal
- */
- FHQ_TT_getTaskName =
- {
- private ["_task", "_name"];
- _task = (_this select 0) select 0;
- if (typename _task == "ARRAY") then
- {
- _name = _task select 0;
- }
- else
- {
- _name = _task;
- };
- _name;
- };
- /* FHQ_TT_createSimpleTask:
- *
- * Internal
- */
- FHQ_TT_createSimpleTask =
- {
- private ["_currentUnits", "_currentTask", "_currentTaskState", "_taskObjects", "_taskName"];
- _currentUnits = _this select 0;
- _currentTask = _this select 1; // [name|[name,parent], text, title, waypoint, object/position]
- _currentTaskState = _this select 2;
- _taskObjects = [];
- {
- private "_task";
- if (typename (_currentTask select 0) == "ARRAY") then
- {
- private ["_parentTask"];
- _taskName = (_currentTask select 0) select 0;
- _parentTask = (_currentTask select 0) select 1;
- _task = _x createSimpleTask [_taskName, _x getVariable format["FHQ_TT_taskname_%1", _parentTask]];
- }
- else
- {
- _taskName = _currentTask select 0;
- _task = _x createSimpleTask [_currentTask select 0];
- };
- _task setSimpleTaskDescription [_currentTask select 1, _currentTask select 2, _currentTask select 3];
- if (count _currentTask > 4) then
- {
- switch (typename (_currentTask select 4)) do
- {
- case "ARRAY":
- {
- _task setSimpleTaskDestination (_currentTask select 4);
- };
- case "OBJECT":
- {
- _task setSimpleTaskTarget [_currentTask select 4, true];
- };
- };
- };
- _task setTaskState _currentTaskState;
- if (tolower(_currentTaskState) == "assigned") then
- {
- _x setCurrentTask _task;
- };
- _x setVariable [format["FHQ_TT_taskname_%1", _taskName], _task, true];
- _taskObjects = _taskObjects + [_task];
- } forEach _currentUnits;
- _taskObjects;
- };
- /* Internal */
- FHQ_TT_addTaskEntries =
- {
- private ["_currentUnits", "_tasks", "_count", "_i", "_current", "_state"];
- _currentUnits = _this select 0;
- _tasks = _this select 1;
- _count = count _tasks;
- if (_count > 0) then
- {
- if (FHQ_TT_is_arma3) then
- {
- for [ {_i = 0}, {_i < _count}, {_i = _i + 1}] do
- {
- _current = _tasks select _i;
- _state = "created";
- // Optional state
- if (count _current >= 6) then
- {
- _state = _current select 5;
- };
- // fifth element is either an object/position, or a string. In the latter case,
- // object/position was ommited but initial state given
- if (count _current >= 5) then
- {
- if (typename (_current select 4) == "STRING") then
- {
- _state = _current select 4;
- };
- };
- FHQ_TT_TaskList = FHQ_TT_TaskList + [[_currentUnits, _current, _state]];
- };
- }
- else
- {
- for [ {_i = _count - 1}, {_i >= 0}, {_i = _i - 1}] do
- {
- _current = _tasks select _i;
- _state = "created";
- // Optional state
- if (count _current >= 6) then
- {
- _state = _current select 5;
- };
- // fifth element is either an object/position, or a string. In the latter case,
- // object/position was ommited but initial state given
- if (count _current >= 5) then
- {
- if (typename (_current select 4) == "STRING") then
- {
- _state = _current select 4;
- };
- };
- FHQ_TT_TaskList = FHQ_TT_TaskList + [[_currentUnits, _current, _state]];
- };
- }
- };
- };
- /* FHQ_TT_addTasks: Add tasks to the mission
- *
- * write me
- *
- */
- FHQ_TT_addTasks =
- {
- private ["_numEntries", "_unitPool", "_currentUnits", "_currentTaskList", "_current"];
- if (!isServer) exitWith {};
- _numEntries = count _this;
- if (_numEntries <= 0) exitWith {};
- //_unitPool = (if (isMultiplayer) then {playableUnits} else {switchableUnits});
- //_currentUnits = _unitPool;
- _currentTaskList = [];
- for "_i" from 0 to (_numEntries - 1) do
- {
- _current = _this select _i;
- if (typename _current == "ARRAY") then
- {
- _currentTaskList = _currentTaskList + [_current];
- }
- else
- {
- // Parameter is a filter for the units.
- if (_i != 0) then
- {
- //_unitPool = _unitPool - _currentUnits;
- };
- if (count _currentTaskList > 0) then
- {
- [_currentUnits, _currentTaskList] call FHQ_TT_addTaskEntries;
- _currentTaskList = [];
- };
- //_currentUnits = [_current, _unitPool] call FHQ_TT_filterUnits;
- _currentUnits = _current;
- };
- };
- if (count _currentTaskList > 0) then
- {
- [_currentUnits, _currentTaskList] call FHQ_TT_addTaskEntries;
- };
- // Send task list to clients
- publicVariable "FHQ_TT_TaskList";
- if (!isDedicated) then
- {
- FHQ_TT_TaskList call FHQ_TT_UpdateTaskList;
- };
- FHQ_TT_initialized = true;
- publicVariable "FHQ_TT_initialized";
- };
- FHQ_TT_hasTask =
- {
- private "_result";
- _result = false;
- {
- if ((_x call FHQ_TT_getTaskName) == _this) exitWith {_result = true;};
- } forEach FHQ_TT_ClientTaskList;
- _result;
- };
- FHQ_TT_taskHint =
- {
- if (!FHQ_TT_is_arma3) then
- {
- /* Arma 2 */
- private ["_desc", "_state", "_color", "_icon", "_text"];
- _desc = _this select 0;
- _state = _this select 1;
- _color = [1, 1, 1, 1];
- _icon = "taskNew";
- _text = "New Task";
- switch (tolower(_state)) do
- {
- case "created":
- {
- _color = [1, 1, 1, 1];
- _icon = "taskNew";
- _text = localize "str_taskNew";
- };
- case "assigned":
- {
- _color = [1, 1, 1, 1];
- _icon = "taskCurrent";
- _text = localize "str_taskSetCurrent";
- };
- case "succeeded":
- {
- _color = [0.600000,0.839215,0.466666,1];
- _icon = "taskDone";
- _text = localize "str_taskAccomplished";
- };
- case "canceled":
- {
- _color = [0.75,0.75,0.75,1];
- _icon = "taskFailed";
- _text = localize "str_taskCancelled";
- };
- case "cancelled":
- {
- _color = [0.75,0.75,0.75,1];
- _icon = "taskFailed";
- _text = localize "str_taskCancelled";
- };
- case "failed":
- {
- _color = [0.972549,0.121568,0,1];
- _icon = "taskFailed";
- _text = localize "str_taskFailed";
- };
- };
- taskHint [format ["%1\n%2", _text, _desc], _color, _icon];
- }
- else
- {
- /* Arma 3 */
- private ["_notifyTemplate", "_desc", "_state"];
- _desc = _this select 0;
- _state = _this select 1;
- switch (tolower _state) do
- {
- case "created":
- {
- _notifyTemplate = "TaskCreated";
- };
- case "assigned":
- {
- _notifyTemplate = "TaskAssigned";
- };
- case "succeeded":
- {
- _notifyTemplate = "TaskSucceeded";
- };
- case "canceled":
- {
- _notifyTemplate = "TaskCanceled";
- };
- case "cancelled":
- {
- _notifyTemplate = "TaskCanceled";
- };
- case "failed":
- {
- _notifyTemplate = "TaskFailed";
- };
- };
- [_notifyTemplate, ["", _desc]] call BIS_fnc_showNotification;
- };
- };
- FHQ_TT_UpdateTaskList =
- {
- if (isDedicated) exitWith {};
- private ["_count", "_i", "_tasks"];
- _tasks = _this;
- _count = count _tasks;
- _unitPool = (if (isMultiplayer) then {playableUnits} else {switchableUnits});
- if (_count > 0) then
- {
- for [ {_i = 0}, {_i < _count}, {_i = _i + 1}] do
- {
- private ["_current", "_currentUnits", "_taskObjects", "_currentTask",
- "_currentTaskState", "_currentTaskName", "_currentTaskParent"];
- _current = _tasks select _i; // [units, taskDesc, state]
- _currentTask = _current select 1; // [name|[name,parent], text, title, waypoint, object/position]
- _currentUnits = _current select 0;
- _currentTaskState = _current select 2;
- _currentTaskName = "";
- _currentTaskParent = "";
- _currentUnits = [_currentUnits, _unitPool] call FHQ_TT_filterUnits;
- if (typename (_currentTask select 0) == "ARRAY") then
- {
- _currentTaskName = (_currentTask select 0) select 0;
- _currentTaskParent = (_currentTask select 0) select 1;
- }
- else
- {
- _currentTaskName = _currentTask select 0;
- };
- if (_currentTaskName call FHQ_TT_hasTask) then
- {
- private ["_localTask", "_x", "_task"];
- _localTask = FHQ_TT_ClientTaskList select _i; // [name, state, objects]
- diag_log format["_localTask -> %1, _curent -> %2", _localTask select 1, _current select 2];
- if ((_current select 2) != (_localTask select 1)) then
- {
- // Update the task
- _localTask set [1, _current select 2];
- FHQ_TT_ClientTaskList set [_i, _localTask];
- if (player in (_currentUnits)) then
- {
- [_currentTask select 2, _current select 2] call FHQ_TT_taskHint;
- };
- {
- _task = _x;
- if (_current select 2 == "assigned") then
- {
- {
- if (_task in (simpletasks _x)) then
- {
- _x setCurrentTask _task;
- };
- } forEach _currentUnits;
- };
- _task setTaskState (_current select 2);
- } forEach (_localTask select 2);
- };
- }
- else
- {
- _taskObjects = [_currentUnits, _currentTask, _currentTaskState] call FHQ_TT_createSimpleTask;
- FHQ_TT_ClientTaskList set [_i, [(_current select 1), _currentTaskState, _taskObjects]];
- if (player in (_currentUnits) && !FHQ_TT_supressTaskHints) then
- {
- [_currentTask select 2, _currentTaskState] call FHQ_TT_taskHint;
- };
- };
- };
- };
- };
- /* FHQ_TT_setTaskState: Set state of a specific task
- *
- * write me
- *
- * [_taskName, _state] call FHQ_TT_setTaskState;
- */
- FHQ_TT_setTaskState =
- {
- if (!isServer) exitWith {};
- private ["_count", "_taskName", "_newState", "_i", "_curTask"];
- _count = count FHQ_TT_TaskList;
- _taskName = _this select 0;
- _newState = _this select 1;
- for [ {_i = 0}, {_i < _count}, {_i = _i + 1}] do
- {
- _curTask = FHQ_TT_TaskList select _i;
- diag_log format["_curTask = %1", _curTask];
- //if (_taskName == ((_curTask select 1) select 0)) exitWith
- if (_taskName == ([_curTask select 1] call FHQ_TT_getTaskName)) exitWith
- {
- _curTask set [2, _newState];
- FHQ_TT_TaskList set [_i, _curTask];
- };
- };
- publicVariable "FHQ_TT_TaskList";
- if (!isDedicated) then
- {
- FHQ_TT_TaskList call FHQ_TT_UpdateTaskList;
- };
- };
- /* FHQ_TT_getTaskState: Get state of a specific task
- *
- * write me
- *
- * _result = [_taskName] call FHQ_TT_getTaskState;
- */
- FHQ_TT_getTaskState =
- {
- private ["_result", "_taskName"];
- _result = "";
- _taskName = _this select 0;
- {
- // if (((_x select 1) select 0) == _taskname) exitWith
- if (([_x select 1] call FHQ_TT_getTaskName) == _taskname) exitWith
- {
- _result = (_x select 2);
- };
- } forEach FHQ_TT_TaskList;
- _result;
- };
- /* FHQ_TT_isTaskCompleted: Check whether a task is canceled, successful or failed
- *
- * _result = [_taskName] call FHQ_TT_isTaskCompleted;
- */
- FHQ_TT_isTaskCompleted =
- {
- private "_result";
- _result = (tolower(_this call FHQ_TT_getTaskState) in ["succeeded", "canceled", "failed"]);
- _result;
- };
- /* FHQ_TT_areTasksCompleted: Check for all tasks given whether they are cancelled, successful, or failed
- * _result = [_taskName1, _taskName2, ...] call FHQ_TT_areTasksCompleted
- */
- FHQ_TT_areTasksCompleted =
- {
- private ["_result", "_x"];
- _result = true;
- {
- if (!(tolower ([_x] call FHQ_TT_getTaskState) in ["succeeded", "canceled", "failed"])) exitWith
- {
- _result = false;
- };
- } forEach _this;
- _result;
- };
- /* FHQ_TT_isTaskSuccessful: Check whether a task is ended successfully
- *
- * _result = [_taskName] call FHQ_TT_isTaskSuccessful;
- */
- FHQ_TT_isTaskSuccessful =
- {
- private "_result";
- _result = (tolower(_this call FHQ_TT_getTaskState) == "succeeded");
- _result;
- };
- /* FHQ_TT_areTasksSuccessful: Check success for all tasks given
- * _result = [_taskName1, _taskName2, ...] call FHQ_TT_areTasksSuccessful
- */
- FHQ_TT_areTasksSuccessful =
- {
- private ["_result", "_x"];
- _result = true;
- {
- if (tolower ([_x] call FHQ_TT_getTaskState) != "succeeded") exitWith
- {
- _result = false;
- };
- } forEach _this;
- _result;
- };
- /* FHQ_TT_getAllTasksWithState: Get all tasks with a given state
- *
- * _taskList = [_state] call FHQ_TT_getAllTasksWithState;
- */
- FHQ_TT_getAllTasksWithState =
- {
- private ["_result", "_taskState"];
- _result = [];
- _taskState = _this select 0;
- {
- if ((_x select 2) == _taskState) then
- {
- _result = _result + [(_x select 1) select 0];
- };
- } forEach FHQ_TT_TaskList;
- _result;
- };
- /* FHQ_TT_markTaskAndNext: Mark a task as completed, and look for the next
- * open task.
- *
- * ["taskName", "state", ("newTask1", "newTask2" ... )] call FHQ_TT_markTaskAndNext;
- */
- FHQ_TT_markTaskAndNext =
- {
- private "_i";
- [_this select 0, _this select 1] call FHQ_TT_setTaskState;
- for [ {_i = 2}, {_i < count _this}, {_i = _i + 1} ] do
- {
- if (!([_this select _i] call FHQ_TT_isTaskCompleted)) exitWith
- {
- [_this select _i, "assigned"] call FHQ_TT_setTaskState;
- };
- };
- };
- /* ------------ End of file, calling init ------------ */
- call FHQ_TT_init;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement