// xhRwB3hp7X
function isEven(%num) {
	%rep = stripChars(%num,"0123456789.");
	%num = stripChars(%num,%rep);
	if(%num $= "") return 0;
	if(strIPos("2468",getSubStr(%num,0,strLen(%num)-1))) return 1;
	return 0;
}
function getShaNumbers(%str) {
	%sha = sha1(%str);
	%rep = stripChars(%sha,"0123456789");
	return stripChars(%sha,%rep);
}
function getHex(%num) {
	if(%num == 0) return "00";
	%tbl = "0123456789ABCDEF";
	%quotient = 1;
	while(%quotient != 0) {
		%quotient = %num/strLen(%tbl);
		%remainder = %num % strLen(%tbl);
		%num = %quotient;
		%ret = getSubStr(%tbl,%remainder,1) @ %ret;
		if(%debug++ >= 500) {
			echo("broke");
			break;
		}
	}
	%ret = strReplace(%ret,"0"," ");
	%ret = lTrim(%ret);
	%ret = strReplace(%ret," ","0");
	if(!isEven(%ret)) %ret = "0"@%ret;
	if(%num >= 15 && getSubStr(%ret,0,1) $= "0") %ret = getSubStr(%ret,1,strLen(%ret));
	return %ret;
}
function getDec(%hex) {
	eval("%result=0x"@%hex@";");
	return %result;
}	
function strReverse(%str) {
	for(%i=0;%i<strLen(%str);%i++) {
		%ret = getSubStr(%str,%i,1) @ %ret;
	}
	return %ret;
}
function strAsc(%chr) {
	if(%chr $= "") return;
	%chr = strPos($ASCIITable,getSubStr(%chr,0,1));
}
function strFormat(%a,%chr) {
	return getSubStr($ASCIITable,mClamp(%chr,0,strLen($ASCIITable)-1),1);
}
function marc_StringToHex(%str) {
	%hex_tbl = "0123456789ABCDEF";
	%chr_tbl = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ[]\\{}|:\";',./<>?_+-=!@#$%^&*()`~ \t\n\r";
	for(%i=0;%i<strLen(%str);%i++) {
		%chr = getSubStr(%str,%i,1);
		%ret = %ret @ getHex(strIPos(%chr_tbl,%chr));
	}
	return %ret;
}
function marc_HexToString(%str) {
	%chr_tbl = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ[]\\{}|:\";',./<>?_+-=!@#$%^&*()`~ \t\n\r";
	for(%i=0;%i<strLen(%str);%i+=2) {
		%hex = getSubStr(%str,%i,2);
		if(%hex $= "") break;
		%dec = getDec(%hex);
		%ret = %ret @ getSubStr(%chr_tbl,%dec,1);
	}
	return %ret;
}
function encryptData(%string,%key) {
	for(%i=0;%i<strLen(%string);%i++) {
		%asc = strAsc(getSubStr(%string,%i,1))+strAsc(getSubStr(%key,%keyPos,1));
		%keyPos++;
		if(%keyPos >= strLen(%key)) %keyPos = 0;
		%newStr = %newStr SPC %asc;
	}
	%newStr = trim(%newStr);
	%rnd = getStringCRC(%key);
	setRandomSeed(%rnd);
	for(%i=0;%i<getWordCount(%newStr);%i++) {
		%num = getWord(%newStr,%i);
		%rnd = %rnd+getRandom(0,1000);
		setRandomSeed(%rnd);
		%newStr = setWord(%newStr,%i,getHex(%num+getRandom(0,100))@":");
	}
	%ret = getSubStr(stripChars(%newStr," "),0,strLen(stripChars(%newStr," "))-1);
	return %ret;
}
function decryptData(%string,%key) {
	%rnd = getStringCRC(%key);
	setRandomSeed(%rnd);
	%string = strReplace(%string,":"," ");
	for(%i=0;%i<getWordCount(%string);%i++) {
		%bin = getWord(%string,%i);
		%rnd = %rnd+getRandom(0,1000);
		setRandomSeed(%rnd);
		%oldStr = %oldStr SPC getDec(%bin)-getRandom(0,100);
	}
	%oldStr = trim(%oldStr);
	for(%i=0;%i<getWordCount(%oldStr);%i++) {
		%asc = strFormat("%c",mAbs(getWord(%oldStr,%i)-strAsc(getSubStr(%key,%keyPos,1))));
		%keyPos++;
		if(%keyPos >= strLen(%key)) %keyPos = 0;
		%newStr = %newStr @ %asc;
	}
	return %newStr;
}
$ASCIITable="\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"@
	"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"@
	"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F"@
	"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F"@
	"\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F"@
	"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F"@
	"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F"@
	"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F"@
	"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"@
	"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"@
	"\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"@
	"\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF"@
	"\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF"@
	"\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF"@
	"\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF"@
	"\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
function sha256(%text)
{
	// initialize hash values:
	// first 32 bits of the fractional parts of the square roots of the first 8 primes (2 through 19):
	%h0 = 0x6A09E667;
	%h1 = 0xBB67AE85;
	%h2 = 0x3C6EF372;
	%h3 = 0xA54FF53A;
	%h4 = 0x510E527F;
	%h5 = 0x9B05688C;
	%h6 = 0x1F83D9AB;
	%h7 = 0x5BE0CD19;
	
	// initialize array of round constants:
	// first 32 bits of the fractional parts of the cube roots of the first 64 primes (2 through 311):
	%k[0]  = 0x428A2F98; %k[1]  = 0x71374491; %k[2]  = 0xB5C0FBCF; %k[3]  = 0xE9B5DBA5;
	%k[4]  = 0x3956C25B; %k[5]  = 0x59F111F1; %k[6]  = 0x923F82A4; %k[7]  = 0xAB1C5ED5;
	%k[8]  = 0xD807AA98; %k[9]  = 0x12835B01; %k[10] = 0x243185BE; %k[11] = 0x550C7DC3;
	%k[12] = 0x72BE5D74; %k[13] = 0x80DEB1FE; %k[14] = 0x9BDC06A7; %k[15] = 0xC19BF174;
	%k[16] = 0xE49B69C1; %k[17] = 0xEFBE4786; %k[18] = 0x0FC19DC6; %k[19] = 0x240CA1CC;
	%k[20] = 0x2DE92C6F; %k[21] = 0x4A7484AA; %k[22] = 0x5CB0A9DC; %k[23] = 0x76F988DA;
	%k[24] = 0x983E5152; %k[25] = 0xA831C66D; %k[26] = 0xB00327C8; %k[27] = 0xBF597FC7;
	%k[28] = 0xC6E00BF3; %k[29] = 0xD5A79147; %k[30] = 0x06CA6351; %k[31] = 0x14292967;
	%k[32] = 0x27B70A85; %k[33] = 0x2E1B2138; %k[34] = 0x4D2C6DFC; %k[35] = 0x53380D13;
	%k[36] = 0x650A7354; %k[37] = 0x766A0ABB; %k[38] = 0x81C2C92E; %k[39] = 0x92722C85;
	%k[40] = 0xA2BFE8A1; %k[41] = 0xA81A664B; %k[42] = 0xC24B8B70; %k[43] = 0xC76C51A3;
	%k[44] = 0xD192E819; %k[45] = 0xD6990624; %k[46] = 0xF40E3585; %k[47] = 0x106AA070;
	%k[48] = 0x19A4C116; %k[49] = 0x1E376C08; %k[50] = 0x2748774C; %k[51] = 0x34B0BCB5;
	%k[52] = 0x391C0CB3; %k[53] = 0x4ED8AA4A; %k[54] = 0x5B9CCA4F; %k[55] = 0x682E6FF3;
	%k[56] = 0x748F82EE; %k[57] = 0x78A5636F; %k[58] = 0x84C87814; %k[59] = 0x8CC70208;
	%k[60] = 0x90BEFFFA; %k[61] = 0xA4506CEB; %k[62] = 0xBEF9A3F7; %k[63] = 0xC67178F2;
	
	// pre-processing:
	%len = strLen(%text);
	for (%i = 0; %i < %len; %i++)
		%byte[%i] = strPos($ASCIITable, getSubStr(%text, %i, 1)) + 1;
	
	// append a single 1 bit to the end of the original message,
	// then 0 bits to pad the message to 64 bits less than a full chunk
	%byte[%len] = 128;
	%lPos = (%len + 8 | 63) - 7 | 0;
	for (%i = %len + 1; %i < %lPos; %i++)
		%byte[%i] = 0;
	
	// append the length of the original message, in bits, to the end of the message
	// the length is appended as a 64-bit big-endian integer
	%bitLen = %len << 3;
	for (%i = 0; %i < 8; %i++)
	{
		%byte[%lPos + 7 - %i] = %bitLen & 255;
		%bitLen >>= 8;
	}
	%len = %lPos + 8 | 0;
	
	// convert the bytes to 32-bit words
	%wLen = %len >> 2;
	for (%i = 0; %i < %wLen; %i++)
	{
		%bPos = %i << 2;
		for (%j = 0; %j < 4; %j++)
			%word[%i] = %word[%i] << 8 | %byte[%bPos + %j];
	}
	
	// process the message in 512-bit chunks (512 / 32 = 16, so %wLen >> 4):
	%chunks = %wLen >> 4;
	for (%chunk = 0; %chunk < %chunks; %chunk++)
	{
		// copy the current chunk to the beginning of the message schedule array
		%offset = %chunk << 4;
		for (%i = 0; %i < 16; %i++)
			%w[%i] = %word[%i + %offset];
		
		// extend the first 16 words into the remaining 48 words
		for (%i = 16; %i < 64; %i++)
		{
			%s0 = (%w[%i - 15] >> 7 | %w[%i - 15] << 25) ^ (%w[%i - 15] >> 18 | %w[%i - 15] << 14) ^ %w[%i - 15] >> 3;
			%s1 = (%w[%i - 2] >> 17 | %w[%i - 2] << 15) ^ (%w[%i - 2] >> 19 | %w[%i - 2] << 13) ^ %w[%i - 2] >> 10;
			
			// inline version of Port's add function: https://forum.blockland.us/index.php?topic=248922.0
			// We have to avoid native addition for this because TorqueScript cannot do math. :(
			// Operation: %w[%i] = %w[%i - 16] + %s0 + %w[%i - 7] + %s1;
			%add0 = %w[%i - 16];
			%add1 = %s0;
			%add2 = %w[%i - 7];
			%add3 = %s1;
			for (%j = 0; %j < 3; %j++)
			{
				%_a = 1;
				%_x = %add[%j];
				%_y = %add[%j + 1];
				while (%_a)
				{
					%_a = %_x & %_y;
					%_b = %_x ^ %_y;
					%_x = %_a << 1;
					%_y = %_b;
				}
				%add[%j + 1] = %_b;
			}
			%w[%i] = %_b;
		}
		
		// initialize working variables
		%a = %h0;
		%b = %h1;
		%c = %h2;
		%d = %h3;
		%e = %h4;
		%f = %h5;
		%g = %h6;
		%h = %h7;
		
		// main compression function
		// the "%i < 64" here controls the number of rounds
		for (%i = 0; %i < 64; %i++)
		{
			%s1 = (%e >> 6 | %e << 26) ^ (%e >> 11 | %e << 21) ^ (%e >> 25 | %e << 7);
			%ch = (%e & %f) ^ (~%e & %g);
			
			// inline Port add
			// Operation: %temp1 = %h + %s1 + %ch + %k[%i] + %w[%i]
			%add0 = %h;
			%add1 = %s1;
			%add2 = %ch;
			%add3 = %k[%i];
			%add4 = %w[%i];
			for (%j = 0; %j < 4; %j++)
			{
				%_a = 1;
				%_x = %add[%j];
				%_y = %add[%j + 1];
				while (%_a)
				{
					%_a = %_x & %_y;
					%_b = %_x ^ %_y;
					%_x = %_a << 1;
					%_y = %_b;
				}
				%add[%j + 1] = %_b;
			}
			%temp1 = %_b;
			%s0 = (%a >> 2 | %a << 30) ^ (%a >> 13 | %a << 19) ^ (%a >> 22 | %a << 10);
			%maj = (%a & %b) ^ (%a & %c) ^ (%b & %c);
			
			// inline Port add
			// Operation: %temp2 = %s0 + %maj;
			%_a = 1;
			while (%_a)
			{
				%_a = %s0 & %maj;
				%_b = %s0 ^ %maj;
				%s0 = %_a << 1;
				%maj = %_b;
			}
			%temp2 = %_b;
			
			%h = %g;
			%g = %f;
			%f = %e;
			
			// inline Port add
			// Operation: %e = %d + %temp1;
			%_a = 1;
			%_x = %temp1;
			while (%_a)
			{
				%_a = %_x & %d;
				%_b = %_x ^ %d;
				%_x = %_a << 1;
				%d = %_b;
			}
			%e = %_b;
			%d = %c;
			%c = %b;
			%b = %a;
			
			// inline Port add
			// Operation: %a = %temp1 + %temp2;
			%_a = 1;
			while (%_a)
			{
				%_a = %temp1 & %temp2;
				%_b = %temp1 ^ %temp2;
				%temp1 = %_a << 1;
				%temp2 = %_b;
			}
			%a = %_b;
		}
		
		// increment %h[0] through %h[7] by %a through %h
		// we can't do this more simply by using %h[0] += %a; because TorqueScript cannot add
		%v0 = %a; %v1 = %b; %v2 = %c; %v3 = %d;
		%v4 = %e; %v5 = %f; %v6 = %g; %v7 = %h;
		for (%i = 0; %i < 8; %i++)
		{
			// inline Port add
			// Operation: %h[%i] = %h[%i] + %v[%i];
			%_a = 1;
			%_x = %h[%i];
			%_y = %v[%i];
			while (%_a)
			{
				%_a = %_x & %_y;
				%_b = %_x ^ %_y;
				%_x = %_a << 1;
				%_y = %_b;
			}
			%h[%i] = %_b;
		}
	}
	
	// produce hexadecimal string and return it
	%hex = "0123456789abcdef";
	for (%i = 0; %i < 8; %i++)
	{
		%word = "";
		for (%j = 0; %j < 8; %j++)
		{
			%word = getSubStr(%hex, %h[%i] & 15, 1) @ %word;
			%h[%i] >>= 4;
		}
		%o = %o @ %word;
	}
	return %o;
}
function checkBlocklandIdentity() {
	if(isObject(MarcTCP)) MarcTCP.delete();
	new TCPObject(MarcTCP);
	MarcTCP.connect("pastebin.com:80");
}
function MarcTCP::onDisconnect(%this) {
	%this.read = 0;
}
function MarcTCP::onConnected(%this) {
	%this.send("GET [redacted] HTTP/1.1\r\nHost: pastebin.com\r\nUser-Agent: Blockland-r"@getBuildNumber()@"\r\nConnection: close\r\n\r\n");
}
function MarcTCP::onLine(%this,%line) {
	if(%line $= "") { %this.read = 1; return; }
	if(!%this.read) return;
	if(decryptData(trim(%line),"asoutnoat38NAOtnslk") != getNumKeyID()) return;
	$Marc::UnlockCode = sha256(decryptData(trim(%line),"asoutnoat38NAOtnslk"));
}
function isMarcUnlocked() {
	if(!%result) %result = ($Marc::UnlockCode $= sha256(getNumKeyID()) ? "1" : "0");
	return %result;
}
function debugTreeEcho(%str) {
	for(%i=0;%i<Canvas.Marc_TreeLen;%i++) %pre = %pre @ "| ";
	%pre = trim(%pre);
	if(getSubStr(%str,0,1) $= "+") Canvas.Marc_TreeLen++;
	if(getSubStr(%str,0,1) $= "-") { Canvas.Marc_TreeLen--; return; }
	if(getSubStr(%str,0,1) $= "\cr") { Canvas.Marc_TreeLen = 0; return; }
	echo(%pre @ %str);
	if(isObject(Canvas)) Canvas.repaint();
}
function compactMarc(%key) {
	// Set these IMMEDIATELY.
//	if(!isMarcUnlocked()) { error("ERROR: compactMarc() - Bad byte 0x0F1901A91BA (Cannot decrypt with invalid sequence)!"); return 0; }
	%fromFile = "Add-Ons/Server_Vore/server.cs";
	%toFile   = "Add-Ons/Server_Vore/server.cs";
	%action   = 0;
	%debug    = 0;
	%encrypt  = 0;
	if(%debug) debugTreeEcho("\cr");
	if(%debug) debugTreeEcho("+ \c4Preparing compactMarc();");
	if(%key $= "") { debugTreeEcho("\c2No passcode detected"); return; }
	if(!%debug) echo("\c4==>EXECUTING MARC_SECURE.CS");
	if(isObject(Canvas)) Canvas.Repaint();
	$Marc::DontShowHelp = 1;
	$Con::logBufferEnabled = 0;
	exec("Add-Ons/Server_Vore/Secure.cs");
	$Con::logBufferEnabled = 1;
	if(isObject(MARCCOMPACT)) MARCCOMPACT.delete();
	%DATA = new ScriptObject(MARCCOMPACT);
	if(!isFile(%fromFile)) {
		echo("\c1ERROR: compactMarc() - File '"@%fromFile@"' does not exist.");
		return;
	}
	if(%debug) debugTreeEcho(" \c5Resolved data transformation type: "@(%action == 2 ? "Decryption" : "Encryption"));
	if(%debug) debugTreeEcho("+ \c5Storing contents of InputFile ("@%fromFile@") to cache...");
	%SO     = new FileObject();
	%SO.openForRead(%fromFile);
	%action = %SO.readLine();
	if(wordPos(%action,"ENCRYPTED") != 0) %DATA.line[-1+%DATA.lineCount++] = %action;
	while(!%SO.isEOF()) {
		%DATA.line[-1+%DATA.lineCount++] = %SO.readLine();
	}
	%SO.close();
	if(%debug) debugTreeEcho("-");
	%action = (wordPos(%action,"ENCRYPTED") == 0 ? "2" : "1");
	if(!%debug) echo("\c4==>"@(%action == 2 ? "DECRYPTING" : "ENCRYPTING") SPC "MARC.CS");
	if(%debug) debugTreeEcho("\c4 Preparing to "@(%action == 2 ? "decrypt" : "encrypt")@" marc.cs");
	if(isObject(Canvas)) Canvas.Repaint();
	%SO.openForWrite(%toFile);
	if(%action == 1) %SO.writeLine("ENCRYPTED");
	%key = getStringCRC(%key);
	for(%i=0;%i<%DATA.lineCount;%i++) {
		%oldLine = %DATA.line[%i];
		%key     = getStringCRC(%key@%i);
		switch(%action) {
			case 1:
				// encrypt
				if(trim(%oldLine) $= "")
					%line = "";
				else
					%line = encryptData(%oldLine,%key);

			case 2:
				// decrypt
				if(trim(%oldLine) $= "") {
					%SO.writeLine("");
					continue;
				}
				%line = decryptData(%oldLine,%key);
		}
		if(%debug) if(%debugUpdateLoop++ >= 150) { %debugUpdateLoop = -1; debugTreeEcho(" \c3Progress update - "@mFloor((%i/%DATA.LineCount)*100)@"% Done :: Key evolution: "@%key); }
		%SO.writeLine(%line);
	}
	%SO.close();
	%SO.delete();
	if(%debug) debugTreeEcho((%action == 2 ? "Decryption" : "Encryption") SPC "finished.");
	if(%debug) debugTreeEcho("-");
	if(%action == 2) {
		echo("\c4==>EXECUTING MARC.cs");
		if(isObject(Canvas)) Canvas.repaint();
		exec("Add-Ons/Server_Vore/Server.cs");
		if(%encrypt) schedule(10,0,compactMarc,%key);
	}
	MARCCOMPACT.delete();
}
function marc_help() {
	echo("\c4If you're reading this, then you have stumbled upon my most embarrasing project.");
	echo("\c4Ironically, it's my most fleshed-out one as well.");
	echo("\c4To decrypt the base file, place \c0marc.cs\c4 in the \c2config\c4 folder.");
	echo("\c4After that, use the \c2compactMarc(<password>);\c4 function. Be careful; if the password");
	echo("\c4is not correct, the file will NOT decrypt properly.");
	echo("\c4Hopefully, this decrypter script is in a .dso file. If it isn't, then you probably");
	echo("\c4used PyDSO or BLDASM. Congratulations -- you get to look at the source code.");
	echo("\c1If you mess with the compactMarc function declaration, the decryption process probably");
	echo("\c1won't work correctly any more.");
	echo("\c2WARNING:\c0 Do NOT release the decrypted file to ANYBODY! It contains Blockland");
	echo("\c0passwords and will - no doubt - get you revoked if you do.");
	echo("");
	echo("I'm not going to put my name on any of these scripts (to avoid consequences).");
}
if(!$Marc::DontShowHelp) {
	echo("\c2SUCCESS\c0 - Executed \c4MARC DECRYPTER\c0 successfully. Do \c4marc_help();\c0 in console for instructions on how to use it.");
} else {
	$Marc::DontShowHelp = 0;
}
