/*
	std::ofstream myfile("debug.txt");
	myfile << "Base: ";
	myfile << carSaveBase;
	myfile << " Power: ";
	myfile << powerAddress;
	myfile << " Handling: ";
	myfile << handleAddress;
	myfile.close();
	*/
}

static bool saveOk = false;
unsigned char carDatadxp[0xFF];
static int SaveOk()
{
	saveOk = true;
	return 1;
}

char carFileNamedxp[0xFF];
bool loadOkdxp = false;
bool customCardxp = false;

static void saveMileagedxp()
{

	//Mileage Write to "GAME/mileage.dat"
	auto mileageLocation = (uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x280);
	//try this maybe, casting to int probably not right/not gonna work
	FILE* tempFile = fopen("mileage.dat", "wb");
	fwrite(mileageLocation, 1, sizeof(mileageLocation), tempFile);
	fclose(tempFile);
}

static void LoadMileagedxp()
{

	memset(mileDatadxp, 0, 0x08);
	FILE* miles = fopen("mileage.dat", "rb");
	if (miles)
	{
		fseek(miles, 0, SEEK_END);
		int mileSize = ftell(miles);
		if (mileSize == 0x08)
		{
			fseek(miles, 0, SEEK_SET);
			fread(mileDatadxp, mileSize, 1, miles);
			uintptr_t mileMemory = *(uintptr_t*)(imageBasedxplus + 0x1F7D578);
			memcpy((void*)(mileMemory + 0x280), mileDatadxp + 0x00, 0x04);
			fclose(miles);
		}
	}
}

static int SaveGameData()
{
	if (!saveOk)
		return 1;

	// Car Profile saving
	memset(carDatadxp, 0, 0xFF);
	memset(carFileNamedxp, 0, 0xFF);

	uintptr_t carSaveBase = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x268);

	//memcpy(carData + 0x01, (void*)(carSaveBase + 0xB8), 0x1); //successfully dumped power and handling!
	memcpy(carDatadxp + 0x00, (void*)(carSaveBase + 0x0), 0xFF); //dumps whole region

	CreateDirectoryA("OpenParrot_Cars", nullptr);

	if (customCardxp)
	{
		sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\custom.car");
	}
	else
	{
		sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34));
	}

	FILE* file = fopen(carFileNamedxp, "wb");
	fwrite(carDatadxp, 1, 0xFF, file);
	fclose(file);

	saveMileagedxp();

	saveOk = false;
	return 1;

	/*
	memset(saveData, 0, 0x2000);
	uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10);
	value = *(uintptr_t*)(value + 0x108);
	memcpy(saveData, (void *)value, 0x340);
	FILE* file = fopen("openprogress.sav", "wb");
	fwrite(saveData, 1, 0x2000, file);
	fclose(file);

	// Car Profile saving
	memset(carData, 0, 0xFF);
	memset(carFileNamedxp, 0, 0xFF);
	memcpy(carData, (void *)*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18), 0xE0);
	CreateDirectoryA("OpenParrot_Cars", nullptr);
	if(customCardxp)
	{
		sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\custom.car");
	}
	else
	{
		sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C));
	}
	FILE *carSave = fopen(carFileNamedxp, "wb");
	fwrite(carData, 1, 0xE0, file);
	fclose(carSave);
	saveOk = false;
	return 1;
	*/
}

uintptr_t saveGameOffsetdxp;

static int LoadGameData()
{
	saveOk = false;
	memset(saveDatadxp, 0x0, 0x2000);
	FILE* file = fopen("openprogress.sav", "rb");
	if (file)
	{
		fseek(file, 0, SEEK_END);
		int fsize = ftell(file);
		if (fsize == 0x2000)
		{
			fseek(file, 0, SEEK_SET);
			fread(saveDatadxp, fsize, 1, file);
			uintptr_t value = *(uintptr_t*)(imageBasedxplus + 0x1948F10);
			value = *(uintptr_t*)(value + 0x108);

			// First page
			memcpy((void *)(value + 0x10), saveDatadxp + 0x10, 0x20);
			memcpy((void *)(value + 0x40), saveDatadxp + 0x40, 0x08);
			memcpy((void *)(value + 0x48 + 8), saveDatadxp + 0x48 + 8, 0x08);
			memcpy((void *)(value + 0x48 + 24), saveDatadxp + 0x48 + 24, 0x08);
			memcpy((void *)(value + 0x48 + 32), saveDatadxp + 0x48 + 32, 0x08);

			// Second page
			value += 0x110;
			memcpy((void *)(value), saveDatadxp + 0x110, 0x90);
			value -= 0x110;

			// Third Page
			value += 0x1B8;
			memcpy((void *)(value), saveDatadxp + 0x1B8, 0x48);
			memcpy((void *)(value + 0x48 + 8), saveDatadxp + 0x1B8 + 0x48 + 8, 0x28);
			value -= 0x1B8;

			// Fourth page
			value += 0x240;
			memcpy((void *)(value), saveDatadxp + 0x240, 0x68);
			value -= 0x240;

			// Fifth page
			value += 0x2B8;
			memcpy((void *)(value), saveDatadxp + 0x2B8, 0x88);
			value -= 0x2B8;

			loadOkdxp = true;

			//TA stuff

			// First chunk
		}
		fclose(file);
	}
	return 1;
}

static void LoadWmmt5CarData()
{
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));

	customCardxp = false;
	memset(carDatadxp, 0, 0xFF);
	memset(carFileNamedxp, 0, 0xFF);
	CreateDirectoryA("OpenParrot_Cars", nullptr);

	LoadMileagedxp();

	// check for custom car
	sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\custom.car");
	if (FileExists(carFileNamedxp))
	{
		FILE* file = fopen(carFileNamedxp, "rb");
		if (file)
		{
			fseek(file, 0, SEEK_END);
			int fsize = ftell(file);
			if (fsize == 0xFF)
			{
				fseek(file, 0, SEEK_SET);
				fread(carDatadxp, fsize, 1, file);
				uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x268);
				memcpy((void*)(carSaveLocation + 0xAC), carDatadxp + 0xAC, 0x1); //power
				memcpy((void*)(carSaveLocation + 0xB8), carDatadxp + 0xB8, 0x1); //handling
				memcpy((void*)(carSaveLocation + 0x28), carDatadxp + 0x28, 0x1); //region
				memcpy((void*)(carSaveLocation + 0x34), carDatadxp + 0x34, 0x1); //carID
				memcpy((void*)(carSaveLocation + 0x38), carDatadxp + 0x38, 0x1); //defaultColor
				memcpy((void*)(carSaveLocation + 0x3C), carDatadxp + 0x3C, 0x1); //customColor
				memcpy((void*)(carSaveLocation + 0x40), carDatadxp + 0x40, 0x1); //rims
				memcpy((void*)(carSaveLocation + 0x44), carDatadxp + 0x44, 0x1); //rimColor
				memcpy((void*)(carSaveLocation + 0x48), carDatadxp + 0x48, 0x1); //aero
				memcpy((void*)(carSaveLocation + 0x4C), carDatadxp + 0x4C, 0x1); //hood
				memcpy((void*)(carSaveLocation + 0x58), carDatadxp + 0x58, 0x1); //wang
				memcpy((void*)(carSaveLocation + 0x5C), carDatadxp + 0x5C, 0x1); //mirror
				memcpy((void*)(carSaveLocation + 0x60), carDatadxp + 0x60, 0x1); //sticker
				memcpy((void*)(carSaveLocation + 0x64), carDatadxp + 0x64, 0x1); //stickerVariant
				memcpy((void*)(carSaveLocation + 0x88), carDatadxp + 0x88, 0x1); //roofSticker
				memcpy((void*)(carSaveLocation + 0x8C), carDatadxp + 0x8C, 0x1); //roofStickerVariant
				memcpy((void*)(carSaveLocation + 0x90), carDatadxp + 0x90, 0x1); //neon
				memcpy((void*)(carSaveLocation + 0x94), carDatadxp + 0x94, 0x1); //trunk
				memcpy((void*)(carSaveLocation + 0x98), carDatadxp + 0x98, 0x1); //plateFrame
				memcpy((void*)(carSaveLocation + 0xA0), carDatadxp + 0xA0, 0x4); //plateNumber
				memcpy((void*)(carSaveLocation + 0xA4), carDatadxp + 0xA4, 0x1); //vinyl_body_challenge_prefecture_1~15
				memcpy((void*)(carSaveLocation + 0xA8), carDatadxp + 0xA8, 0x1); //vinyl_body_challenge_prefecture
				memcpy((void*)(carSaveLocation + 0xBC), carDatadxp + 0xBC, 0x1); //rank
				memcpy((void*)(carSaveLocation + 0xF0), carDatadxp + 0xF0, 0x1); //title??

				customCardxp = true;
			}
			loadOkdxp = false;
			fclose(file);
			return;
		}
	}
	if (ToBool(config["Tune"]["Force Full Tune"]))
	{
		CreateThread(0, 0, forceFT, 0, 0, 0);
	}

	memset(carFileNamedxp, 0, 0xFF);
	// Load actual car if available
	sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34));
	if(FileExists(carFileNamedxp))
	{
		FILE* file = fopen(carFileNamedxp, "rb");
		if (file)
		{
			fseek(file, 0, SEEK_END);
			int fsize = ftell(file);
			if (fsize == 0xFF)
			{
				fseek(file, 0, SEEK_SET);
				fread(carDatadxp, fsize, 1, file);
				uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x268);
				memcpy((void*)(carSaveLocation + 0xAC), carDatadxp + 0xAC, 0x1); //power
				memcpy((void*)(carSaveLocation + 0xB8), carDatadxp + 0xB8, 0x1); //handling
				memcpy((void*)(carSaveLocation + 0x28), carDatadxp + 0x28, 0x1); //region
				memcpy((void*)(carSaveLocation + 0x34), carDatadxp + 0x34, 0x1); //carID
				memcpy((void*)(carSaveLocation + 0x38), carDatadxp + 0x38, 0x1); //defaultColor
				memcpy((void*)(carSaveLocation + 0x3C), carDatadxp + 0x3C, 0x1); //customColor
				memcpy((void*)(carSaveLocation + 0x40), carDatadxp + 0x40, 0x1); //rims
				memcpy((void*)(carSaveLocation + 0x44), carDatadxp + 0x44, 0x1); //rimColor
				memcpy((void*)(carSaveLocation + 0x48), carDatadxp + 0x48, 0x1); //aero
				memcpy((void*)(carSaveLocation + 0x4C), carDatadxp + 0x4C, 0x1); //hood
				memcpy((void*)(carSaveLocation + 0x58), carDatadxp + 0x58, 0x1); //wang
				memcpy((void*)(carSaveLocation + 0x5C), carDatadxp + 0x5C, 0x1); //mirror
				memcpy((void*)(carSaveLocation + 0x60), carDatadxp + 0x60, 0x1); //sticker
				memcpy((void*)(carSaveLocation + 0x64), carDatadxp + 0x64, 0x1); //stickerVariant
				memcpy((void*)(carSaveLocation + 0x88), carDatadxp + 0x88, 0x1); //roofSticker
				memcpy((void*)(carSaveLocation + 0x8C), carDatadxp + 0x8C, 0x1); //roofStickerVariant
				memcpy((void*)(carSaveLocation + 0x90), carDatadxp + 0x90, 0x1); //neon
				memcpy((void*)(carSaveLocation + 0x94), carDatadxp + 0x94, 0x1); //trunk
				memcpy((void*)(carSaveLocation + 0x98), carDatadxp + 0x98, 0x1); //plateFrame
				memcpy((void*)(carSaveLocation + 0xA0), carDatadxp + 0xA0, 0x4); //plateNumber
				memcpy((void*)(carSaveLocation + 0xA4), carDatadxp + 0xA4, 0x1); //vinyl_body_challenge_prefecture_1~15
				memcpy((void*)(carSaveLocation + 0xA8), carDatadxp + 0xA8, 0x1); //vinyl_body_challenge_prefecture
				memcpy((void*)(carSaveLocation + 0xBC), carDatadxp + 0xBC, 0x1); //rank
				memcpy((void*)(carSaveLocation + 0xF0), carDatadxp + 0xF0, 0x1); //title??
			}
			fclose(file);
		}
	}
	loadOkdxp = false;
}

static void loadCar()
{
	std::thread t1(LoadWmmt5CarData);
	t1.detach();
}

static int ReturnTrue()
{
	return 1;
}

void GenerateDongleDataDxp(bool isTerminal)
{
	memset(hasp_buffer, 0, 0xD40);
	hasp_buffer[0] = 0x01;
	hasp_buffer[0x13] = 0x01;
	hasp_buffer[0x17] = 0x0A;
	hasp_buffer[0x1B] = 0x04;
	hasp_buffer[0x1C] = 0x3B;
	hasp_buffer[0x1D] = 0x6B;
	hasp_buffer[0x1E] = 0x40;
	hasp_buffer[0x1F] = 0x87;

	hasp_buffer[0x23] = 0x01;
	hasp_buffer[0x27] = 0x0A;
	hasp_buffer[0x2B] = 0x04;
	hasp_buffer[0x2C] = 0x3B;
	hasp_buffer[0x2D] = 0x6B;
	hasp_buffer[0x2E] = 0x40;
	hasp_buffer[0x2F] = 0x87;

	if(isTerminal)
	{
		memcpy(hasp_buffer + 0xD00, "278311042069", 12); //272211990002
		hasp_buffer[0xD3E] = 0x6B;
		hasp_buffer[0xD3F] = 0x94;
	}
	else
	{
		memcpy(hasp_buffer + 0xD00, "278313042069", 12); //272213990002
		hasp_buffer[0xD3E] = 0x6D;
		hasp_buffer[0xD3F] = 0x92;
	}
}

char customNamedxp[256];

static DWORD WINAPI SpamcustomNamedxp(LPVOID)
{
	while (true)
	{

		Sleep(50);
		void *value = (void *)(imageBasedxplus + 0x1F846F0);
		memcpy(value, customNamedxp, strlen(customNamedxp) + 1);

	}
}

static DWORD WINAPI SpamMulticast(LPVOID)
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

	int ttl = 255;
	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));

	int reuse = 1;
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));

	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&reuse, sizeof(reuse));

	sockaddr_in bindAddr = { 0 };
	bindAddr.sin_family = AF_INET;
	bindAddr.sin_addr.s_addr = inet_addr(ipaddrdxplus);
	bindAddr.sin_port = htons(50765);
	bind(sock, (sockaddr*)&bindAddr, sizeof(bindAddr));

	ip_mreq mreq;
	mreq.imr_multiaddr.s_addr = inet_addr("225.0.0.1");
	mreq.imr_interface.s_addr = inet_addr(ipaddrdxplus);

	setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));

	const uint8_t* byteSequences_Free[] = {
		dxpterminalPackage1_Free,
		dxpterminalPackage2_Free,
		dxpterminalPackage3_Free,
		dxpterminalPackage4_Free,
		dxpterminalPackage5_Free,
		dxpterminalPackage6_Free,
	};

	const size_t byteSizes_Free[] = {
		sizeof(dxpterminalPackage1_Free),
		sizeof(dxpterminalPackage2_Free),
		sizeof(dxpterminalPackage3_Free),
		sizeof(dxpterminalPackage4_Free),
		sizeof(dxpterminalPackage5_Free),
		sizeof(dxpterminalPackage6_Free),
	};

	const uint8_t* byteSequences_Event2P[] = {
		dxpterminalPackage1_Event2P,
		dxpterminalPackage2_Event2P,
		dxpterminalPackage3_Event2P,
		dxpterminalPackage4_Event2P,
		dxpterminalPackage5_Event2P,
		dxpterminalPackage6_Event2P,
	};

	const size_t byteSizes_Event2P[] = {
		sizeof(dxpterminalPackage1_Event2P),
		sizeof(dxpterminalPackage2_Event2P),
		sizeof(dxpterminalPackage3_Event2P),
		sizeof(dxpterminalPackage4_Event2P),
		sizeof(dxpterminalPackage5_Event2P),
		sizeof(dxpterminalPackage6_Event2P),
	};

	const uint8_t* byteSequences_Event4P[] = {
		dxpterminalPackage1_Event4P,
		dxpterminalPackage2_Event4P,
		dxpterminalPackage3_Event4P,
		dxpterminalPackage4_Event4P,
		dxpterminalPackage5_Event4P,
		dxpterminalPackage6_Event4P,
	};

	const size_t byteSizes_Event4P[] = {
		sizeof(dxpterminalPackage1_Event4P),
		sizeof(dxpterminalPackage2_Event4P),
		sizeof(dxpterminalPackage3_Event4P),
		sizeof(dxpterminalPackage4_Event4P),
		sizeof(dxpterminalPackage5_Event4P),
		sizeof(dxpterminalPackage6_Event4P),
	};

	const uint8_t* byteSequences_Coin[] = {
		dxpterminalPackage1_Coin,
		dxpterminalPackage2_Coin,
		dxpterminalPackage3_Coin,
		dxpterminalPackage4_Coin,
		dxpterminalPackage5_Coin,
		dxpterminalPackage6_Coin,
	};

	const size_t byteSizes_Coin[] = {
		sizeof(dxpterminalPackage1_Coin),
		sizeof(dxpterminalPackage2_Coin),
		sizeof(dxpterminalPackage3_Coin),
		sizeof(dxpterminalPackage4_Coin),
		sizeof(dxpterminalPackage5_Coin),
		sizeof(dxpterminalPackage6_Coin),
	};

	sockaddr_in toAddr = { 0 };
	toAddr.sin_family = AF_INET;
	toAddr.sin_addr.s_addr = inet_addr("225.0.0.1");
	toAddr.sin_port = htons(50765);

	isFreePlay = ToBool(config["General"]["FreePlay"]);
	isEventMode2P = ToBool(config["TerminalEmuConfig"]["2P Event Mode"]);
	isEventMode4P = ToBool(config["TerminalEmuConfig"]["4P Event Mode"]);

	if (isFreePlay)
	{
		if (isEventMode2P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event2P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event2P[i], byteSizes_Event2P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else if (isEventMode4P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event4P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event4P[i], byteSizes_Event4P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else {
			while (true) for (int i = 0; i < _countof(byteSequences_Free); i++)
			{
				sendto(sock, (const char*)byteSequences_Free[i], byteSizes_Free[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
	}

	while (true) for (int i = 0; i < _countof(byteSequences_Coin); i++)
	{
		sendto(sock, (const char*)byteSequences_Coin[i], byteSizes_Coin[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
		Sleep(8);
	}
}

/*
extern int* ffbOffset;
extern int* ffbOffset2;
extern int* ffbOffset3;
extern int* ffbOffset4;

DWORD WINAPI Wmmt5FfbCollector(void* ctx)
{
	uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0);
	while (true)
	{
		*ffbOffset = *(DWORD *)(imageBase + 0x196F188);
		*ffbOffset2 = *(DWORD *)(imageBase + 0x196F18c);
		*ffbOffset3 = *(DWORD *)(imageBase + 0x196F190);
		*ffbOffset4 = *(DWORD *)(imageBase + 0x196F194);
		Sleep(10);
	}
}*/

static InitFunction Wmmt5Func([]()
{/*
	FILE* fileF = _wfopen(L"Fsetting.lua.gz", L"r");
	if (fileF == NULL)
	{
		FILE* settingsF = _wfopen(L"Fsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsF);
		fclose(settingsF);
	}
	else
	{
		fclose(fileF);
	}

	FILE* fileG = _wfopen(L"Gsetting.lua.gz", L"r");
	if (fileG == NULL)
	{
		FILE* settingsG = _wfopen(L"Gsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsG);
		fclose(settingsG);
	}
	else
	{
		fclose(fileG);
	}*/

	bool isTerminal = false;
	if (ToBool(config["General"]["TerminalMode"]))
	{
		isTerminal = true;
	}

	std::string networkip = config["General"]["NetworkAdapterIP"];
	if (!networkip.empty())
	{
		ipaddrdxplus = networkip.c_str();
	}

	hookPort = "COM3";
	imageBasedxplus = (uintptr_t)GetModuleHandleA(0);
	MH_Initialize();

	// Hook dongle funcs
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_write", dxpHook_hasp_write, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_read", dxpHook_hasp_read, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_get_size", dxpHook_hasp_get_size, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_decrypt", dxpHook_hasp_decrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_encrypt", dxpHook_hasp_encrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_logout", dxpHook_hasp_logout, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_login", dxpHook_hasp_login, NULL);

	GenerateDongleDataDxp(isTerminal);

	//prevents game from setting time, thanks pockywitch!
	MH_CreateHookApi(L"KERNEL32", "SetSystemTime", Hook_SetSystemTime, reinterpret_cast<LPVOID*>(&pSetSystemTime));

	// Patch some check TEMP DISABLE AS WELL OVER HERE
	// NOT WORKING 1
	// FOUND ON 1
	injector::WriteMemory<uint8_t>(hook::get_pattern("85 C9 0F 94 C0 84 C0 0F 94 C0 84 C0 75 ? 40 32 F6 EB ?", 0x15), 0, true); //patches out dongle error2 (doomer)

	// Patch some jnz
	// FOUND ON 1
	injector::MakeNOP(hook::get_pattern("83 C0 FD 83 F8 01 76 ? 49 8D ? ? ? ? 00 00"), 6);

	// Patch some shit
	// NOT FOUND:

	// Skip weird camera init that stucks entire pc on certain brands. TESTED ONLY ON 05!!!!
	if (ToBool(config["General"]["WhiteScreenFix"]))
	{
		injector::WriteMemory<DWORD>(hook::get_pattern("48 8B C4 55 57 41 54 41 55 41 56 48 8D 68 A1 48 81 EC 90 00 00 00 48 C7 45 D7 FE FF FF FF 48 89 58 08 48 89 70 18 45 33 F6 4C 89 75 DF 33 C0 48 89 45 E7", 0), 0x90C3C032, true);
	}

	// Patch some call
	// 45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ?? ?? ?? ?? 48 8B 08
	//THIS injector::MakeNOP(hook::get_pattern("45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ? ? ? ? 48 8B 08", 12), 5);

	{
		// 199AE18 TIME OFFSET RVA temp disable ALL JNZ PATCH

		auto location = hook::get_pattern<char>("41 3B C7 74 0E 48 8D 8F B8 00 00 00 BA F6 01 00 00 EB 6E 48 8D 8F A0 00 00 00");
		// Patch some jnz
		injector::WriteMemory<uint8_t>(location + 3, 0xEB, true); //patches content router (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x22, 2); //patches ip addr error again (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x33, 2); //patches ip aaddr error(doomer)
	}

	// Skip DebugBreak on MFStartup fail
	{
		/*
		auto location = hook::get_pattern<char>("48 83 EC 28 33 D2 B9 70 00 02 00 E8 ? ? ? ? 85 C0 79 06");
		injector::WriteMemory<uint8_t>(location + 0x12, 0xEB, true);
		*/
	}

	if (isTerminal)
	{
		// Patch some func to 1
		// NOT FOUND:
		//safeJMP(hook::get_pattern("0F B6 41 05 2C 30 3C 09 77 04 0F BE C0 C3 83 C8 FF C3"), ReturnTrue);

		// Patch some func to 1
	}
	else
	{
		// Disregard terminal scanner stuff.

		{

			/*
			auto location = hook::get_pattern<char>("48 8B 18 48 3B D8 0F 84 8B 00 00 00 0F 1F 80 00 00 00 00 39 73 1C 74 5C 80 7B 31 00");
			injector::MakeNOP(location + 0xF, 2); // 0xF
			*/
			injector::MakeNOP(imageBasedxplus + 0x9F2BB3, 2);
		}

		// spam thread
		if (ToBool(config["General"]["TerminalEmulator"]))
		{
			CreateThread(0, 0, SpamMulticast, 0, 0, 0);
		}
	}

	auto chars = { 'F', 'G' };

	for (auto cha : chars)
	{
		auto patterns = hook::pattern(va("%02X 3A 2F", cha));

		if (patterns.size() > 0)
		{
			for (int i = 0; i < patterns.size(); i++)
			{
				char* text = patterns.get(i).get<char>(0);
				std::string text_str(text);

				std::string to_replace = va("%c:/", cha);
				std::string replace_with = va("./%c", cha);

				std::string replaced = text_str.replace(0, to_replace.length(), replace_with);

				injector::WriteMemoryRaw(text, (char*)replaced.c_str(), replaced.length() + 1, true);
			}
		}
	}

	if (ToBool(config["General"]["SkipMovies"]))
	{
		// Skip movies fuck you wmmt5
	}

	std::string value = config["General"]["CustomName"];
	if (!value.empty())
	{

		memset(customNamedxp, 0, 256);
		strcpy(customNamedxp, value.c_str());
		CreateThread(0, 0, SpamcustomNamedxp, 0, 0, 0);

	}

	// Save story stuff (only 05)
	{

		// skip erasing of temp card data
		/*
		// Skip erasing of temp card
		safeJMP(imageBase + 0x54DCE1, LoadGameData);
		safeJMP(imageBase + 0x5612F0, ReturnTrue);
		safeJMP(imageBase + 0x5753C0, ReturnTrue);
		safeJMP(imageBase + 0x57DF10, ReturnTrue);

		safeJMP(imageBase + 0x92DB20, ReturnTrue);
		safeJMP(imageBase + 0x5628C0, ReturnTrue);
		safeJMP(imageBase + 0x579090, ReturnTrue);

		// Skip more
		safeJMP(imageBase + 0x54B0F0, ReturnTrue);
		safeJMP(imageBase + 0x909DB0, ReturnTrue);
		safeJMP(imageBase + 0x59FD90, ReturnTrue);
		safeJMP(imageBase + 0x5A0030, ReturnTrue);
		safeJMP(imageBase + 0x915370, ReturnTrue);
		safeJMP(imageBase + 0x5507A0, ReturnTrue);
		safeJMP(imageBase + 0x561290, ReturnTrue);

		safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData);

		// crash fix

		// Save progress trigger
		injector::WriteMemory<WORD>(imageBase + 0x556CE3, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x556CE3 + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBase + 0x556CED, 0x9090D0FF, true);

		// Try save later!
		injector::MakeNOP(imageBase + 0x308546, 0x12);
		injector::WriteMemory<WORD>(imageBase + 0x308546, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x308546 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBase + 0x308550, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBase + 0x308550 + 4, 0x90C0, true);

		CreateThread(0, 0, Wmmt5FfbCollector, 0, 0, 0);
		*/

		// Enable all print
		injector::MakeNOP(imageBasedxplus + 0x898BD3, 6);

		//load car trigger
		safeJMP(imageBasedxplus + 0x72AB90, loadCar);

		//save car trigger

		injector::MakeNOP(imageBasedxplus + 0x376F76, 0x12);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F76, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x376F76 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x376F80, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F80 + 4, 0x90C0, true);

		//prevents startup saving
		injector::WriteMemory<WORD>(imageBasedxplus + 0x6B909A, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x6B909A + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x6B90A4, 0x9090D0FF, true);

	}

	MH_EnableHook(MH_ALL_HOOKS);

}, GameID::WMMT5DXPlus);
#endif
#pragma optimize("", on)


	mreq.imr_interface.s_addr = inet_addr(ipaddrdxplus);

	setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));

	const uint8_t* byteSequences_Free[] = {
		dxpterminalPackage1_Free,
		dxpterminalPackage2_Free,
		dxpterminalPackage3_Free,
		dxpterminalPackage4_Free,
		dxpterminalPackage5_Free,
		dxpterminalPackage6_Free,
	};

	const size_t byteSizes_Free[] = {
		sizeof(dxpterminalPackage1_Free),
		sizeof(dxpterminalPackage2_Free),
		sizeof(dxpterminalPackage3_Free),
		sizeof(dxpterminalPackage4_Free),
		sizeof(dxpterminalPackage5_Free),
		sizeof(dxpterminalPackage6_Free),
	};

	const uint8_t* byteSequences_Event2P[] = {
		dxpterminalPackage1_Event2P,
		dxpterminalPackage2_Event2P,
		dxpterminalPackage3_Event2P,
		dxpterminalPackage4_Event2P,
		dxpterminalPackage5_Event2P,
		dxpterminalPackage6_Event2P,
	};

	const size_t byteSizes_Event2P[] = {
		sizeof(dxpterminalPackage1_Event2P),
		sizeof(dxpterminalPackage2_Event2P),
		sizeof(dxpterminalPackage3_Event2P),
		sizeof(dxpterminalPackage4_Event2P),
		sizeof(dxpterminalPackage5_Event2P),
		sizeof(dxpterminalPackage6_Event2P),
	};

	const uint8_t* byteSequences_Event4P[] = {
		dxpterminalPackage1_Event4P,
		dxpterminalPackage2_Event4P,
		dxpterminalPackage3_Event4P,
		dxpterminalPackage4_Event4P,
		dxpterminalPackage5_Event4P,
		dxpterminalPackage6_Event4P,
	};

	const size_t byteSizes_Event4P[] = {
		sizeof(dxpterminalPackage1_Event4P),
		sizeof(dxpterminalPackage2_Event4P),
		sizeof(dxpterminalPackage3_Event4P),
		sizeof(dxpterminalPackage4_Event4P),
		sizeof(dxpterminalPackage5_Event4P),
		sizeof(dxpterminalPackage6_Event4P),
	};

	const uint8_t* byteSequences_Coin[] = {
		dxpterminalPackage1_Coin,
		dxpterminalPackage2_Coin,
		dxpterminalPackage3_Coin,
		dxpterminalPackage4_Coin,
		dxpterminalPackage5_Coin,
		dxpterminalPackage6_Coin,
	};

	const size_t byteSizes_Coin[] = {
		sizeof(dxpterminalPackage1_Coin),
		sizeof(dxpterminalPackage2_Coin),
		sizeof(dxpterminalPackage3_Coin),
		sizeof(dxpterminalPackage4_Coin),
		sizeof(dxpterminalPackage5_Coin),
		sizeof(dxpterminalPackage6_Coin),
	};

	sockaddr_in toAddr = { 0 };
	toAddr.sin_family = AF_INET;
	toAddr.sin_addr.s_addr = inet_addr("225.0.0.1");
	toAddr.sin_port = htons(50765);

	isFreePlay = ToBool(config["General"]["FreePlay"]);
	isEventMode2P = ToBool(config["TerminalEmuConfig"]["2P Event Mode"]);
	isEventMode4P = ToBool(config["TerminalEmuConfig"]["4P Event Mode"]);

	if (isFreePlay)
	{
		if (isEventMode2P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event2P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event2P[i], byteSizes_Event2P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else if (isEventMode4P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event4P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event4P[i], byteSizes_Event4P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else {
			while (true) for (int i = 0; i < _countof(byteSequences_Free); i++)
			{
				sendto(sock, (const char*)byteSequences_Free[i], byteSizes_Free[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
	}

	while (true) for (int i = 0; i < _countof(byteSequences_Coin); i++)
	{
		sendto(sock, (const char*)byteSequences_Coin[i], byteSizes_Coin[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
		Sleep(8);
	}
}

/*
extern int* ffbOffset;
extern int* ffbOffset2;
extern int* ffbOffset3;
extern int* ffbOffset4;

DWORD WINAPI Wmmt5FfbCollector(void* ctx)
{
	uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0);
	while (true)
	{
		*ffbOffset = *(DWORD *)(imageBase + 0x196F188);
		*ffbOffset2 = *(DWORD *)(imageBase + 0x196F18c);
		*ffbOffset3 = *(DWORD *)(imageBase + 0x196F190);
		*ffbOffset4 = *(DWORD *)(imageBase + 0x196F194);
		Sleep(10);
	}
}*/

static InitFunction Wmmt5Func([]()
{/*
	FILE* fileF = _wfopen(L"Fsetting.lua.gz", L"r");
	if (fileF == NULL)
	{
		FILE* settingsF = _wfopen(L"Fsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsF);
		fclose(settingsF);
	}
	else
	{
		fclose(fileF);
	}

	FILE* fileG = _wfopen(L"Gsetting.lua.gz", L"r");
	if (fileG == NULL)
	{
		FILE* settingsG = _wfopen(L"Gsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsG);
		fclose(settingsG);
	}
	else
	{
		fclose(fileG);
	}*/

	bool isTerminal = false;
	if (ToBool(config["General"]["TerminalMode"]))
	{
		isTerminal = true;
	}

	std::string networkip = config["General"]["NetworkAdapterIP"];
	if (!networkip.empty())
	{
		ipaddrdxplus = networkip.c_str();
	}

	hookPort = "COM3";
	imageBasedxplus = (uintptr_t)GetModuleHandleA(0);
	MH_Initialize();

	// Hook dongle funcs
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_write", dxpHook_hasp_write, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_read", dxpHook_hasp_read, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_get_size", dxpHook_hasp_get_size, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_decrypt", dxpHook_hasp_decrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_encrypt", dxpHook_hasp_encrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_logout", dxpHook_hasp_logout, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_login", dxpHook_hasp_login, NULL);

	GenerateDongleDataDxp(isTerminal);

	//prevents game from setting time, thanks pockywitch!
	MH_CreateHookApi(L"KERNEL32", "SetSystemTime", Hook_SetSystemTime, reinterpret_cast<LPVOID*>(&pSetSystemTime));

	// Patch some check TEMP DISABLE AS WELL OVER HERE
	// NOT WORKING 1
	// FOUND ON 1
	injector::WriteMemory<uint8_t>(hook::get_pattern("85 C9 0F 94 C0 84 C0 0F 94 C0 84 C0 75 ? 40 32 F6 EB ?", 0x15), 0, true); //patches out dongle error2 (doomer)

	// Patch some jnz
	// FOUND ON 1
	injector::MakeNOP(hook::get_pattern("83 C0 FD 83 F8 01 76 ? 49 8D ? ? ? ? 00 00"), 6);

	// Patch some shit
	// NOT FOUND:

	// Skip weird camera init that stucks entire pc on certain brands. TESTED ONLY ON 05!!!!
	if (ToBool(config["General"]["WhiteScreenFix"]))
	{
		injector::WriteMemory<DWORD>(hook::get_pattern("48 8B C4 55 57 41 54 41 55 41 56 48 8D 68 A1 48 81 EC 90 00 00 00 48 C7 45 D7 FE FF FF FF 48 89 58 08 48 89 70 18 45 33 F6 4C 89 75 DF 33 C0 48 89 45 E7", 0), 0x90C3C032, true);
	}

	// Patch some call
	// 45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ?? ?? ?? ?? 48 8B 08
	//THIS injector::MakeNOP(hook::get_pattern("45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ? ? ? ? 48 8B 08", 12), 5);

	{
		// 199AE18 TIME OFFSET RVA temp disable ALL JNZ PATCH

		auto location = hook::get_pattern<char>("41 3B C7 74 0E 48 8D 8F B8 00 00 00 BA F6 01 00 00 EB 6E 48 8D 8F A0 00 00 00");
		// Patch some jnz
		injector::WriteMemory<uint8_t>(location + 3, 0xEB, true); //patches content router (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x22, 2); //patches ip addr error again (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x33, 2); //patches ip aaddr error(doomer)
	}

	// Skip DebugBreak on MFStartup fail
	{
		/*
		auto location = hook::get_pattern<char>("48 83 EC 28 33 D2 B9 70 00 02 00 E8 ? ? ? ? 85 C0 79 06");
		injector::WriteMemory<uint8_t>(location + 0x12, 0xEB, true);
		*/
	}

	if (isTerminal)
	{
		// Patch some func to 1
		// NOT FOUND:
		//safeJMP(hook::get_pattern("0F B6 41 05 2C 30 3C 09 77 04 0F BE C0 C3 83 C8 FF C3"), ReturnTrue);

		// Patch some func to 1
	}
	else
	{
		// Disregard terminal scanner stuff.

		{

			/*
			auto location = hook::get_pattern<char>("48 8B 18 48 3B D8 0F 84 8B 00 00 00 0F 1F 80 00 00 00 00 39 73 1C 74 5C 80 7B 31 00");
			injector::MakeNOP(location + 0xF, 2); // 0xF
			*/
			injector::MakeNOP(imageBasedxplus + 0x9F2BB3, 2);
		}

		// spam thread
		if (ToBool(config["General"]["TerminalEmulator"]))
		{
			CreateThread(0, 0, SpamMulticast, 0, 0, 0);
		}
	}

	auto chars = { 'F', 'G' };

	for (auto cha : chars)
	{
		auto patterns = hook::pattern(va("%02X 3A 2F", cha));

		if (patterns.size() > 0)
		{
			for (int i = 0; i < patterns.size(); i++)
			{
				char* text = patterns.get(i).get<char>(0);
				std::string text_str(text);

				std::string to_replace = va("%c:/", cha);
				std::string replace_with = va("./%c", cha);

				std::string replaced = text_str.replace(0, to_replace.length(), replace_with);

				injector::WriteMemoryRaw(text, (char*)replaced.c_str(), replaced.length() + 1, true);
			}
		}
	}

	if (ToBool(config["General"]["SkipMovies"]))
	{
		// Skip movies fuck you wmmt5
	}

	std::string value = config["General"]["CustomName"];
	if (!value.empty())
	{

		memset(customNamedxp, 0, 256);
		strcpy(customNamedxp, value.c_str());
		CreateThread(0, 0, SpamcustomNamedxp, 0, 0, 0);

	}

	// Save story stuff (only 05)
	{

		// skip erasing of temp card data
		/*
		// Skip erasing of temp card
		safeJMP(imageBase + 0x54DCE1, LoadGameData);
		safeJMP(imageBase + 0x5612F0, ReturnTrue);
		safeJMP(imageBase + 0x5753C0, ReturnTrue);
		safeJMP(imageBase + 0x57DF10, ReturnTrue);

		safeJMP(imageBase + 0x92DB20, ReturnTrue);
		safeJMP(imageBase + 0x5628C0, ReturnTrue);
		safeJMP(imageBase + 0x579090, ReturnTrue);

		// Skip more
		safeJMP(imageBase + 0x54B0F0, ReturnTrue);
		safeJMP(imageBase + 0x909DB0, ReturnTrue);
		safeJMP(imageBase + 0x59FD90, ReturnTrue);
		safeJMP(imageBase + 0x5A0030, ReturnTrue);
		safeJMP(imageBase + 0x915370, ReturnTrue);
		safeJMP(imageBase + 0x5507A0, ReturnTrue);
		safeJMP(imageBase + 0x561290, ReturnTrue);

		safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData);

		// crash fix

		// Save progress trigger
		injector::WriteMemory<WORD>(imageBase + 0x556CE3, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x556CE3 + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBase + 0x556CED, 0x9090D0FF, true);

		// Try save later!
		injector::MakeNOP(imageBase + 0x308546, 0x12);
		injector::WriteMemory<WORD>(imageBase + 0x308546, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x308546 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBase + 0x308550, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBase + 0x308550 + 4, 0x90C0, true);

		CreateThread(0, 0, Wmmt5FfbCollector, 0, 0, 0);
		*/

		// Enable all print
		injector::MakeNOP(imageBasedxplus + 0x898BD3, 6);

		//load car trigger
		safeJMP(imageBasedxplus + 0x72AB90, loadCar);

		//save car trigger

		injector::MakeNOP(imageBasedxplus + 0x376F76, 0x12);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F76, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x376F76 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x376F80, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F80 + 4, 0x90C0, true);

		//prevents startup saving
		injector::WriteMemory<WORD>(imageBasedxplus + 0x6B909A, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x6B909A + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x6B90A4, 0x9090D0FF, true);

	}

	MH_EnableHook(MH_ALL_HOOKS);

}, GameID::WMMT5DXPlus);
#endif
#pragma optimize("", on)


}

char customNamedxp[256];

static DWORD WINAPI SpamcustomNamedxp(LPVOID)
{
	while (true)
	{

		Sleep(50);
		void *value = (void *)(imageBasedxplus + 0x1F846F0);
		memcpy(value, customNamedxp, strlen(customNamedxp) + 1);

	}
}

static DWORD WINAPI SpamMulticast(LPVOID)
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

	int ttl = 255;
	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));

	int reuse = 1;
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));

	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&reuse, sizeof(reuse));

	sockaddr_in bindAddr = { 0 };
	bindAddr.sin_family = AF_INET;
	bindAddr.sin_addr.s_addr = inet_addr(ipaddrdxplus);
	bindAddr.sin_port = htons(50765);
	bind(sock, (sockaddr*)&bindAddr, sizeof(bindAddr));

	ip_mreq mreq;
	mreq.imr_multiaddr.s_addr = inet_addr("225.0.0.1");
	mreq.imr_interface.s_addr = inet_addr(ipaddrdxplus);

	setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));

	const uint8_t* byteSequences_Free[] = {
		dxpterminalPackage1_Free,
		dxpterminalPackage2_Free,
		dxpterminalPackage3_Free,
		dxpterminalPackage4_Free,
		dxpterminalPackage5_Free,
		dxpterminalPackage6_Free,
	};

	const size_t byteSizes_Free[] = {
		sizeof(dxpterminalPackage1_Free),
		sizeof(dxpterminalPackage2_Free),
		sizeof(dxpterminalPackage3_Free),
		sizeof(dxpterminalPackage4_Free),
		sizeof(dxpterminalPackage5_Free),
		sizeof(dxpterminalPackage6_Free),
	};

	const uint8_t* byteSequences_Event2P[] = {
		dxpterminalPackage1_Event2P,
		dxpterminalPackage2_Event2P,
		dxpterminalPackage3_Event2P,
		dxpterminalPackage4_Event2P,
		dxpterminalPackage5_Event2P,
		dxpterminalPackage6_Event2P,
	};

	const size_t byteSizes_Event2P[] = {
		sizeof(dxpterminalPackage1_Event2P),
		sizeof(dxpterminalPackage2_Event2P),
		sizeof(dxpterminalPackage3_Event2P),
		sizeof(dxpterminalPackage4_Event2P),
		sizeof(dxpterminalPackage5_Event2P),
		sizeof(dxpterminalPackage6_Event2P),
	};

	const uint8_t* byteSequences_Event4P[] = {
		dxpterminalPackage1_Event4P,
		dxpterminalPackage2_Event4P,
		dxpterminalPackage3_Event4P,
		dxpterminalPackage4_Event4P,
		dxpterminalPackage5_Event4P,
		dxpterminalPackage6_Event4P,
	};

	const size_t byteSizes_Event4P[] = {
		sizeof(dxpterminalPackage1_Event4P),
		sizeof(dxpterminalPackage2_Event4P),
		sizeof(dxpterminalPackage3_Event4P),
		sizeof(dxpterminalPackage4_Event4P),
		sizeof(dxpterminalPackage5_Event4P),
		sizeof(dxpterminalPackage6_Event4P),
	};

	const uint8_t* byteSequences_Coin[] = {
		dxpterminalPackage1_Coin,
		dxpterminalPackage2_Coin,
		dxpterminalPackage3_Coin,
		dxpterminalPackage4_Coin,
		dxpterminalPackage5_Coin,
		dxpterminalPackage6_Coin,
	};

	const size_t byteSizes_Coin[] = {
		sizeof(dxpterminalPackage1_Coin),
		sizeof(dxpterminalPackage2_Coin),
		sizeof(dxpterminalPackage3_Coin),
		sizeof(dxpterminalPackage4_Coin),
		sizeof(dxpterminalPackage5_Coin),
		sizeof(dxpterminalPackage6_Coin),
	};

	sockaddr_in toAddr = { 0 };
	toAddr.sin_family = AF_INET;
	toAddr.sin_addr.s_addr = inet_addr("225.0.0.1");
	toAddr.sin_port = htons(50765);

	isFreePlay = ToBool(config["General"]["FreePlay"]);
	isEventMode2P = ToBool(config["TerminalEmuConfig"]["2P Event Mode"]);
	isEventMode4P = ToBool(config["TerminalEmuConfig"]["4P Event Mode"]);

	if (isFreePlay)
	{
		if (isEventMode2P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event2P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event2P[i], byteSizes_Event2P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else if (isEventMode4P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event4P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event4P[i], byteSizes_Event4P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else {
			while (true) for (int i = 0; i < _countof(byteSequences_Free); i++)
			{
				sendto(sock, (const char*)byteSequences_Free[i], byteSizes_Free[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
	}

	while (true) for (int i = 0; i < _countof(byteSequences_Coin); i++)
	{
		sendto(sock, (const char*)byteSequences_Coin[i], byteSizes_Coin[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
		Sleep(8);
	}
}

/*
extern int* ffbOffset;
extern int* ffbOffset2;
extern int* ffbOffset3;
extern int* ffbOffset4;

DWORD WINAPI Wmmt5FfbCollector(void* ctx)
{
	uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0);
	while (true)
	{
		*ffbOffset = *(DWORD *)(imageBase + 0x196F188);
		*ffbOffset2 = *(DWORD *)(imageBase + 0x196F18c);
		*ffbOffset3 = *(DWORD *)(imageBase + 0x196F190);
		*ffbOffset4 = *(DWORD *)(imageBase + 0x196F194);
		Sleep(10);
	}
}*/

static InitFunction Wmmt5Func([]()
{/*
	FILE* fileF = _wfopen(L"Fsetting.lua.gz", L"r");
	if (fileF == NULL)
	{
		FILE* settingsF = _wfopen(L"Fsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsF);
		fclose(settingsF);
	}
	else
	{
		fclose(fileF);
	}

	FILE* fileG = _wfopen(L"Gsetting.lua.gz", L"r");
	if (fileG == NULL)
	{
		FILE* settingsG = _wfopen(L"Gsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsG);
		fclose(settingsG);
	}
	else
	{
		fclose(fileG);
	}*/

	bool isTerminal = false;
	if (ToBool(config["General"]["TerminalMode"]))
	{
		isTerminal = true;
	}

	std::string networkip = config["General"]["NetworkAdapterIP"];
	if (!networkip.empty())
	{
		ipaddrdxplus = networkip.c_str();
	}

	hookPort = "COM3";
	imageBasedxplus = (uintptr_t)GetModuleHandleA(0);
	MH_Initialize();

	// Hook dongle funcs
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_write", dxpHook_hasp_write, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_read", dxpHook_hasp_read, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_get_size", dxpHook_hasp_get_size, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_decrypt", dxpHook_hasp_decrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_encrypt", dxpHook_hasp_encrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_logout", dxpHook_hasp_logout, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_login", dxpHook_hasp_login, NULL);

	GenerateDongleDataDxp(isTerminal);

	//prevents game from setting time, thanks pockywitch!
	MH_CreateHookApi(L"KERNEL32", "SetSystemTime", Hook_SetSystemTime, reinterpret_cast<LPVOID*>(&pSetSystemTime));

	// Patch some check TEMP DISABLE AS WELL OVER HERE
	// NOT WORKING 1
	// FOUND ON 1
	injector::WriteMemory<uint8_t>(hook::get_pattern("85 C9 0F 94 C0 84 C0 0F 94 C0 84 C0 75 ? 40 32 F6 EB ?", 0x15), 0, true); //patches out dongle error2 (doomer)

	// Patch some jnz
	// FOUND ON 1
	injector::MakeNOP(hook::get_pattern("83 C0 FD 83 F8 01 76 ? 49 8D ? ? ? ? 00 00"), 6);

	// Patch some shit
	// NOT FOUND:

	// Skip weird camera init that stucks entire pc on certain brands. TESTED ONLY ON 05!!!!
	if (ToBool(config["General"]["WhiteScreenFix"]))
	{
		injector::WriteMemory<DWORD>(hook::get_pattern("48 8B C4 55 57 41 54 41 55 41 56 48 8D 68 A1 48 81 EC 90 00 00 00 48 C7 45 D7 FE FF FF FF 48 89 58 08 48 89 70 18 45 33 F6 4C 89 75 DF 33 C0 48 89 45 E7", 0), 0x90C3C032, true);
	}

	// Patch some call
	// 45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ?? ?? ?? ?? 48 8B 08
	//THIS injector::MakeNOP(hook::get_pattern("45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ? ? ? ? 48 8B 08", 12), 5);

	{
		// 199AE18 TIME OFFSET RVA temp disable ALL JNZ PATCH

		auto location = hook::get_pattern<char>("41 3B C7 74 0E 48 8D 8F B8 00 00 00 BA F6 01 00 00 EB 6E 48 8D 8F A0 00 00 00");
		// Patch some jnz
		injector::WriteMemory<uint8_t>(location + 3, 0xEB, true); //patches content router (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x22, 2); //patches ip addr error again (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x33, 2); //patches ip aaddr error(doomer)
	}

	// Skip DebugBreak on MFStartup fail
	{
		/*
		auto location = hook::get_pattern<char>("48 83 EC 28 33 D2 B9 70 00 02 00 E8 ? ? ? ? 85 C0 79 06");
		injector::WriteMemory<uint8_t>(location + 0x12, 0xEB, true);
		*/
	}

	if (isTerminal)
	{
		// Patch some func to 1
		// NOT FOUND:
		//safeJMP(hook::get_pattern("0F B6 41 05 2C 30 3C 09 77 04 0F BE C0 C3 83 C8 FF C3"), ReturnTrue);

		// Patch some func to 1
	}
	else
	{
		// Disregard terminal scanner stuff.

		{

			/*
			auto location = hook::get_pattern<char>("48 8B 18 48 3B D8 0F 84 8B 00 00 00 0F 1F 80 00 00 00 00 39 73 1C 74 5C 80 7B 31 00");
			injector::MakeNOP(location + 0xF, 2); // 0xF
			*/
			injector::MakeNOP(imageBasedxplus + 0x9F2BB3, 2);
		}

		// spam thread
		if (ToBool(config["General"]["TerminalEmulator"]))
		{
			CreateThread(0, 0, SpamMulticast, 0, 0, 0);
		}
	}

	auto chars = { 'F', 'G' };

	for (auto cha : chars)
	{
		auto patterns = hook::pattern(va("%02X 3A 2F", cha));

		if (patterns.size() > 0)
		{
			for (int i = 0; i < patterns.size(); i++)
			{
				char* text = patterns.get(i).get<char>(0);
				std::string text_str(text);

				std::string to_replace = va("%c:/", cha);
				std::string replace_with = va("./%c", cha);

				std::string replaced = text_str.replace(0, to_replace.length(), replace_with);

				injector::WriteMemoryRaw(text, (char*)replaced.c_str(), replaced.length() + 1, true);
			}
		}
	}

	if (ToBool(config["General"]["SkipMovies"]))
	{
		// Skip movies fuck you wmmt5
	}

	std::string value = config["General"]["CustomName"];
	if (!value.empty())
	{

		memset(customNamedxp, 0, 256);
		strcpy(customNamedxp, value.c_str());
		CreateThread(0, 0, SpamcustomNamedxp, 0, 0, 0);

	}

	// Save story stuff (only 05)
	{

		// skip erasing of temp card data
		/*
		// Skip erasing of temp card
		safeJMP(imageBase + 0x54DCE1, LoadGameData);
		safeJMP(imageBase + 0x5612F0, ReturnTrue);
		safeJMP(imageBase + 0x5753C0, ReturnTrue);
		safeJMP(imageBase + 0x57DF10, ReturnTrue);

		safeJMP(imageBase + 0x92DB20, ReturnTrue);
		safeJMP(imageBase + 0x5628C0, ReturnTrue);
		safeJMP(imageBase + 0x579090, ReturnTrue);

		// Skip more
		safeJMP(imageBase + 0x54B0F0, ReturnTrue);
		safeJMP(imageBase + 0x909DB0, ReturnTrue);
		safeJMP(imageBase + 0x59FD90, ReturnTrue);
		safeJMP(imageBase + 0x5A0030, ReturnTrue);
		safeJMP(imageBase + 0x915370, ReturnTrue);
		safeJMP(imageBase + 0x5507A0, ReturnTrue);
		safeJMP(imageBase + 0x561290, ReturnTrue);

		safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData);

		// crash fix

		// Save progress trigger
		injector::WriteMemory<WORD>(imageBase + 0x556CE3, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x556CE3 + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBase + 0x556CED, 0x9090D0FF, true);

		// Try save later!
		injector::MakeNOP(imageBase + 0x308546, 0x12);
		injector::WriteMemory<WORD>(imageBase + 0x308546, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x308546 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBase + 0x308550, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBase + 0x308550 + 4, 0x90C0, true);

		CreateThread(0, 0, Wmmt5FfbCollector, 0, 0, 0);
		*/

		// Enable all print
		injector::MakeNOP(imageBasedxplus + 0x898BD3, 6);

		//load car trigger
		safeJMP(imageBasedxplus + 0x72AB90, loadCar);

		//save car trigger

		injector::MakeNOP(imageBasedxplus + 0x376F76, 0x12);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F76, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x376F76 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x376F80, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F80 + 4, 0x90C0, true);

		//prevents startup saving
		injector::WriteMemory<WORD>(imageBasedxplus + 0x6B909A, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x6B909A + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x6B90A4, 0x9090D0FF, true);

	}

	MH_EnableHook(MH_ALL_HOOKS);

}, GameID::WMMT5DXPlus);
#endif
#pragma optimize("", on)


for (int i = 0; i < _countof(byteSequences_Event4P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event4P[i], byteSizes_Event4P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}

		}
		else {
			while (true) for (int i = 0; i < _countof(byteSequences_Free); i++)
			{
				sendto(sock, (const char*)byteSequences_Free[i], byteSizes_Free[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
	}

	while (true) for (int i = 0; i < _countof(byteSequences_Coin); i++)
	{
		sendto(sock, (const char*)byteSequences_Coin[i], byteSizes_Coin[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
		Sleep(8);
	}
}

/*
extern int* ffbOffset;
extern int* ffbOffset2;
extern int* ffbOffset3;
extern int* ffbOffset4;

DWORD WINAPI Wmmt5FfbCollector(void* ctx)
{
	uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0);
	while (true)
	{
		*ffbOffset = *(DWORD *)(imageBase + 0x196F188);
		*ffbOffset2 = *(DWORD *)(imageBase + 0x196F18c);
		*ffbOffset3 = *(DWORD *)(imageBase + 0x196F190);
		*ffbOffset4 = *(DWORD *)(imageBase + 0x196F194);
		Sleep(10);
	}
}*/

static InitFunction Wmmt5Func([]()
{/*
	FILE* fileF = _wfopen(L"Fsetting.lua.gz", L"r");
	if (fileF == NULL)
	{
		FILE* settingsF = _wfopen(L"Fsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsF);
		fclose(settingsF);
	}
	else
	{
		fclose(fileF);
	}

	FILE* fileG = _wfopen(L"Gsetting.lua.gz", L"r");
	if (fileG == NULL)
	{
		FILE* settingsG = _wfopen(L"Gsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsG);
		fclose(settingsG);
	}
	else
	{
		fclose(fileG);
	}*/

	bool isTerminal = false;
	if (ToBool(config["General"]["TerminalMode"]))
	{
		isTerminal = true;
	}

	std::string networkip = config["General"]["NetworkAdapterIP"];
	if (!networkip.empty())
	{
		ipaddrdxplus = networkip.c_str();
	}

	hookPort = "COM3";
	imageBasedxplus = (uintptr_t)GetModuleHandleA(0);
	MH_Initialize();

	// Hook dongle funcs
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_write", dxpHook_hasp_write, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_read", dxpHook_hasp_read, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_get_size", dxpHook_hasp_get_size, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_decrypt", dxpHook_hasp_decrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_encrypt", dxpHook_hasp_encrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_logout", dxpHook_hasp_logout, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_login", dxpHook_hasp_login, NULL);

	GenerateDongleDataDxp(isTerminal);

	//prevents game from setting time, thanks pockywitch!
	MH_CreateHookApi(L"KERNEL32", "SetSystemTime", Hook_SetSystemTime, reinterpret_cast<LPVOID*>(&pSetSystemTime));

	// Patch some check TEMP DISABLE AS WELL OVER HERE
	// NOT WORKING 1
	// FOUND ON 1
	injector::WriteMemory<uint8_t>(hook::get_pattern("85 C9 0F 94 C0 84 C0 0F 94 C0 84 C0 75 ? 40 32 F6 EB ?", 0x15), 0, true); //patches out dongle error2 (doomer)

	// Patch some jnz
	// FOUND ON 1
	injector::MakeNOP(hook::get_pattern("83 C0 FD 83 F8 01 76 ? 49 8D ? ? ? ? 00 00"), 6);

	// Patch some shit
	// NOT FOUND:

	// Skip weird camera init that stucks entire pc on certain brands. TESTED ONLY ON 05!!!!
	if (ToBool(config["General"]["WhiteScreenFix"]))
	{
		injector::WriteMemory<DWORD>(hook::get_pattern("48 8B C4 55 57 41 54 41 55 41 56 48 8D 68 A1 48 81 EC 90 00 00 00 48 C7 45 D7 FE FF FF FF 48 89 58 08 48 89 70 18 45 33 F6 4C 89 75 DF 33 C0 48 89 45 E7", 0), 0x90C3C032, true);
	}

	// Patch some call
	// 45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ?? ?? ?? ?? 48 8B 08
	//THIS injector::MakeNOP(hook::get_pattern("45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ? ? ? ? 48 8B 08", 12), 5);

	{
		// 199AE18 TIME OFFSET RVA temp disable ALL JNZ PATCH

		auto location = hook::get_pattern<char>("41 3B C7 74 0E 48 8D 8F B8 00 00 00 BA F6 01 00 00 EB 6E 48 8D 8F A0 00 00 00");
		// Patch some jnz
		injector::WriteMemory<uint8_t>(location + 3, 0xEB, true); //patches content router (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x22, 2); //patches ip addr error again (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x33, 2); //patches ip aaddr error(doomer)
	}

	// Skip DebugBreak on MFStartup fail
	{
		/*
		auto location = hook::get_pattern<char>("48 83 EC 28 33 D2 B9 70 00 02 00 E8 ? ? ? ? 85 C0 79 06");
		injector::WriteMemory<uint8_t>(location + 0x12, 0xEB, true);
		*/
	}

	if (isTerminal)
	{
		// Patch some func to 1
		// NOT FOUND:
		//safeJMP(hook::get_pattern("0F B6 41 05 2C 30 3C 09 77 04 0F BE C0 C3 83 C8 FF C3"), ReturnTrue);

		// Patch some func to 1
	}
	else
	{
		// Disregard terminal scanner stuff.

		{

			/*
			auto location = hook::get_pattern<char>("48 8B 18 48 3B D8 0F 84 8B 00 00 00 0F 1F 80 00 00 00 00 39 73 1C 74 5C 80 7B 31 00");
			injector::MakeNOP(location + 0xF, 2); // 0xF
			*/
			injector::MakeNOP(imageBasedxplus + 0x9F2BB3, 2);
		}

		// spam thread
		if (ToBool(config["General"]["TerminalEmulator"]))
		{
			CreateThread(0, 0, SpamMulticast, 0, 0, 0);
		}
	}

	auto chars = { 'F', 'G' };

	for (auto cha : chars)
	{
		auto patterns = hook::pattern(va("%02X 3A 2F", cha));

		if (patterns.size() > 0)
		{
			for (int i = 0; i < patterns.size(); i++)
			{
				char* text = patterns.get(i).get<char>(0);
				std::string text_str(text);

				std::string to_replace = va("%c:/", cha);
				std::string replace_with = va("./%c", cha);

				std::string replaced = text_str.replace(0, to_replace.length(), replace_with);

				injector::WriteMemoryRaw(text, (char*)replaced.c_str(), replaced.length() + 1, true);
			}
		}
	}

	if (ToBool(config["General"]["SkipMovies"]))
	{
		// Skip movies fuck you wmmt5
	}

	std::string value = config["General"]["CustomName"];
	if (!value.empty())
	{

		memset(customNamedxp, 0, 256);
		strcpy(customNamedxp, value.c_str());
		CreateThread(0, 0, SpamcustomNamedxp, 0, 0, 0);

	}

	// Save story stuff (only 05)
	{

		// skip erasing of temp card data
		/*
		// Skip erasing of temp card
		safeJMP(imageBase + 0x54DCE1, LoadGameData);
		safeJMP(imageBase + 0x5612F0, ReturnTrue);
		safeJMP(imageBase + 0x5753C0, ReturnTrue);
		safeJMP(imageBase + 0x57DF10, ReturnTrue);

		safeJMP(imageBase + 0x92DB20, ReturnTrue);
		safeJMP(imageBase + 0x5628C0, ReturnTrue);
		safeJMP(imageBase + 0x579090, ReturnTrue);

		// Skip more
		safeJMP(imageBase + 0x54B0F0, ReturnTrue);
		safeJMP(imageBase + 0x909DB0, ReturnTrue);
		safeJMP(imageBase + 0x59FD90, ReturnTrue);
		safeJMP(imageBase + 0x5A0030, ReturnTrue);
		safeJMP(imageBase + 0x915370, ReturnTrue);
		safeJMP(imageBase + 0x5507A0, ReturnTrue);
		safeJMP(imageBase + 0x561290, ReturnTrue);

		safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData);

		// crash fix

		// Save progress trigger
		injector::WriteMemory<WORD>(imageBase + 0x556CE3, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x556CE3 + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBase + 0x556CED, 0x9090D0FF, true);

		// Try save later!
		injector::MakeNOP(imageBase + 0x308546, 0x12);
		injector::WriteMemory<WORD>(imageBase + 0x308546, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x308546 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBase + 0x308550, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBase + 0x308550 + 4, 0x90C0, true);

		CreateThread(0, 0, Wmmt5FfbCollector, 0, 0, 0);
		*/

		// Enable all print
		injector::MakeNOP(imageBasedxplus + 0x898BD3, 6);

		//load car trigger
		safeJMP(imageBasedxplus + 0x72AB90, loadCar);

		//save car trigger

		injector::MakeNOP(imageBasedxplus + 0x376F76, 0x12);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F76, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x376F76 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x376F80, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F80 + 4, 0x90C0, true);

		//prevents startup saving
		injector::WriteMemory<WORD>(imageBasedxplus + 0x6B909A, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x6B909A + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x6B90A4, 0x9090D0FF, true);

	}

	MH_EnableHook(MH_ALL_HOOKS);

}, GameID::WMMT5DXPlus);
#endif
#pragma optimize("", on)


while (true)
	{

		Sleep(50);
		void *value = (void *)(imageBasedxplus + 0x1F846F0);
		memcpy(value, customNamedxp, strlen(customNamedxp) + 1);

	}

}

static DWORD WINAPI SpamMulticast(LPVOID)
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

	int ttl = 255;
	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&ttl, sizeof(ttl));

	int reuse = 1;
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse));

	setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&reuse, sizeof(reuse));

	sockaddr_in bindAddr = { 0 };
	bindAddr.sin_family = AF_INET;
	bindAddr.sin_addr.s_addr = inet_addr(ipaddrdxplus);
	bindAddr.sin_port = htons(50765);
	bind(sock, (sockaddr*)&bindAddr, sizeof(bindAddr));

	ip_mreq mreq;
	mreq.imr_multiaddr.s_addr = inet_addr("225.0.0.1");
	mreq.imr_interface.s_addr = inet_addr(ipaddrdxplus);

	setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq));

	const uint8_t* byteSequences_Free[] = {
		dxpterminalPackage1_Free,
		dxpterminalPackage2_Free,
		dxpterminalPackage3_Free,
		dxpterminalPackage4_Free,
		dxpterminalPackage5_Free,
		dxpterminalPackage6_Free,
	};

	const size_t byteSizes_Free[] = {
		sizeof(dxpterminalPackage1_Free),
		sizeof(dxpterminalPackage2_Free),
		sizeof(dxpterminalPackage3_Free),
		sizeof(dxpterminalPackage4_Free),
		sizeof(dxpterminalPackage5_Free),
		sizeof(dxpterminalPackage6_Free),
	};

	const uint8_t* byteSequences_Event2P[] = {
		dxpterminalPackage1_Event2P,
		dxpterminalPackage2_Event2P,
		dxpterminalPackage3_Event2P,
		dxpterminalPackage4_Event2P,
		dxpterminalPackage5_Event2P,
		dxpterminalPackage6_Event2P,
	};

	const size_t byteSizes_Event2P[] = {
		sizeof(dxpterminalPackage1_Event2P),
		sizeof(dxpterminalPackage2_Event2P),
		sizeof(dxpterminalPackage3_Event2P),
		sizeof(dxpterminalPackage4_Event2P),
		sizeof(dxpterminalPackage5_Event2P),
		sizeof(dxpterminalPackage6_Event2P),
	};

	const uint8_t* byteSequences_Event4P[] = {
		dxpterminalPackage1_Event4P,
		dxpterminalPackage2_Event4P,
		dxpterminalPackage3_Event4P,
		dxpterminalPackage4_Event4P,
		dxpterminalPackage5_Event4P,
		dxpterminalPackage6_Event4P,
	};

	const size_t byteSizes_Event4P[] = {
		sizeof(dxpterminalPackage1_Event4P),
		sizeof(dxpterminalPackage2_Event4P),
		sizeof(dxpterminalPackage3_Event4P),
		sizeof(dxpterminalPackage4_Event4P),
		sizeof(dxpterminalPackage5_Event4P),
		sizeof(dxpterminalPackage6_Event4P),
	};

	const uint8_t* byteSequences_Coin[] = {
		dxpterminalPackage1_Coin,
		dxpterminalPackage2_Coin,
		dxpterminalPackage3_Coin,
		dxpterminalPackage4_Coin,
		dxpterminalPackage5_Coin,
		dxpterminalPackage6_Coin,
	};

	const size_t byteSizes_Coin[] = {
		sizeof(dxpterminalPackage1_Coin),
		sizeof(dxpterminalPackage2_Coin),
		sizeof(dxpterminalPackage3_Coin),
		sizeof(dxpterminalPackage4_Coin),
		sizeof(dxpterminalPackage5_Coin),
		sizeof(dxpterminalPackage6_Coin),
	};

	sockaddr_in toAddr = { 0 };
	toAddr.sin_family = AF_INET;
	toAddr.sin_addr.s_addr = inet_addr("225.0.0.1");
	toAddr.sin_port = htons(50765);

	isFreePlay = ToBool(config["General"]["FreePlay"]);
	isEventMode2P = ToBool(config["TerminalEmuConfig"]["2P Event Mode"]);
	isEventMode4P = ToBool(config["TerminalEmuConfig"]["4P Event Mode"]);

	if (isFreePlay)
	{
		if (isEventMode2P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event2P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event2P[i], byteSizes_Event2P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else if (isEventMode4P) {
			while (true) for (int i = 0; i < _countof(byteSequences_Event4P); i++)
			{
				sendto(sock, (const char*)byteSequences_Event4P[i], byteSizes_Event4P[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
		else {
			while (true) for (int i = 0; i < _countof(byteSequences_Free); i++)
			{
				sendto(sock, (const char*)byteSequences_Free[i], byteSizes_Free[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
				Sleep(8);
			}
		}
	}

	while (true) for (int i = 0; i < _countof(byteSequences_Coin); i++)
	{
		sendto(sock, (const char*)byteSequences_Coin[i], byteSizes_Coin[i], 0, (sockaddr*)&toAddr, sizeof(toAddr));
		Sleep(8);
	}
}

/*
extern int* ffbOffset;
extern int* ffbOffset2;
extern int* ffbOffset3;
extern int* ffbOffset4;

DWORD WINAPI Wmmt5FfbCollector(void* ctx)
{
	uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0);
	while (true)
	{
		*ffbOffset = *(DWORD *)(imageBase + 0x196F188);
		*ffbOffset2 = *(DWORD *)(imageBase + 0x196F18c);
		*ffbOffset3 = *(DWORD *)(imageBase + 0x196F190);
		*ffbOffset4 = *(DWORD *)(imageBase + 0x196F194);
		Sleep(10);
	}
}*/

static InitFunction Wmmt5Func([]()
{/*
	FILE* fileF = _wfopen(L"Fsetting.lua.gz", L"r");
	if (fileF == NULL)
	{
		FILE* settingsF = _wfopen(L"Fsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsF);
		fclose(settingsF);
	}
	else
	{
		fclose(fileF);
	}

	FILE* fileG = _wfopen(L"Gsetting.lua.gz", L"r");
	if (fileG == NULL)
	{
		FILE* settingsG = _wfopen(L"Gsetting.lua.gz", L"wb");
		fwrite(settingData, 1, sizeof(settingData), settingsG);
		fclose(settingsG);
	}
	else
	{
		fclose(fileG);
	}*/

	bool isTerminal = false;
	if (ToBool(config["General"]["TerminalMode"]))
	{
		isTerminal = true;
	}

	std::string networkip = config["General"]["NetworkAdapterIP"];
	if (!networkip.empty())
	{
		ipaddrdxplus = networkip.c_str();
	}

	hookPort = "COM3";
	imageBasedxplus = (uintptr_t)GetModuleHandleA(0);
	MH_Initialize();

	// Hook dongle funcs
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_write", dxpHook_hasp_write, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_read", dxpHook_hasp_read, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_get_size", dxpHook_hasp_get_size, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_decrypt", dxpHook_hasp_decrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_encrypt", dxpHook_hasp_encrypt, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_logout", dxpHook_hasp_logout, NULL);
	MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_login", dxpHook_hasp_login, NULL);

	GenerateDongleDataDxp(isTerminal);

	//prevents game from setting time, thanks pockywitch!
	MH_CreateHookApi(L"KERNEL32", "SetSystemTime", Hook_SetSystemTime, reinterpret_cast<LPVOID*>(&pSetSystemTime));

	// Patch some check TEMP DISABLE AS WELL OVER HERE
	// NOT WORKING 1
	// FOUND ON 1
	injector::WriteMemory<uint8_t>(hook::get_pattern("85 C9 0F 94 C0 84 C0 0F 94 C0 84 C0 75 ? 40 32 F6 EB ?", 0x15), 0, true); //patches out dongle error2 (doomer)

	// Patch some jnz
	// FOUND ON 1
	injector::MakeNOP(hook::get_pattern("83 C0 FD 83 F8 01 76 ? 49 8D ? ? ? ? 00 00"), 6);

	// Patch some shit
	// NOT FOUND:

	// Skip weird camera init that stucks entire pc on certain brands. TESTED ONLY ON 05!!!!
	if (ToBool(config["General"]["WhiteScreenFix"]))
	{
		injector::WriteMemory<DWORD>(hook::get_pattern("48 8B C4 55 57 41 54 41 55 41 56 48 8D 68 A1 48 81 EC 90 00 00 00 48 C7 45 D7 FE FF FF FF 48 89 58 08 48 89 70 18 45 33 F6 4C 89 75 DF 33 C0 48 89 45 E7", 0), 0x90C3C032, true);
	}

	// Patch some call
	// 45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ?? ?? ?? ?? 48 8B 08
	//THIS injector::MakeNOP(hook::get_pattern("45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ? ? ? ? 48 8B 08", 12), 5);

	{
		// 199AE18 TIME OFFSET RVA temp disable ALL JNZ PATCH

		auto location = hook::get_pattern<char>("41 3B C7 74 0E 48 8D 8F B8 00 00 00 BA F6 01 00 00 EB 6E 48 8D 8F A0 00 00 00");
		// Patch some jnz
		injector::WriteMemory<uint8_t>(location + 3, 0xEB, true); //patches content router (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x22, 2); //patches ip addr error again (doomer)

		// Skip some jnz
		injector::MakeNOP(location + 0x33, 2); //patches ip aaddr error(doomer)
	}

	// Skip DebugBreak on MFStartup fail
	{
		/*
		auto location = hook::get_pattern<char>("48 83 EC 28 33 D2 B9 70 00 02 00 E8 ? ? ? ? 85 C0 79 06");
		injector::WriteMemory<uint8_t>(location + 0x12, 0xEB, true);
		*/
	}

	if (isTerminal)
	{
		// Patch some func to 1
		// NOT FOUND:
		//safeJMP(hook::get_pattern("0F B6 41 05 2C 30 3C 09 77 04 0F BE C0 C3 83 C8 FF C3"), ReturnTrue);

		// Patch some func to 1
	}
	else
	{
		// Disregard terminal scanner stuff.

		{

			/*
			auto location = hook::get_pattern<char>("48 8B 18 48 3B D8 0F 84 8B 00 00 00 0F 1F 80 00 00 00 00 39 73 1C 74 5C 80 7B 31 00");
			injector::MakeNOP(location + 0xF, 2); // 0xF
			*/
			injector::MakeNOP(imageBasedxplus + 0x9F2BB3, 2);
		}

		// spam thread
		if (ToBool(config["General"]["TerminalEmulator"]))
		{
			CreateThread(0, 0, SpamMulticast, 0, 0, 0);
		}
	}

	auto chars = { 'F', 'G' };

	for (auto cha : chars)
	{
		auto patterns = hook::pattern(va("%02X 3A 2F", cha));

		if (patterns.size() > 0)
		{
			for (int i = 0; i < patterns.size(); i++)
			{
				char* text = patterns.get(i).get<char>(0);
				std::string text_str(text);

				std::string to_replace = va("%c:/", cha);
				std::string replace_with = va("./%c", cha);

				std::string replaced = text_str.replace(0, to_replace.length(), replace_with);

				injector::WriteMemoryRaw(text, (char*)replaced.c_str(), replaced.length() + 1, true);
			}
		}
	}

	if (ToBool(config["General"]["SkipMovies"]))
	{
		// Skip movies fuck you wmmt5
	}

	std::string value = config["General"]["CustomName"];
	if (!value.empty())
	{

		memset(customNamedxp, 0, 256);
		strcpy(customNamedxp, value.c_str());
		CreateThread(0, 0, SpamcustomNamedxp, 0, 0, 0);

	}

	// Save story stuff (only 05)
	{

		// skip erasing of temp card data
		/*
		// Skip erasing of temp card
		safeJMP(imageBase + 0x54DCE1, LoadGameData);
		safeJMP(imageBase + 0x5612F0, ReturnTrue);
		safeJMP(imageBase + 0x5753C0, ReturnTrue);
		safeJMP(imageBase + 0x57DF10, ReturnTrue);

		safeJMP(imageBase + 0x92DB20, ReturnTrue);
		safeJMP(imageBase + 0x5628C0, ReturnTrue);
		safeJMP(imageBase + 0x579090, ReturnTrue);

		// Skip more
		safeJMP(imageBase + 0x54B0F0, ReturnTrue);
		safeJMP(imageBase + 0x909DB0, ReturnTrue);
		safeJMP(imageBase + 0x59FD90, ReturnTrue);
		safeJMP(imageBase + 0x5A0030, ReturnTrue);
		safeJMP(imageBase + 0x915370, ReturnTrue);
		safeJMP(imageBase + 0x5507A0, ReturnTrue);
		safeJMP(imageBase + 0x561290, ReturnTrue);

		safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData);

		// crash fix

		// Save progress trigger
		injector::WriteMemory<WORD>(imageBase + 0x556CE3, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x556CE3 + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBase + 0x556CED, 0x9090D0FF, true);

		// Try save later!
		injector::MakeNOP(imageBase + 0x308546, 0x12);
		injector::WriteMemory<WORD>(imageBase + 0x308546, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBase + 0x308546 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBase + 0x308550, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBase + 0x308550 + 4, 0x90C0, true);

		CreateThread(0, 0, Wmmt5FfbCollector, 0, 0, 0);
		*/

		// Enable all print
		injector::MakeNOP(imageBasedxplus + 0x898BD3, 6);

		//load car trigger
		safeJMP(imageBasedxplus + 0x72AB90, loadCar);

		//save car trigger

		injector::MakeNOP(imageBasedxplus + 0x376F76, 0x12);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F76, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x376F76 + 2, (uintptr_t)SaveGameData, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x376F80, 0x3348D0FF, true);
		injector::WriteMemory<WORD>(imageBasedxplus + 0x376F80 + 4, 0x90C0, true);

		//prevents startup saving
		injector::WriteMemory<WORD>(imageBasedxplus + 0x6B909A, 0xB848, true);
		injector::WriteMemory<uintptr_t>(imageBasedxplus + 0x6B909A + 2, (uintptr_t)SaveOk, true);
		injector::WriteMemory<DWORD>(imageBasedxplus + 0x6B90A4, 0x9090D0FF, true);

	}

	MH_EnableHook(MH_ALL_HOOKS);

}, GameID::WMMT5DXPlus);
#endif
#pragma optimize("", on)


bool gstAssetManager::ImportVector(const std::string& folder,
                                   const VectorProductImportRequest& asset,
                                   QString& msg)

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>
#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::CancelVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

{
  VectorProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::VectorProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing vector asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::ImportRaster(const std::string& folder,
                                   const RasterProductImportRequest& asset,
                                   QString& msg) {
  RasterProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::RasterProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing raster asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::makeDir(const std::string& assetdir, QString &error)
{
  if (khExists(AssetDefs::AssetPathToFilename(assetdir))) {
    error = kh::tr("'%1' already exists").arg(assetdir.c_str());
    return false;
  }

  return khAssetManagerProxy::MakeAssetDir(assetdir, error);
}


{
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>
#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error)

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::CancelVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::ImportVector(const std::string& folder,
                                   const VectorProductImportRequest& asset,
                                   QString& msg) {
  VectorProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::VectorProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing vector asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::ImportRaster(const std::string& folder,
                                   const RasterProductImportRequest& asset,
                                   QString& msg) {
  RasterProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::RasterProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing raster asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::makeDir(const std::string& assetdir, QString &error)
{
  if (khExists(AssetDefs::AssetPathToFilename(assetdir))) {
    error = kh::tr("'%1' already exists").arg(assetdir.c_str());
    return false;
  }

  return khAssetManagerProxy::MakeAssetDir(assetdir, error);
}


#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>
#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error)

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::CancelVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::ImportVector(const std::string& folder,
                                   const VectorProductImportRequest& asset,
                                   QString& msg) {
  VectorProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::VectorProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing vector asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::ImportRaster(const std::string& folder,
                                   const RasterProductImportRequest& asset,
                                   QString& msg) {
  RasterProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::RasterProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing raster asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::makeDir(const std::string& assetdir, QString &error)
{
  if (khExists(AssetDefs::AssetPathToFilename(assetdir))) {
    error = kh::tr("'%1' already exists").arg(assetdir.c_str());
    return false;
  }

  return khAssetManagerProxy::MakeAssetDir(assetdir, error);
}


#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>
#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  if (ver) {
    return khAssetManagerProxy::CancelVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::ImportVector(const std::string& folder,
                                   const VectorProductImportRequest& asset,
                                   QString& msg) {
  VectorProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::VectorProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing vector asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::ImportRaster(const std::string& folder,
                                   const RasterProductImportRequest& asset,
                                   QString& msg) {
  RasterProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::RasterProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing raster asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::makeDir(const std::string& assetdir, QString &error)
{
  if (khExists(AssetDefs::AssetPathToFilename(assetdir))) {
    error = kh::tr("'%1' already exists").arg(assetdir.c_str());
    return false;
  }

  return khAssetManagerProxy::MakeAssetDir(assetdir, error);
}


if (ver) {
    return khAssetManagerProxy::CancelVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>
#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());

bool gstAssetManager::ImportVector(const std::string& folder,
                                   const VectorProductImportRequest& asset,
                                   QString& msg) {
  VectorProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::VectorProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing vector asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::ImportRaster(const std::string& folder,
                                   const RasterProductImportRequest& asset,
                                   QString& msg) {
  RasterProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::RasterProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing raster asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::makeDir(const std::string& assetdir, QString &error)
{
  if (khExists(AssetDefs::AssetPathToFilename(assetdir))) {
    error = kh::tr("'%1' already exists").arg(assetdir.c_str());
    return false;
  }

  return khAssetManagerProxy::MakeAssetDir(assetdir, error);
}


#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>
#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->


if (!khAssetManagerProxy::VectorProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing vector asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>
#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::CancelVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::ImportVector(const std::string& folder,
                                   const VectorProductImportRequest& asset,
                                   QString& msg) {
  VectorProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  return true;
}

bool gstAssetManager::ImportRaster(const std::string& folder,
                                   const RasterProductImportRequest& asset,
                                   QString& msg) {
  RasterProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::RasterProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing raster asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::makeDir(const std::string& assetdir, QString &error)
{
  if (khExists(AssetDefs::AssetPathToFilename(assetdir))) {
    error = kh::tr("'%1' already exists").arg(assetdir.c_str());
    return false;
  }

  return khAssetManagerProxy::MakeAssetDir(assetdir, error);
}


#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
#include <fcntl.h>

#include <qstring.h>

#include <gstAssetManager.h>
#include <gstSource.h>
#include <gstKVPFile.h>
#include <gstKVPTable.h>
#include <autoingest/Asset.h>
#include <autoingest/khAssetManagerProxy.h>

#include <khException.h>
#include <khFileUtils.h>

gstAssetManager::gstAssetManager(const char* n)
    : assetroot(n) {
}

gstAssetManager::~gstAssetManager() {
}

bool gstAssetManager::buildAsset(const gstAssetHandle& handle, QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  bool needed;
  bool success = khAssetManagerProxy::BuildAsset(handle->getAsset()->GetRef(),
                                                 needed, error);
  if (success && !needed) {
    error = kh::tr("Nothing to do. Already up to date.");
    success = false;
  }
  return success;
}

bool gstAssetManager::rebuildAsset(const gstAssetHandle& handle,
                                   QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::RebuildVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::cancelAsset(const gstAssetHandle& handle,
                                  QString& error) {
  if (!handle->isValid()) {
    error = kh::tr("No asset specified");
    return false;
  }

  AssetVersion ver(handle->getAsset()->CurrVersionRef());
  if (ver) {
    return khAssetManagerProxy::CancelVersion(ver->GetRef(), error);
  } else {
    error = kh::tr("No current version");
    return false;
  }
}

bool gstAssetManager::ImportVector(const std::string& folder,
                                   const VectorProductImportRequest& asset,
                                   QString& msg) {
  VectorProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::VectorProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing vector asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::ImportRaster(const std::string& folder,
                                   const RasterProductImportRequest& asset,
                                   QString& msg) {
  RasterProductImportRequest req(asset);

  req.assetname =
    AssetDefs::FilenameToAssetPath(folder + "/" + asset.assetname);

  if (!khAssetManagerProxy::RasterProductImport(req, msg)) {
    notify(NFY_WARN,
           "Error importing raster asset named %s into directory %s\n%s\n",
           asset.assetname.c_str(), folder.c_str(),
           msg.latin1());
    return false;
  }

  return true;
}

bool gstAssetManager::makeDir(const std::string& assetdir, QString &error)
{
  if (khExists(AssetDefs::AssetPathToFilename(assetdir))) {
    error = kh::tr("'%1' already exists").arg(assetdir.c_str());
    return false;
  }

  return khAssetManagerProxy::MakeAssetDir(assetdir, error);
}


Element* MOSFET_sub::info_p(QString& Name,
			char* &BitmapFile, bool getNewOne)

/***************************************************************************
                              mosfet_sub.cpp
                             ----------------
    begin                : Fri Jun 4 2004
    email                : example@nnthink.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *                                                                         *
 ***************************************************************************/

#include "mosfet_sub.h"

Basic_MOSFET::Basic_MOSFET()
{
  // these must be the first properties in the list !!!
  Props.append(new Property("Type", "nfet", false,
	QObject::tr("polarity")+" [nfet, pfet]"));
  Props.append(new Property("Vt0", "1.0 V", true,
	QObject::tr("zero-bias threshold voltage")));

  Props.append(new Property("Kp", "2e-5", true,
	QObject::tr("transconductance coefficient in A/V^2")));
  Props.append(new Property("Gamma", "0.0", false,
	QObject::tr("bulk threshold in sqrt(V)")));
  Props.append(new Property("Phi", "0.6 V", false,
	QObject::tr("surface potential")));
  Props.append(new Property("Lambda", "0.0", true,
	QObject::tr("channel-length modulation parameter in 1/V")));
  Props.append(new Property("Rd", "0.0 Ohm", false,
	QObject::tr("drain ohmic resistance")));
  Props.append(new Property("Rs", "0.0 Ohm", false,
	QObject::tr("source ohmic resistance")));
  Props.append(new Property("Rg", "0.0 Ohm", false,
	QObject::tr("gate ohmic resistance")));
  Props.append(new Property("Is", "1e-14 A", false,
	QObject::tr("bulk junction saturation current")));
  Props.append(new Property("N", "1.0", false,
	QObject::tr("bulk junction emission coefficient")));
  Props.append(new Property("W", "1 um", false,
	QObject::tr("channel width")));
  Props.append(new Property("L", "1 um", false,
	QObject::tr("channel length")));
  Props.append(new Property("Ld", "0.0", false,
	QObject::tr("lateral diffusion length")));
  Props.append(new Property("Tox", "0.1 um", false,
	QObject::tr("oxide thickness")));
  Props.append(new Property("Cgso", "0.0", false,
	QObject::tr("gate-source overlap capacitance per meter of "
		    "channel width in F/m")));
  Props.append(new Property("Cgdo", "0.0", false,
	QObject::tr("gate-drain overlap capacitance per meter of "
		    "channel width in F/m")));
  Props.append(new Property("Cgbo", "0.0", false,
	QObject::tr("gate-bulk overlap capacitance per meter of "
		    "channel length in F/m")));
  Props.append(new Property("Cbd", "0.0 F", false,
	QObject::tr("zero-bias bulk-drain junction capacitance")));
  Props.append(new Property("Cbs", "0.0 F", false,
	QObject::tr("zero-bias bulk-source junction capacitance")));
  Props.append(new Property("Pb", "0.8 V", false,
	QObject::tr("bulk junction potential")));
  Props.append(new Property("Mj", "0.5", false,
	QObject::tr("bulk junction bottom grading coefficient")));
  Props.append(new Property("Fc", "0.5", false,
	QObject::tr("bulk junction forward-bias depletion capacitance "
		    "coefficient")));
  Props.append(new Property("Cjsw", "0.0", false,
	QObject::tr("zero-bias bulk junction periphery capacitance per meter "
		    "of junction perimeter in F/m")));
  Props.append(new Property("Mjsw", "0.33", false,
	QObject::tr("bulk junction periphery grading coefficient")));
  Props.append(new Property("Tt", "0.0 ps", false,
	QObject::tr("bulk transit time")));
  Props.append(new Property("Nsub", "0.0", false,
	QObject::tr("substrate bulk doping density in 1/cm^3")));
  Props.append(new Property("Nss", "0.0", false,
	QObject::tr("surface state density in 1/cm^2")));
  Props.append(new Property("Tpg", "1", false,
	QObject::tr("gate material type: 0 = alumina; -1 = same as bulk; "
		    "1 = opposite to bulk")));
  Props.append(new Property("Uo", "600.0", false,
	QObject::tr("surface mobility in cm^2/Vs")));
  Props.append(new Property("Rsh", "0.0", false,
	QObject::tr("drain and source diffusion sheet resistance in "
		    "Ohms/square")));
  Props.append(new Property("Nrd", "1", false,
	QObject::tr("number of equivalent drain squares")));
  Props.append(new Property("Nrs", "1", false,
	QObject::tr("number of equivalent source squares")));
  Props.append(new Property("Cj", "0.0", false,
	QObject::tr("zero-bias bulk junction bottom capacitance per square "
		    "meter of junction area in F/m^2")));
  Props.append(new Property("Js", "0.0", false,
	QObject::tr("bulk junction saturation current per square "
		    "meter of junction area in A/m^2")));
  Props.append(new Property("Ad", "0.0", false,
	QObject::tr("drain diffusion area in m^2")));
  Props.append(new Property("As", "0.0", false,
	QObject::tr("source diffusion area in m^2")));
  Props.append(new Property("Pd", "0.0 m", false,
	QObject::tr("drain junction perimeter")));
  Props.append(new Property("Ps", "0.0 m", false,
	QObject::tr("source junction perimeter")));
  Props.append(new Property("Kf", "0.0", false,
	QObject::tr("flicker noise coefficient")));
  Props.append(new Property("Af", "1.0", false,
	QObject::tr("flicker noise exponent")));
  Props.append(new Property("Ffe", "1.0", false,
	QObject::tr("flicker noise frequency exponent")));
  Props.append(new Property("Temp", "26.85", false,
	QObject::tr("simulation temperature in degree Celsius")));
  Props.append(new Property("Tnom", "26.85", false,
	QObject::tr("parameter measurement temperature")));

  Name  = "T";
}

MOSFET_sub::MOSFET_sub()
{
  Description = QObject::tr("MOS field-effect transistor with substrate");
  createSymbol();
  tx = x2+4;
  ty = y1+4;
  Model = "MOSFET";
}

Component* MOSFET_sub::newOne()
{
  MOSFET_sub* p = new MOSFET_sub();
  p->Props.first()->Value = Props.first()->Value;
  p->Props.next()->Value = Props.next()->Value;
  p->recreate(0);
  return p;
}

Element* MOSFET_sub::info(QString& Name, char* &BitmapFile, bool getNewOne)
{
  Name = QObject::tr("n-MOSFET");
  BitmapFile = (char *) "nmosfet_sub";

  if(getNewOne)  return new MOSFET_sub();
  return 0;
}

{
  Name = QObject::tr("p-MOSFET");
  BitmapFile = (char *) "pmosfet_sub";

  if(getNewOne) {
    MOSFET_sub* p = new MOSFET_sub();
    p->Props.first()->Value = "pfet";
    p->Props.next()->Value = "-1.0 V";
    p->recreate(0);
    return p;
  }
  return 0;
}

Element* MOSFET_sub::info_depl(QString& Name,
			char* &BitmapFile, bool getNewOne)
{
  Name = QObject::tr("depletion MOSFET");
  BitmapFile = (char *) "dmosfet_sub";

  if(getNewOne) {
    MOSFET_sub* p = new MOSFET_sub();
    p->Props.first();
    p->Props.next()->Value = "-1.0 V";
    p->recreate(0);
    return p;
  }
  return 0;
}

void MOSFET_sub::createSymbol()
{
  Lines.append(new Line(-14,-13,-14, 13,QPen(Qt::darkBlue,3)));
  Lines.append(new Line(-30,  0,-14,  0,QPen(Qt::darkBlue,2)));

  Lines.append(new Line(-10,-11,  0,-11,QPen(Qt::darkBlue,2)));
  Lines.append(new Line(  0,-11,  0,-30,QPen(Qt::darkBlue,2)));
  Lines.append(new Line(-10, 11,  0, 11,QPen(Qt::darkBlue,2)));
  Lines.append(new Line(  0, 11,  0, 30,QPen(Qt::darkBlue,2)));
  Lines.append(new Line(-10,  0, 20,  0,QPen(Qt::darkBlue,2)));

  Lines.append(new Line(-10,-16,-10, -7,QPen(Qt::darkBlue,3)));
  Lines.append(new Line(-10,  7,-10, 16,QPen(Qt::darkBlue,3)));

  Lines.append(new Line( -4, 24,  4, 20,QPen(Qt::darkBlue,2)));

  if(Props.first()->Value == "nfet") {
    Lines.append(new Line( -9,  0, -4, -5,QPen(Qt::darkBlue,2)));
    Lines.append(new Line( -9,  0, -4,  5,QPen(Qt::darkBlue,2)));
  }
  else {
    Lines.append(new Line( -1,  0, -6, -5,QPen(Qt::darkBlue,2)));
    Lines.append(new Line( -1,  0, -6,  5,QPen(Qt::darkBlue,2)));
  }

  if((Props.next()->Value.trimmed().at(0) == '-') ==
     (Props.first()->Value == "nfet"))
    Lines.append(new Line(-10, -8,-10,  8,QPen(Qt::darkBlue,3)));
  else
    Lines.append(new Line(-10, -4,-10,  4,QPen(Qt::darkBlue,3)));

  Ports.append(new Port(-30,  0));
  Ports.append(new Port(  0,-30));
  Ports.append(new Port(  0, 30));
  Ports.append(new Port( 20,  0));

  x1 = -30; y1 = -30;
  x2 =  30; y2 =  30;
}