Jump to content
  • 0
TolH

typeOF player !=

Question

Hello,

i have been trying to give different loadout depending on what typeOF player you select at the server slot selection.

Everything works just fine if i select a normal "VirtualMan_EPOCH" slot. It's when i select "B_sniper_F" or "B_Helipilot_F" that the script is skipping part.

I don't get any error on my .rpt but it seems that the script is skipping a couple of line before ending.

So if i select for exemple (typeOf player != "B_sniper_F"), then it will go trough the code but will be skipping those lines:

    player setpos _pos1;
    player enableFatigue false;
    waitUntil{!isNull (findDisplay 46) && !dialog && cameraOn isEqualTo player && cameraView == "INTERNAL"};
    player switchCamera "EXTERNAL";
    HALV_takegive = [player,150];
    publicVariableServer "HALV_takegive";

Then the script will continue to the next part that is the "check" to see if player is either Epoch, sniper or pilot.

It's as if the script is executed before the player as spanwed on the map and don't have time to execute the first couple of line. Any help would be really appreciated to know why some of the line are skipped but not others.

This is the script i made:

Line to check are:

# //waitUntil {typeOF player != "VirtualMan_EPOCH" or typeOf player != "B_sniper_F" or typeOf player != "B_Helipilot_F"};

This is the part that is skipped on script execution:

#   player setpos _pos1;
    player enableFatigue false;
    waitUntil{!isNull (findDisplay 46) && !dialog && cameraOn isEqualTo player && cameraView == "INTERNAL"};
    player switchCamera "EXTERNAL";
    HALV_takegive = [player,150];
    publicVariableServer "HALV_takegive";

private ["_adminlist"];
//-
waitUntil {alive vehicle player}; 
//waitUntil {typeOF player != "VirtualMan_EPOCH" or typeOf player != "B_sniper_F" or typeOf player != "B_Helipilot_F"};
waitUntil {typeOF player != "VirtualMan_EPOCH"};
//-
_pos1 = [14636.907, 16770.1, 0.00143814];
//_adminlist = ["xx","xx","xx","xx","xx","xx"];

//--------------------------------------------------------------------//
if ((EPOCH_playerAliveTime < 0.1) && (EPOCH_playerCrypto < 1)) then 
{
	//spawning_script = [] execVM "custom\spawn.sqf";
	//waitUntil {scriptDone spawning_script};
	player setpos _pos1;
	player enableFatigue false;
	waitUntil{!isNull (findDisplay 46) && !dialog && cameraOn isEqualTo player && cameraView == "INTERNAL"};
	player switchCamera "EXTERNAL";
	HALV_takegive = [player,150];
	publicVariableServer "HALV_takegive";
	/*	if (typeOf player == "VirtualMan_EPOCH") then 
		{
			systemchat "YOU ARE A NORMAL EPOCH PLAYER, TEST!";
		};
		if (typeOf player == "B_sniper_F") then 
		{
			systemchat "YOU ARE A SNIPER, TEST!";
		};
		if (typeOf player == "B_Helipilot_F") then 
		{
			systemchat "YOU ARE A PILOT, TEST!";
		};*/
/*	//For Admin ASORGS Gear Selector
	if ((getPlayerUID player) in _adminlist) then 
	{ 
		systemchat " -=ADMIN=- Detected: -Gear selector loaded. Type !gear to access it.-";
		//player addAction ["<t color='#6a8a19'>Gear Selector</t>", "ASORGS\open.sqf", "", 0, true, true, "", ""];
	};*/
}
else
{
	systemchat "Welcome back!";
	player enableFatigue false;
	waitUntil{!isNull (findDisplay 46) && !dialog && cameraOn isEqualTo player && cameraView == "INTERNAL"};
	player switchCamera "EXTERNAL";
	/*	if (typeOf player == "VirtualMan_EPOCH") then 
		{
			systemchat "YOU ARE A NORMAL EPOCH PLAYER, TEST!";
		};
		if (typeOf player == "B_sniper_F") then 
		{
			systemchat "YOU ARE A SNIPER, TEST!";
		};
		if (typeOf player == "B_Helipilot_F") then 
		{
			systemchat "YOU ARE A PILOT, TEST!";
		};*/
/*	//For Admin ASORGS Gear Selector
	if ((getPlayerUID player) in _adminlist) then 
	{ 
		systemchat " -=ADMIN=- Detected: -Gear selector loaded. Type !gear to access it.-";
		//player addAction ["<t color='#6a8a19'>Gear Selector</t>", "ASORGS\open.sqf", "", 0, true, true, "", ""];
	};*/
};
//--------------------------------------------------------------------//
Edited by TolH

Share this post


Link to post
Share on other sites

38 answers to this question

Recommended Posts

  • 0

Which one is faster, highly depends on the syntax that is used and the return!

7c7761ddf498d8faa1b5f701a2270001.png < c06e3f07e63c48a1802c7d5bc94da495.png

3856c71c78a491b2cb69c6d1b1f628a3.png > 2bae415b9a787616809bc2cb9a3c086a.png

I recommend to use == in this case, because comparing two strings with == is not case sensitive and when using classNames, you don't really need to check case sensitive and you also don't need to write the ClassName with the exact Upper/Lowercase letters, which allows you to code much faster than when you have to look up each exact className that is returned, just for a simple comparison in a simple line of a script.

https://community.bistudio.com/wiki/Code_Optimisation

Make it work.

"Premature optimization is the root of all evil."
Donald Knuth

No need to worry about making it work at light speed if it doesn't even do what it is supposed to. Focus on getting a working product first.

Make it fast.

Optimisation is everything when running lots of instances, with low delays. However, there is such thing as premature optimisation. Also, avoid excessive cleverness.

"Excessive cleverness is doing something in a really clever way when actually you could have done it in a much more straightforward but slightly less optimal manner. You've probably seen examples of people who construct amazing chains of macros (in C) or bizarre overloading patterns (in C++) which work fine but which you look at an go "wtf"? EC is a variation of premature-optimisation. It's also an act of hubris - programmers doing things because they want to show how clever they are rather than getting the job done." - sbsmac

 

You guys can optimise your scripts as much as you want, but in this case it is already a waste of time to even consider a "optimization", not even talking about starting an argument over it.
Focus on working code first, then make it readable and if (a big "IF") it performs worse, look up how you could possibly optimize it.
Don't waste more than 2x the time you needed to write a script into optimizing it.
If you need more time, then you should probably rewrite it completely or just move on to another script, and come back to rewrite it later on with a "clear" head.

 

Edited by KiloSwiss

Share this post


Link to post
Share on other sites
  • 0

I was eating popcorn the whole time. But because of Halv's very mature answers I spilled it all over the keyboard out of laughter.

im sorry to break it to you, but you are the laughing stock here ... 

just to break down waht kiloswiss said here for you, (wich is what i said all along):

if you are comparinging anything but strings isEqualTo is faster.

if you are comparing strings, except for exact matching strings == is faster.

but hey, ignorant people will be ignorant ... you are a good example.

ignorance.jpg

Share this post


Link to post
Share on other sites
  • 0

Which one is faster, highly depends on the syntax that is used and the return!

7c7761ddf498d8faa1b5f701a2270001.png < c06e3f07e63c48a1802c7d5bc94da495.png

you cannot evaluate code that does nothing, not to mention the first case returns false where the last case returns true wich for obvius reasons distorts the end result.

Share this post


Link to post
Share on other sites
  • 0

Yes you can, because It does not nothing, it uses "isEqualTo" or "==" to make a comparison between two strings, resulting in a bool and since you want to compare the performance between those two, adding additional "workload" in form of a hint or other code, will have an effect on the end result that might end up like my examples.
The hidden hint in these four pictures was: If you add something to the "naked" comparison, it will most likely mess up the results.

And as I already mentioned:

Which one is faster, highly depends on the syntax that is used and the return!

We can continue to compare code snippets with different results (both true, only one true and the other false, etc.) but as I already wrote it is not worth the time.

Edited by KiloSwiss

Share this post


Link to post
Share on other sites
  • 0

Yes you can, because It does not nothing, it uses "isEqualTo" or "==" to make a comparison between two strings, resulting in a bool and since you want to compare the performance between those two, adding additional "workload" in form of a hint or other code, will have an effect on the end result that might end up like my examples.
The hidden hint in these four pictures was: If you add something to the "naked" comparison, it will most likely mess up the results.

And as I already mentioned:

We can continue to compare code snippets with different results (both true, only one true and the other false, etc.) but as I already wrote it is not worth the time.

{} is not a bool, thats nil, had you used {true} then it returns a bool.

when comparing code for speed optimization, you should always compare equal results(as in both should return true or both return false), or the result will obviusly be distorted like in your case one returns false and the other returns true, thats like comparing apples and oranges.

its a good idea to add something for the code to do upon completion, that will takes close to same time to perform (like a hintSilent or text in chat). this will help stabilize the results.

using something like hint is a bad idea as it has a sound that can take variable times to fetch/perform (especially on a lesser system), hence it will distort the result.

however i do agree with you on the part where you say == should (in most cases anyway) be used for strings, isEqualTo is best used with anything else.

imo it is always best to aim for getting the fastest / most optimized code possible, obviusly this causes some ppl to complicate simple things in attempts to speed up the process, however imo simple is always better (tho simple rarely gives the initially intended result).

Share this post


Link to post
Share on other sites
  • 0
«help stabilize the results» by adding additional "workload" to the script.
According to that logic:
If you want to make a taste comparison between Pepsi and Coke, better mix some Rum (Or Jack, or whatever) into it, to "help stabilize the results"...
I'm also not talking about any returns, only about the part between the ():
if ( boolean ) then {};

8f223264325f6709870cae30220f3d35.png f2c6ce254af04523f96d77082379368d.png

No Photoshop, just run both "codes" 5 times and made a screenshot at the last one!
The results for both tests varied between 0.0019... and 0.0022... ms

/edit
I edited this post 20 times now because I'm trying to figure out, why this forum is messing up with the formatting of my post?

Where is the "classic" view, where you can add/remove all those CODE, B, I, QUOTE, URL etc. tags manually?

Edited by KiloSwiss

Share this post


Link to post
Share on other sites
  • 0
«help stabilize the results» by adding additional "workload" to the script.
According to that logic:
If you want to make a taste comparison between Pepsi and Coke, better mix some Rum (Or Jack, or whatever) into it, to "help stabilize the results"...

thats not exactly how it works, but i see why you could be confused here ...

ill try to explain so you can better understand:

as an example you can messure the wieght of something light on a large scale, often that will return a distorted result. however add a large weight to the scale and deduct the weight added after and you will get a more percise result.

same applys in this case as in adding a constant time to the small amount that is there, will help stabilize the end result, so you can easier differ between them.

I'm also not talking about any returns, only about the part between the ():

when you messure the time it takes for code to complete, it should ideally return something or it is not a true test.

 

No Photoshop, just run both "codes" 5 times and made a screenshot at the last one!
The results for both tests varied between 0.0019... and 0.0022... ms

this returns true and can be considdered a true test, however the scope is so light that the diffrence can barely be messured, hence why you should add some load to get a more stable result.

/edit
I edited this post 20 times now because I'm trying to figure out, why this forum is messing up with the formatting of my post?

Where is the "classic" view, where you can add/remove all those CODE, B, I, QUOTE, URL etc. tags manually?

i would love that aswell

Share this post


Link to post
Share on other sites
  • 0

Thanks for the replies guys, what i was trying to do is to have different skins depending on the screen selecting slot you select before getting in the game so in-game i could have restricted some vehicle/weapon and such depending on the modeltype player has from that selected slot.

exemple:
            side="WEST";
                    position[]={23601.15,3.1900001,18004.951};
                    azimut=130.01601;
                    special="NONE";
                    id=0;
                    side="WEST";
                    vehicle="B_sniper_F";
                    player="PLAY CDG";
                    leader=1;
                    skill=0.60000002;

But epoch overwrite the type of player on respawn to female or male model. Was an easy fix to find what slot the player has taken.

### Wanted to do it because i don't know how to check the slot number without a different model in there.

### So a better question would be, If for exemple i want to choose the slot let's say number 9 from the player selection, how would i go about it to find out that the player is in fact in the slot #9  Without knowing it's model. Maybe by group name "Alpha 1-1-1 or something like that ? setGroupId

 

 

EDIT: figured it out for the timer, ignore the rest of the post.

Also, if i may, i would have another question not related to this topic but about a mission i am making and it's about a simple timer.

This is the undone mission:

 

//============================================////============================================//
private ["_Missionmarker1","_towns","_RandomTownPosition","_MoreRandomTownPosition","_spawnRandomisation","_spwnposNew","_SPWradioTower","_TowerMarker"];
//============================================////============================================//
	//MISSION RUNNING CHECK
		mission_isrunning = 1;
		diag_log "-=NORRY=-: Mission -Invasion.sqf- Started";
	//TEST SPAWN AT A RANDOM Village, City or CityCapital //"Rydygier"
		_towns = nearestLocations [position player, ["NameVillage","NameCity","NameCityCapital"], 40000];
		_RandomTownPosition = position (_towns select (floor (random (count _towns))));
	//optional also for more randomization:
		_posX = (_RandomTownPosition select 0) + (random 200) - (random 200);
		_posY = (_RandomTownPosition select 1) + (random 200) - (random 200);
		_MoreRandomTownPosition = [_posX,_posY,0];
//============================================////============================================//
	//CREATE MARKER
		//CREATE MAIN MISSION MARKER
		_Missionmarker1 = createMarker ["Missionmarker1", _MoreRandomTownPosition];
		"Missionmarker1" setMarkerColor "ColorRed";
		"Missionmarker1" setMarkerShape "ELLIPSE";
		"Missionmarker1" setMarkerBrush "SolidFull";
		"Missionmarker1" setMarkerSize [1200,1200];
		"Missionmarker1" setMarkerAlpha 0.2;
//============================================////============================================//
	//RANDOMISATION FOR TOWER POSITION RADIUS
		_spawnRandomisation=1000; //1000m
		_spwnposNew = [(getMarkerPos "Missionmarker1"),random _spawnRandomisation, random 360] call BIS_fnc_relPos;
	//CREATE RADIOTOWER
		_SPWradioTower = "Land_TTowerBig_2_F" createVehicle _spwnposNew;
		waitUntil {uiSleep 1; alive _SPWradioTower};
		_SPWradioTower setVectorUp [0,0,1];
	//MARKER AT RADIOTOWER
		_TowerMarker = createMarker ["Radio-Tower", getPos _SPWradioTower];
		"Radio-Tower" setMarkerColor "ColorYellow";
		"Radio-Tower" setMarkerType "loc_Transmitter";
		"Radio-Tower" setMarkerText " -=RadioTower=-";
//============================================////============================================//
	//MESSAGE
		_targetStartText = "<t align='center' size='2.2'>New Target</t><br/><t size='1.5' color='#08b000' align='center'>Town Invasion Started</t><br/>____________________<br/>We did a good job with the last target, lads. I want to see the same again.<br/><br/><t size='1.2' color='#08b000' align='center'> Get yourselves over to the invaded town and take 'em all down!</t><br/>";
		GlobalHint = _targetStartText; publicVariable "GlobalHint"; hint parseText GlobalHint;
		showNotification = ["NewMain", "The Resistance has invaded a nearby town"]; publicVariable "showNotification";
		//WAIT 12 SECONDS BEFORE SENDING NEXT MESSAGE
		uiSleep 12;
		showNotification = ["NewSub", "Destroy the enemy radio tower."]; publicVariable "showNotification";	
//============================================////============================================//
	//ADDING AI GROUP
	//GROUND UNIT
		//GROUPID = 1 
		nul_script1 = ["Missionmarker1",3,800,[true,false],[false,false,false],false,[30,0],[0,0],"default",nil,nil,1] execVM "NorryMissions\LV\militarize.sqf";
		waitUntil {scriptDone nul_script1};
	//GROUND VEHICLE UNIT
		//GROUPID = 2 
		nul_script2 = ["Missionmarker1",3,950,[false,false],[true,false,false],false,[0,0],[3,0],"default",nil,nil,2] execVM "NorryMissions\LV\militarize.sqf";
		waitUntil {scriptDone nul_script2};
	//AIR VEHICLE UNIT
		//GROUPID = 3 
		nul_script3 = ["Missionmarker1",3,1200,[false,false],[false,false,true],false,[0,0],[2,0],"default",nil,nil,3] execVM "NorryMissions\LV\militarize.sqf";
		waitUntil {scriptDone nul_script3};
	//FILLHOUSE SCRIPT
		//GROUPID = 4 
		nul_script4 = ["Missionmarker1",3,true,2,[15,0],1000,"default",nil,nil,4] execVM "NorryMissions\LV\fillHouse.sqf";
		waitUntil {scriptDone nul_script4};
	//RADIOTOWER GROUND UNIT
		//GROUPID = 5 
		nul_script5 = ["Radio-Tower",3,100,[true,false],[false,false,false],false,[20,0],[0,0],"default",nil,nil,5] execVM "NorryMissions\LV\militarize.sqf";
		waitUntil {scriptDone nul_script5};
//============================================////============================================//
	//START TIMER
	//SEND REINFORCEMENT AFTER A WHILE IF TOWER IS STILL UP AND AT LEAST ONE PLAYER LOGGED IN
	_count = 0;
	//_playerCount = {alive _x} count playableUnits;
		while {alive _SPWradioTower} do 
		{
			//wait for timer while loop method
			while {_count < 1800} do 
			{
				_count = _count + 1;
				uiSleep 1;
			};
			//SEND REINFORCMENT #1
			if (_count == 900) then 
			{
				showNotification = ["RadioTowerCAS", "The resistance called air support! Get that tower down."]; publicVariable "showNotification";
				//AIR VEHICLE UNIT
					//GROUPID = 6 
					nul_script6 = ["Missionmarker1",3,1600,[false,false],[false,false,true],false,[0,0],[1,0],"default",nil,nil,6] execVM "NorryMissions\LV\militarize.sqf";
					waitUntil {scriptDone nul_script6};
			};
			//SEND REINFORCMENT #2
			if (_count == 1800) then 
			{
				showNotification = ["RadioTowerCAS", "The resistance called air support! Get that tower down."]; publicVariable "showNotification";
				//AIR VEHICLE UNIT
					//GROUPID = 7 
					nul_script7 = ["Missionmarker1",3,1600,[false,false],[false,false,true],false,[0,0],[2,0],"default",nil,nil,7] execVM "NorryMissions\LV\militarize.sqf";
					waitUntil {scriptDone nul_script7};
			};
			if (_count >= 1801) then 
			{
				uiSleep 1;
			};
		};
//============================================////============================================//
	//RADIOTOWER DESTROYED, UPDATE RADIOTOWER MARKER
		waitUntil {uiSleep 5; !alive _SPWradioTower};
		diag_log format ["-=NORRY=-: Mission -Invasion.sqf- TOWER DESTROYED"];
		"Radio-Tower" setMarkerColor "ColorGrey";
		"Radio-Tower" setMarkerType "loc_Transmitter";
		"Radio-Tower" setMarkerText " -=RadioTower=- Destroyed";
		uiSleep 5;
		_wreck = getMarkerPos "Radio-Tower" nearestObject "Land_TTowerBig_2_ruins_F";
//============================================////============================================//
	//MESSAGE
		_radioTowerDownText = "<t align='center' size='2.2'>Sub Objective</t><br/><t size='1.5' color='#08b000' align='center'>RadioTower Deactivated!</t><br/>____________________<br/>The enemy radio tower has been destroyed! Well done.<br/><br/><t size='1.2' color='#08b000' align='center'> The enemy cannot call in air support now!</t><br/>";
		GlobalHint = _radioTowerDownText; hint parseText GlobalHint; publicVariable "GlobalHint";
		showNotification = ["CompletedSub", "Enemy radio tower destroyed!"]; publicVariable "showNotification";
//============================================////============================================//
	//MISION ON HOLD UNTIL 10 ENNEMIES IS LEFT
		_AiCount = resistance countSide allunits;
		diag_log format ["RESISTANCE AI NUMBER IS -=%1=-", _AiCount];
		waitUntil {uiSleep 5; _AiCount <= 50};
//============================================////============================================//
	//MESSAGE
		_targetCompleteText = "<t align='center' size='2.2'>Main Objective</t><br/><t size='1.5' color='#08b000' align='center'>The Resistance has been wiped out!!!</t><br/>____________________<br/>Fantastic job, lads!<br/><br/><t size='1.2' color='#08b000' align='center'> Give us a moment here at HQ and we'll line up your next target for you.</t><br/>";
		GlobalHint = _targetCompleteText; hint parseText GlobalHint; publicVariable "GlobalHint";
		showNotification = ["CompletedMain", "Town taken back."]; publicVariable "showNotification";
//============================================////============================================//
	//WAIT X SECONDS BEFORE DELETING EVERYTHING FOR NOW
		uiSleep 60;
	//MISSION ENDED, DELETING EVERYTHING
		//DELETE GROUP ID 1
			nul_script1	= [LVgroup1] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeGroup.sqf";
			waitUntil {scriptDone nul_script1};
		//DELETE GROUP ID 2
			nul_script2	= [LVgroup2] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeGroup.sqf";
			waitUntil {scriptDone nul_script2};
		//DELETE GROUP ID 3
			nul_script3	= [LVgroup3] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeGroup.sqf";
			waitUntil {scriptDone nul_script3};
		//DELETE GROUP ID 4
			nul_script4	= [LVgroup4] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeGroup.sqf";
			waitUntil {scriptDone nul_script4};
		//DELETE GROUP ID 5
			nul_script5	= [LVgroup5] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeGroup.sqf";
			waitUntil {scriptDone nul_script5};
		//DELETE GROUP ID 6
			nul_script6	= [LVgroup6] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeGroup.sqf";
			waitUntil {scriptDone nul_script6};
		//DELETE GROUP ID 7
			nul_script7	= [LVgroup7] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeGroup.sqf";
			waitUntil {scriptDone nul_script7};
		//DELETE DEAD BODY
			nul_script8 = [1500,playableUnits] execVM "NorryMissions\LV\LV_functions\LV_fnc_removeDead.sqf";
		//DELETE TOWER+WRECK
			deleteVehicle _SPWradioTower;
			deletevehicle _wreck;
		//DELETE MARKER
			deleteMarker "Missionmarker1";
			deleteMarker "Radio-Tower";
//============================================////============================================//
	//MISSION ENDED
		diag_log "-=NORRY=-: Mission -Invasion.sqf- Ended";
		//MISSION ENDED CHECK
			mission_isrunning = 0;
//============================================////============================================//

 

Problem is in the timer, one check pass and the other doesn't:

 

//============================================////============================================//
	//START TIMER
	//SEND REINFORCEMENT AFTER A WHILE IF TOWER IS STILL UP AND AT LEAST ONE PLAYER LOGGED IN
	_count = 0;
	//_playerCount = {alive _x} count playableUnits;
		while {alive _SPWradioTower} do 
		{
			//wait for timer while loop method
			while {_count < 1800} do 
			{
				_count = _count + 1;
				uiSleep 1;
			};
			//SEND REINFORCMENT #1
			if (_count == 900) then 
			{
				showNotification = ["RadioTowerCAS", "The resistance called air support! Get that tower down."]; publicVariable "showNotification";
				//AIR VEHICLE UNIT
					//GROUPID = 6 
					nul_script6 = ["Missionmarker1",3,1600,[false,false],[false,false,true],false,[0,0],[1,0],"default",nil,nil,6] execVM "NorryMissions\LV\militarize.sqf";
					waitUntil {scriptDone nul_script6};
			};
			//SEND REINFORCMENT #2
			if (_count == 1800) then 
			{
				showNotification = ["RadioTowerCAS", "The resistance called air support! Get that tower down."]; publicVariable "showNotification";
				//AIR VEHICLE UNIT
					//GROUPID = 7 
					nul_script7 = ["Missionmarker1",3,1600,[false,false],[false,false,true],false,[0,0],[2,0],"default",nil,nil,7] execVM "NorryMissions\LV\militarize.sqf";
					waitUntil {scriptDone nul_script7};
			};
			if (_count >= 1801) then 
			{
				uiSleep 1;
			};
		};
//============================================////============================================//

 

!! This check does not work   if (_count == 900) then

But this one  work      if (_count == 1800) then

I would really appreciate once again any replies that could help me understand why the first IF doesn't work and the second IF does work !?

 

Thank you!! :D

Edited by TolH

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.

  • Advertisement
  • Supporters
  • Discord

×
×
  • Create New...