mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Javelin refined, working, locking fixes, UI fixes, missile guidance rewrite
This commit is contained in:
parent
c436541f1c
commit
6f3ce27894
@ -12,20 +12,10 @@ class RscLine;
|
||||
class RscInGameUI {
|
||||
class ACE_RscOptics_javelin {
|
||||
idd = 300;
|
||||
controls[] = { "ACE_javelin_elements_group", "CA_Distance", "ACE_Targeting" }; //, "ACE_TargetingConstrains", "ACE_TargetingGate", "ACE_TargetingLines"};
|
||||
controls[] = { "ACE_javelin_elements_group", "ACE_Targeting" }; //, "ACE_TargetingConstrains", "ACE_TargetingGate", "ACE_TargetingLines"};
|
||||
onLoad = QUOTE(_this call FUNC(onOpticLoad));
|
||||
onUnload = "uiNameSpace setVariable ['ACE_RscOptics_javelin',nil];uiNameSpace setVariable ['ACE_RscOptics_javelin_PFH',nil];";
|
||||
|
||||
class CA_Distance: RscOpticsValue {
|
||||
idc = 151;
|
||||
sizeEx = "0";
|
||||
colorText[] = {0,0,0,0};
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = 0;
|
||||
h = 0;
|
||||
};
|
||||
|
||||
class ACE_javelin_elements_group: RscControlsGroup
|
||||
{
|
||||
x = "SafezoneX";
|
||||
@ -45,6 +35,16 @@ class RscInGameUI {
|
||||
height = 0.001;
|
||||
};
|
||||
class Controls {
|
||||
class CA_Distance: RscOpticsValue {
|
||||
idc = 151;
|
||||
sizeEx = "0";
|
||||
colorText[] = {0,0,0,0};
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = 0;
|
||||
h = 0;
|
||||
};
|
||||
|
||||
class ACE_javelin_Day_mode_off: RscPicture {
|
||||
idc = 1001;
|
||||
x = "(SafezoneX+(SafezoneW -SafezoneH*3/4)/2)+ (0.03/4)*3*SafezoneH - SafezoneX";
|
||||
@ -58,7 +58,7 @@ class RscInGameUI {
|
||||
idc = 160;
|
||||
colorText[] = {0.2941,0.8745,0.2157,1};
|
||||
};
|
||||
class ACE_javelin_WFOV_mode_off: ACE_javelin_Day_mode_off {
|
||||
class CA_Javelin_WFOV_mode_off : ACE_javelin_Day_mode_off {
|
||||
idc = 1004;
|
||||
x = "(SafezoneX+(SafezoneW -SafezoneH*3/4)/2)+ (0.307/4)*3*SafezoneH - SafezoneX";
|
||||
text = "\A3\ui_f\data\igui\rscingameui\rscoptics_titan\wfov_co.paa";
|
||||
@ -81,13 +81,6 @@ class RscInGameUI {
|
||||
height = 0.001;
|
||||
};
|
||||
class Controls {
|
||||
class ACE_javelin_WFOV_mode: ACE_javelin_WFOV_mode_off {
|
||||
idc = -1;
|
||||
y = "0.031*SafezoneH - SafezoneY";
|
||||
x = "((SafezoneW -SafezoneH*3/4)/2)+ (0.307/4)*3*SafezoneH - SafezoneX";
|
||||
colorText[] = {0.2941,0.8745,0.2157,1};
|
||||
};
|
||||
/*
|
||||
class StadiaL: RscLine {
|
||||
x = "0.4899*SafezoneW - SafezoneX";
|
||||
y = "0.171*SafezoneH - SafezoneY";
|
||||
@ -130,10 +123,10 @@ class RscInGameUI {
|
||||
h = 0;
|
||||
colorText[] = {0.2941,0.8745,0.2157,1};
|
||||
};
|
||||
*/
|
||||
|
||||
};
|
||||
};
|
||||
class ACE_javelin_NFOV_mode_off: ACE_javelin_Day_mode_off {
|
||||
class CA_Javelin_NFOV_mode_off: ACE_javelin_Day_mode_off {
|
||||
idc = 1003;
|
||||
x = "(SafezoneX+(SafezoneW -SafezoneH*3/4)/2)+ (0.586/4)*3*SafezoneH - SafezoneX";
|
||||
text = "\A3\ui_f\data\igui\rscingameui\rscoptics_titan\nfov_co.paa";
|
||||
@ -156,13 +149,6 @@ class RscInGameUI {
|
||||
height = 0.001;
|
||||
};
|
||||
class Controls {
|
||||
class ACE_javelin_NFOV_mode: ACE_javelin_NFOV_mode_off {
|
||||
idc = 699003;
|
||||
x = "((SafezoneW -SafezoneH*3/4)/2)+ (0.586/4)*3*SafezoneH - SafezoneX";
|
||||
y = "0.031*SafezoneH - SafezoneY";
|
||||
colorText[] = {0.2941,0.8745,0.2157,1};
|
||||
};
|
||||
/*
|
||||
class StadiaL: RscLine {
|
||||
x = "0.4788*SafezoneW - SafezoneX";
|
||||
y = "0.171*SafezoneH - SafezoneY";
|
||||
@ -205,7 +191,7 @@ class RscInGameUI {
|
||||
h = "0.1895*SafezoneH";
|
||||
colorText[] = {0.2941,0.8745,0.2157,1};
|
||||
};
|
||||
*/
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -4,10 +4,10 @@ TRACE_1("enter", _this);
|
||||
|
||||
private["_player", "_currentFireMode"];
|
||||
|
||||
_currentFireMode = ACE_player getVariable["ace_missileguidance_attackProfile", "TOP"];
|
||||
if(_currentFireMode == "LIN") then {
|
||||
_currentFireMode = "TOP";
|
||||
_currentFireMode = ACE_player getVariable["ace_missileguidance_attackProfile", "JAV_TOP"];
|
||||
if(_currentFireMode == "JAV_DIR") then {
|
||||
_currentFireMode = "JAV_TOP";
|
||||
} else {
|
||||
_currentFireMode = "LIN";
|
||||
_currentFireMode = "JAV_DIR";
|
||||
};
|
||||
ACE_player setVariable["ace_missileguidance_attackProfile", _currentFireMode, false];
|
||||
|
@ -3,9 +3,8 @@
|
||||
TRACE_1("enter", _this);
|
||||
|
||||
#define __TRACKINTERVAL 0 // how frequent the check should be.
|
||||
#define __LOCKONTIME 3.0 // Lock on won't occur sooner
|
||||
#define __LOCKONTIMERANDOM 0.3 // Deviation in lock on time
|
||||
#define __SENSORSQUARE 1 // Locking on sensor square side in angles
|
||||
#define __LOCKONTIME 3 // Lock on won't occur sooner
|
||||
#define __LOCKONTIMERANDOM 2 // Deviation in lock on time
|
||||
|
||||
#define __OffsetX ((ctrlPosition __JavelinIGUITargetingLineV) select 0) - 0.5
|
||||
#define __OffsetY ((ctrlPosition __JavelinIGUITargetingLineH) select 1) - 0.5
|
||||
@ -113,10 +112,11 @@ if (isNull _newTarget) then {
|
||||
__JavelinIGUITargetingLines ctrlShow false;
|
||||
__JavelinIGUITargetingConstraints ctrlShow false;
|
||||
|
||||
ACE_player setVariable ["ace_missileguidance_target",nil, false];
|
||||
ACE_player setVariable ["ace_missileguidance_target",nil, false];
|
||||
|
||||
// Disallow fire
|
||||
//if (ACE_player ammo "Javelin" > 0 || {ACE_player ammo "ACE_Javelin_Direct" > 0}) then {ACE_player setWeaponReloadingTime //[player, "Javelin", 0.2];};
|
||||
if (ACE_player ammo (currentWeapon ACE_player) > 0) then { ACE_player setWeaponReloadingTime [player, (currentWeapon ACE_player), 0.2]; };
|
||||
|
||||
} else {
|
||||
if (_newTarget distance ACE_player < 2500
|
||||
&& {(call CBA_fnc_getFoV) select 1 > 9}
|
||||
@ -131,7 +131,7 @@ if (isNull _newTarget) then {
|
||||
|
||||
playSound "ACE_Javelin_Locking";
|
||||
} else {
|
||||
if(diag_tickTime - _lockTime > __LOCKONTIME) then {
|
||||
if(diag_tickTime - _lockTime > __LOCKONTIME + (random __LOCKONTIMERANDOM)) then {
|
||||
TRACE_2("LOCKED!", _currentTarget, _lockTime);
|
||||
|
||||
__JavelinIGUISeek ctrlSetTextColor __ColorGreen;
|
||||
@ -170,6 +170,9 @@ if (isNull _newTarget) then {
|
||||
|
||||
ACE_player setVariable["ace_missileguidance_target", _currentTarget, false];
|
||||
|
||||
// Allow fire
|
||||
ACE_player setWeaponReloadingTime [player, (currentWeapon ACE_player), 0];
|
||||
|
||||
if(diag_tickTime > _soundTime) then {
|
||||
playSound "ACE_Javelin_Locked";
|
||||
_soundTime = diag_tickTime + 0.25;
|
||||
@ -208,21 +211,26 @@ if (isNull _newTarget) then {
|
||||
playSound "ACE_Javelin_Locking";
|
||||
_soundTime = diag_tickTime + 0.25;
|
||||
};
|
||||
// Disallow fire
|
||||
if (ACE_player ammo (currentWeapon ACE_player) > 0) then { ACE_player setWeaponReloadingTime [player, (currentWeapon ACE_player), 0.2]; };
|
||||
};
|
||||
};
|
||||
} else {
|
||||
// Something is wrong with our seek
|
||||
// No targets found
|
||||
_currentTarget = objNull;
|
||||
ACE_player setVariable["ace_missileguidance_target", nil, false];
|
||||
_lockTime = 0;
|
||||
|
||||
__JavelinIGUISeek ctrlSetTextColor __ColorGray;
|
||||
__JavelinIGUITargeting ctrlShow false;
|
||||
__JavelinIGUITargetingGate ctrlShow false;
|
||||
__JavelinIGUITargetingLines ctrlShow false;
|
||||
|
||||
__JavelinIGUITargetingConstraints ctrlShow false;
|
||||
|
||||
ACE_player setVariable ["ace_missileguidance_target",nil, false];
|
||||
};
|
||||
|
||||
|
||||
// Disallow fire
|
||||
if (ACE_player ammo (currentWeapon ACE_player) > 0) then { ACE_player setWeaponReloadingTime [player, (currentWeapon ACE_player), 0.2]; };
|
||||
};
|
||||
};
|
||||
|
||||
//TRACE_2("", _newTarget, _currentTarget);
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define __JavelinIGUISeek (__JavelinIGUI displayCtrl 699000)
|
||||
#define __JavelinIGUITop (__JavelinIGUI displayCtrl 699001)
|
||||
#define __JavelinIGUIDir (__JavelinIGUI displayCtrl 699002)
|
||||
#define __JavelinIGUINFOV (__JavelinIGUI displayCtrl 699003)
|
||||
#define __JavelinIGUINFOV (__JavelinIGUI displayCtrl 1003)
|
||||
#define __JavelinIGUIWFOV (__JavelinIGUI displayCtrl 1004)
|
||||
#define __JavelinIGUIRangefinder (__JavelinIGUI displayCtrl 151)
|
||||
|
||||
|
@ -27,19 +27,19 @@ class GVAR(AttackProfiles) {
|
||||
|
||||
functionName = QFUNC(attackProfile_HI);
|
||||
};
|
||||
class TOP {
|
||||
class JAV_DIR {
|
||||
name = "";
|
||||
visualName = "";
|
||||
description = "";
|
||||
|
||||
functionName = QFUNC(attackProfile_TOP);
|
||||
functionName = QFUNC(attackProfile_JAV_DIR);
|
||||
};
|
||||
class PYM {
|
||||
class JAV_TOP {
|
||||
name = "";
|
||||
visualName = "";
|
||||
description = "";
|
||||
|
||||
functionName = QFUNC(attackProfile_PYM);
|
||||
functionName = QFUNC(attackProfile_JAV_TOP);
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -134,8 +134,8 @@ class CfgAmmo {
|
||||
seekerMaxRange = 2500; // Range from the missile which the seeker can visually search
|
||||
|
||||
// Attack profile type selection
|
||||
defaultAttackProfile = "TOP";
|
||||
attackProfiles[] = { "TOP", "LIN" };
|
||||
defaultAttackProfile = "JAV_TOP";
|
||||
attackProfiles[] = { "JAV_TOP", "JAV_DIR" };
|
||||
};
|
||||
};
|
||||
};
|
@ -18,10 +18,12 @@ PREP(attackProfile_LIN);
|
||||
PREP(attackProfile_DIR);
|
||||
PREP(attackProfile_MID);
|
||||
PREP(attackProfile_HI);
|
||||
PREP(attackProfile_TOP);
|
||||
PREP(attackprofile_PYM);
|
||||
PREP(attackProfile_AIR);
|
||||
|
||||
// Javelin profiles
|
||||
PREP(attackProfile_JAV_DIR);
|
||||
PREP(attackProfile_JAV_TOP);
|
||||
|
||||
// Seeker search functions
|
||||
PREP(seekerType_SALH);
|
||||
PREP(seekerType_Optic);
|
@ -1,54 +1,4 @@
|
||||
//#define DEBUG_MODE_FULL
|
||||
#include "script_component.hpp"
|
||||
|
||||
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
|
||||
private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
|
||||
private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos"];
|
||||
_seekerTargetPos = _this select 0;
|
||||
_launchParams = _this select 1;
|
||||
|
||||
_target = _launchParams select 0;
|
||||
_targetLaunchParams = _launchParams select 1;
|
||||
|
||||
_shooterPos = getPosASL _shooter;
|
||||
_projectilePos = getPosASL _projectile;
|
||||
|
||||
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
|
||||
_distanceToShooter = _projectilePos vectorDistance _shooterPos;
|
||||
|
||||
TRACE_2("", _distanceToTarget, _distanceToShooter);
|
||||
|
||||
// Add height depending on distance for compensate
|
||||
_addHeight = [0,0,0];
|
||||
|
||||
// Always climb an arc on initial launch if we are close to the round
|
||||
if( ((ASLtoATL _projectilePos) select 2) < 5 && _distanceToShooter < 15) then {
|
||||
_addHeight = _addHeight vectorAdd [0,0,_distanceToTarget];
|
||||
} else {
|
||||
// If we are below the target, increase the climbing arc
|
||||
if((_projectilePos select 2) < (_seekerTargetPos select 2) && _distanceToTarget > 100) then {
|
||||
_addHeight = _addHeight vectorAdd [0,0, ((_seekerTargetPos select 2) - (_projectilePos select 2))];
|
||||
};
|
||||
};
|
||||
|
||||
// Handle arcing terminal low for high decent
|
||||
if( (_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget < 100) then {
|
||||
_addHeight = _addHeight vectorDiff [0,0, ((_projectilePos select 2) - (_seekerTargetPos select 2))];
|
||||
} else {
|
||||
if((_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget > 100) then {
|
||||
_addHeight = _addHeight vectorAdd [0,0, _distanceToTarget];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
TRACE_3("", _distanceToTarget,_distanceToShooter,_addHeight);
|
||||
|
||||
_returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
drawLine3D [(ASLtoATL _returnTargetPos) vectorAdd _addHeight, ASLtoATL _returnTargetPos, [0,1,0,1]];
|
||||
#endif
|
||||
|
||||
TRACE_1("Adjusted target position", _returnTargetPos);
|
||||
_returnTargetPos;
|
||||
_this call FUNC(attackProfile_LIN);
|
@ -1,54 +1,4 @@
|
||||
//#define DEBUG_MODE_FULL
|
||||
#include "script_component.hpp"
|
||||
|
||||
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
|
||||
private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
|
||||
private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos"];
|
||||
_seekerTargetPos = _this select 0;
|
||||
_launchParams = _this select 1;
|
||||
|
||||
_target = _launchParams select 0;
|
||||
_targetLaunchParams = _launchParams select 1;
|
||||
|
||||
_shooterPos = getPosASL _shooter;
|
||||
_projectilePos = getPosASL _projectile;
|
||||
|
||||
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
|
||||
_distanceToShooter = _projectilePos vectorDistance _shooterPos;
|
||||
|
||||
TRACE_2("", _distanceToTarget, _distanceToShooter);
|
||||
|
||||
// Add height depending on distance for compensate
|
||||
_addHeight = [0,0,0];
|
||||
|
||||
// Always climb an arc on initial launch if we are close to the round
|
||||
if( ((ASLtoATL _projectilePos) select 2) < 5 && _distanceToShooter < 15) then {
|
||||
_addHeight = _addHeight vectorAdd [0,0,_distanceToTarget];
|
||||
} else {
|
||||
// If we are below the target, increase the climbing arc
|
||||
if((_projectilePos select 2) < (_seekerTargetPos select 2) && _distanceToTarget > 100) then {
|
||||
_addHeight = _addHeight vectorAdd [0,0, ((_seekerTargetPos select 2) - (_projectilePos select 2))];
|
||||
};
|
||||
};
|
||||
|
||||
// Handle arcing terminal low for high decent
|
||||
if( (_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget < 100) then {
|
||||
_addHeight = _addHeight vectorDiff [0,0, ((_projectilePos select 2) - (_seekerTargetPos select 2)) * 0.5];
|
||||
} else {
|
||||
if((_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget > 100) then {
|
||||
_addHeight = _addHeight vectorAdd [0,0, _distanceToTarget*0.02];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
TRACE_3("", _distanceToTarget,_distanceToShooter,_addHeight);
|
||||
|
||||
_returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
drawLine3D [(ASLtoATL _returnTargetPos) vectorAdd _addHeight, ASLtoATL _returnTargetPos, [0,1,0,1]];
|
||||
#endif
|
||||
|
||||
TRACE_1("Adjusted target position", _returnTargetPos);
|
||||
_returnTargetPos;
|
||||
_this call FUNC(attackProfile_LIN);
|
@ -0,0 +1,69 @@
|
||||
//#define DEBUG_MODE_FULL
|
||||
#include "script_component.hpp"
|
||||
|
||||
#define STAGE_LAUNCH 1
|
||||
#define STAGE_CLIMB 2
|
||||
#define STAGE_COAST 3
|
||||
#define STAGE_TERMINAL 4
|
||||
|
||||
EXPLODE_7_PVT(((_this select 1) select 0),_shooter,_weapon,_muzzle,_mode,_ammo,_magazine,_projectile);
|
||||
private["_targetPos", "_projectilePos", "_target", "_seekerTargetPos", "_launchParams", "_targetLaunchParams"];
|
||||
private["_distanceToTarget", "_distanceToShooter", "_addHeight", "_returnTargetPos", "_state"];
|
||||
_seekerTargetPos = _this select 0;
|
||||
_launchParams = _this select 1;
|
||||
|
||||
_target = _launchParams select 0;
|
||||
_targetLaunchParams = _launchParams select 1;
|
||||
|
||||
_state = _this select 2;
|
||||
if( (count _state) < 1) then {
|
||||
_state set[0, STAGE_LAUNCH];
|
||||
};
|
||||
|
||||
_shooterPos = getPosASL _shooter;
|
||||
_projectilePos = getPosASL _projectile;
|
||||
|
||||
_distanceToTarget = _projectilePos vectorDistance _seekerTargetPos;
|
||||
_distanceToShooter = _projectilePos vectorDistance _shooterPos;
|
||||
_distanceShooterToTarget = _shooterPos vectorDistance _seekerTargetPos;
|
||||
|
||||
TRACE_2("", _distanceToTarget, _distanceToShooter);
|
||||
|
||||
// Add height depending on distance for compensate
|
||||
_returnTargetPos = _seekerTargetPos;
|
||||
|
||||
switch( (_state select 0) ) do {
|
||||
case STAGE_LAUNCH: {
|
||||
TRACE_1("STAGE_LAUNCH","");
|
||||
if(_distanceToShooter < 10) then {
|
||||
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*2];
|
||||
} else {
|
||||
_state set[0, STAGE_CLIMB];
|
||||
};
|
||||
};
|
||||
case STAGE_CLIMB: {
|
||||
TRACE_1("STAGE_CLIMB","");
|
||||
_cruisAlt = 60;
|
||||
if(_distanceShooterToTarget < w) then {
|
||||
_cruisAlt = 60 * (_distanceShooterToTarget/2000);
|
||||
TRACE_1("_cruisAlt", _cruisAlt);
|
||||
};
|
||||
|
||||
if( ((ASLToATL _projectilePos) select 2) - ((ASLToATL _seekerTargetPos) select 2) >= _cruisAlt) then {
|
||||
_state set[0, STAGE_TERMINAL];
|
||||
} else {
|
||||
_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget*2];
|
||||
};
|
||||
};
|
||||
case STAGE_TERMINAL: {
|
||||
TRACE_1("STAGE_TERMINAL","");
|
||||
//_returnTargetPos = _seekerTargetPos vectorAdd [0,0,_distanceToTarget * 0.02];
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
drawLine3D [(ASLtoATL _returnTargetPos), (ASLtoATL _seekerTargetPos), [0,1,0,1]];
|
||||
#endif
|
||||
|
||||
TRACE_1("Adjusted target position", _returnTargetPos);
|
||||
_returnTargetPos;
|
@ -40,12 +40,6 @@ if( (_projectilePos select 2) > (_seekerTargetPos select 2) && _distanceToTarget
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
TRACE_3("", _distanceToTarget,_distanceToShooter,_addHeight);
|
||||
|
||||
_returnTargetPos = _seekerTargetPos vectorAdd _addHeight;
|
||||
|
||||
#ifdef DEBUG_MODE_FULL
|
||||
drawLine3D [(ASLtoATL _returnTargetPos) vectorAdd _addHeight, ASLtoATL _returnTargetPos, [0,1,0,1]];
|
||||
#endif
|
||||
|
@ -1,4 +0,0 @@
|
||||
//#define DEBUG_MODE_FULL
|
||||
#include "script_component.hpp"
|
||||
|
||||
_this call FUNC(attackProfile_LIN);
|
@ -12,7 +12,7 @@
|
||||
* Boolean
|
||||
*/
|
||||
|
||||
#define DEBUG_MODE_FULL
|
||||
//#define DEBUG_MODE_FULL
|
||||
#include "script_component.hpp"
|
||||
private["_seeker", "_targetPos", "_seekerMaxAngle", "_vectorTo", "_sensorPos", "_vertOk", "_horzOk", "_dir", "_headingPitch"];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user