diff --git a/r5dev/include/address.h b/r5dev/include/address.h
index 44250051..6405fe8e 100644
--- a/r5dev/include/address.h
+++ b/r5dev/include/address.h
@@ -59,6 +59,11 @@ public:
 		return reinterpret_cast<T>(ptr);
 	}
 
+	template<class T> T GetValue()
+	{
+		return *reinterpret_cast<T*>(ptr);
+	}
+
 	MemoryAddress Offset(std::ptrdiff_t offset)
 	{
 		return MemoryAddress(ptr + offset);
@@ -94,33 +99,43 @@ public:
 		return *this;
 	}
 
-	bool CheckOpCode(char opcode)
+	bool CheckOpCodes(const std::vector<std::uint8_t> opcodeArray)
 	{
-		return *reinterpret_cast<char*>(ptr) == opcode;
+		std::uintptr_t reference = ptr; // Create pointer reference.
+
+		for (auto [byteAtCurrentAddress, i] = std::tuple{ std::uint8_t(), (std::size_t)0 }; i < opcodeArray.size(); i++, reference++) // Loop forward in the ptr class member.
+		{
+			byteAtCurrentAddress = *reinterpret_cast<std::uint8_t*>(reference); // Get byte at current address.
+
+			if (byteAtCurrentAddress != opcodeArray[i]) // If byte at ptr doesn't equal in the byte array return false.
+				return false;
+		}
+
+		return true;
 	}
 
 	template<class T> T GetVirtualFunctionIndex()
 	{
-		return *reinterpret_cast<T*>(ptr) / 4;
+		return *reinterpret_cast<T*>(ptr) / 8; // Its divided by 8 in x64.
 	}
 
-	void Patch(std::vector<byte> opcodes)
+	void Patch(std::vector<std::uint8_t> opcodes)
 	{
 		DWORD oldProt = NULL;
 
 		SIZE_T dwSize = opcodes.size();
-		VirtualProtect((void*)ptr, dwSize, PAGE_EXECUTE_READWRITE, &oldProt);
+		VirtualProtect((void*)ptr, dwSize, PAGE_EXECUTE_READWRITE, &oldProt); // Patch page to be able to read and write to it.
 
 		for (int i = 0; i < opcodes.size(); i++)
 		{
-			*(byte*)(ptr + i) = opcodes[i];
+			*(std::uint8_t*)(ptr + i) = opcodes[i]; // Write opcodes to address.
 		}
 
 		dwSize = opcodes.size();
-		VirtualProtect((void*)ptr, dwSize, oldProt, &oldProt);
+		VirtualProtect((void*)ptr, dwSize, oldProt, &oldProt); // Restore protection.
 	}
 
-	MemoryAddress FindPattern(const char* pattern, Direction searchDirect, int opCodesToScan = 100)
+	MemoryAddress FindPatternSelf(const char* pattern, Direction searchDirect, int opCodesToScan = 100, int occurence = 1)
 	{
 		static auto PatternToBytes = [](const char* pattern)
 		{
@@ -155,6 +170,7 @@ public:
 
 		const std::vector<int> PatternBytes = PatternToBytes(pattern); // Convert our pattern to a byte array.
 		const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes.
+		int occurences = 0;
 
 		for (auto i = 01; i < opCodesToScan + BytesInfo.first; ++i)
 		{
@@ -175,13 +191,118 @@ public:
 
 			if (FoundAddress)
 			{
-				return MemoryAddress(&ScanBytes[memOffset]);
+				occurences++;
+				if (occurence == occurences)
+				{
+					ptr = reinterpret_cast<std::uintptr_t>(&ScanBytes[memOffset]);
+					return *this;
+				}
+			}
+
+		}
+
+		ptr = std::uintptr_t();
+		return *this;
+	}
+
+	MemoryAddress FindPattern(const char* pattern, Direction searchDirect, int opCodesToScan = 100, int occurence = 1)
+	{
+		static auto PatternToBytes = [](const char* pattern)
+		{
+			char* PatternStart = const_cast<char*>(pattern); // Cast const away and get start of pattern.
+			char* PatternEnd = PatternStart + std::strlen(pattern); // Get end of pattern.
+
+			std::vector<std::int32_t> Bytes = std::vector<std::int32_t>{ }; // Initialize byte vector.
+
+			for (char* CurrentByte = PatternStart; CurrentByte < PatternEnd; ++CurrentByte)
+			{
+				if (*CurrentByte == '?') // Is current char(byte) a wildcard?
+				{
+					++CurrentByte; // Skip 1 character.
+
+					if (*CurrentByte == '?') // Is it a double wildcard pattern?
+						++CurrentByte; // If so skip the next space that will come up so we can reach the next byte.
+
+					Bytes.push_back(-1); // Push the byte back as invalid.
+				}
+				else
+				{
+					// https://stackoverflow.com/a/43860875/12541255
+					// Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal.
+					// Afterwards we push the byte into our bytes vector.
+					Bytes.push_back(std::strtoul(CurrentByte, &CurrentByte, 16));
+				}
+			}
+			return Bytes;
+		};
+
+		std::uint8_t* ScanBytes = reinterpret_cast<std::uint8_t*>(ptr); // Get the base of the module.
+
+		const std::vector<int> PatternBytes = PatternToBytes(pattern); // Convert our pattern to a byte array.
+		const std::pair BytesInfo = std::make_pair(PatternBytes.size(), PatternBytes.data()); // Get the size and data of our bytes.
+		int occurences = 0;
+
+		for (auto i = 01; i < opCodesToScan + BytesInfo.first; ++i)
+		{
+			bool FoundAddress = true;
+
+			int memOffset = searchDirect == Direction::UP ? -i : i;
+
+			for (DWORD j = 0ul; j < BytesInfo.first; ++j)
+			{
+				// If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard
+				// our if clause will be false.
+				if (ScanBytes[memOffset + j] != BytesInfo.second[j] && BytesInfo.second[j] != -1)
+				{
+					FoundAddress = false;
+					break;
+				}
+			}
+
+			if (FoundAddress)
+			{
+				occurences++;
+				if (occurence == occurences)
+				{
+					return MemoryAddress(&ScanBytes[memOffset]);
+				}
 			}
 
 		}
 
 		return MemoryAddress();
 	}
+
+	MemoryAddress FollowNearCall(std::ptrdiff_t opcodeOffset = 0x1, std::ptrdiff_t nextInstructionOffset = 0x5)
+	{
+		// Skip E9 opcode.
+		std::uintptr_t skipOpCode = ptr + opcodeOffset;
+
+		// Get 4-byte long relative address.
+		std::int32_t relativeAddress = *reinterpret_cast<std::int32_t*>(skipOpCode);
+
+		// Get location of next instruction.
+		std::uintptr_t nextInstruction = ptr + nextInstructionOffset;
+
+		// Get function location via adding relative address to next instruction.
+		return MemoryAddress(nextInstruction + relativeAddress);
+	}
+
+	MemoryAddress FollowNearCallSelf(std::ptrdiff_t opcodeOffset = 0x1, std::ptrdiff_t nextInstructionOffset = 0x5)
+	{
+		// Skip E9 opcode.
+		std::uintptr_t skipOpCode = ptr + opcodeOffset;
+
+		// Get 4-byte long relative address.
+		std::int32_t relativeAddress = *reinterpret_cast<std::int32_t*>(skipOpCode);
+
+		// Get location of next instruction.
+		std::uintptr_t nextInstruction = ptr + nextInstructionOffset;
+
+		// Get function location via adding relative address to next instruction.
+		ptr = nextInstruction + relativeAddress;
+		return *this;
+	}
 	
 private:
 	std::uintptr_t ptr = 0;
diff --git a/r5dev/include/patterns.h b/r5dev/include/patterns.h
index 980810d7..758a5b63 100644
--- a/r5dev/include/patterns.h
+++ b/r5dev/include/patterns.h
@@ -18,7 +18,7 @@ namespace
 
 #pragma region Squirrel
 	/*0x141057FD0*/
-	FUNC_AT_ADDRESS(org_SQVM_Print, void*, r5_patterns.PatternSearch("48 8B C4 48 89 50 10 4C 89 40 18 4C 89 48 20 53 56 57 48 81 EC 30 08 00 00 48 8B DA 48 8D 70 18 48 8B F9 E8 ?? ?? ?? FF 48 89 74 24 28 48 8D 54 24 30 33"));
+	FUNC_AT_ADDRESS(org_SQVM_Print, void*, r5_patterns.PatternSearch("83 F8 01 48 8D 3D ? ? ? ?").OffsetSelf(0x3).FollowNearCallSelf(0x3, 0x7).GetPtr());
 
 	//DWORD64 p_SQVM_LoadScript = FindPattern("r5apex.exe", (const unsigned char*)"\x48\x89\x5C\x24\x10\x48\x89\x74\x24\x18\x48\x89\x7C\x24\x20\x48\x89\x4C\x24\x08\x55\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\x6C", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); // For S0 and S1