/*=================================================================
	File created by Yohann NICOLAS.
	Add support 1.13d by L'Autour.
	Add support 1.14d and DoNotCloseNihlathakPortal by haxifix.

    @file D2wrapper.cpp
    @brief Main Diablo II extra DLL handler.

    This is the sources of the D2DLL class.

=================================================================*/

#include "plugYFiles.h"			// Install_PlugYFiles()
#include "globalVariable.h"		// Install_VariableOnRealm()
#include "commands.h"			// Install_Commands()
#include "othersFeatures.h"		// Install_ChangeResolution()
#include "mainScreen.h"			// Install_PrintPlugYVersion() Install_VersionChange()
#include "savePath.h"			// Install_ChangingSavePath()
#include "bigStash.h"			// Install_BigStash()
#include "skillPerLevelUp.h"	// Install_SkillPerLevelUp()
#include "statPerLevelUp.h"		// Install_StatPerLevelUp()
#include "statsPoints.h"		// Install_StatsPoints() Install_StatsLimitShiftClick()
#include "skillsPoints.h"		// Install_SkillsPoints()
#include "infinityStash.h"		// Install_MultiPageStash()
#include "newInterfaces.h"		// Install_NewInterfaces()
#include "worldEvent.h"			// Install_WorldEvent()
#include "uberQuest.h"			// Install_UberQuest()
#include "extraOptions.h"		// Install_AlwaysRegenMapInSP()
#include "language.h"			// Install_LanguageManagement()
#include "windowed.h"			// installed with Install_PrintPlugYVersion()
#include "savePlayerData.h"		// Install_SavePlayerData()
#include "customLibraries.h"
#include "common.h"


int version_Game = UNKNOWN;
//int version_binkw32 = UNKNOWN;
//int version_Bnclient = UNKNOWN;
int version_D2Client = UNKNOWN;
int version_D2CMP = UNKNOWN;
int version_D2Common = UNKNOWN;
//int version_D2DDraw = UNKNOWN;
//int version_D2Direct3D = UNKNOWN;
int version_D2Game = UNKNOWN;
//int version_D2Gdi = UNKNOWN;
int version_D2gfx = UNKNOWN;
//int version_D2Glide = UNKNOWN;
int version_D2Lang = UNKNOWN;
int version_D2Launch = UNKNOWN;
//int version_D2MCPClient = UNKNOWN;
//int version_D2Multi = UNKNOWN;
int version_D2Net = UNKNOWN;
//int version_D2sound = UNKNOWN;
int version_D2Win = UNKNOWN;
int version_Fog = UNKNOWN;
//int version_ijl11 = UNKNOWN;
//int version_SmackW32 = UNKNOWN;
int version_Storm = UNKNOWN;

DWORD	offset_Game = NULL;
//DWORD	offset_binkw32 = NULL;
//DWORD	offset_Bnclient = NULL;
DWORD	offset_D2Client = NULL;
DWORD	offset_D2CMP = NULL;
DWORD	offset_D2Common = NULL;
//DWORD	offset_D2DDraw = NULL;
//DWORD	offset_D2Direct3D = NULL;
DWORD	offset_D2Game = NULL;
//DWORD	offset_D2Gdi = NULL;
DWORD	offset_D2gfx = NULL;
//DWORD	offset_D2Glide = NULL;
DWORD	offset_D2Lang = NULL;
DWORD	offset_D2Launch = NULL;
//DWORD	offset_D2MCPClient = NULL;
//DWORD	offset_D2Multi = NULL;
DWORD	offset_D2Net = NULL;
//DWORD	offset_D2sound = NULL;
DWORD	offset_D2Win = NULL;
DWORD	offset_Fog = NULL;
//DWORD	offset_ijl11 = NULL;
//DWORD	offset_SmackW32 = NULL;
DWORD	offset_Storm = NULL;

const char* S_Game =		"Game.exe";
//const char* S_binkw32 =		"binkw32.dll";
//const char* S_Bnclient =	"Bnclient.dll";
const char* S_D2Client =	"D2Client.dll";
const char* S_D2CMP =		"D2CMP.dll";
const char* S_D2Common =	"D2Common.dll";
//const char* S_D2DDraw =		"D2DDraw.dll";
//const char* S_D2Direct3D =	"D2Direct3D.dll";
const char* S_D2Game =		"D2Game.dll";
//const char* S_D2Gdi =		"D2Gdi.dll";
const char* S_D2gfx =		"D2gfx.dll";
//const char* S_D2Glide =		"D2Glide.dll";
const char* S_D2Lang =		"D2Lang.dll";
const char* S_D2Launch =	"D2Launch.dll";
//const char* S_D2MCPClient =	"D2MCPClient.dll";
//const char* S_D2Multi =		"D2Multi.dll";
const char* S_D2Net =		"D2Net.dll";
//const char* S_D2sound =		"D2sound.dll";
const char* S_D2Win =		"D2Win.dll";
const char* S_Fog =			"Fog.dll";
//const char* S_ijl11 =		"ijl11.dll";
//const char* S_SmackW32 =	"SmackW32.dll";
const char* S_Storm =		"Storm.dll";

// Change the protection scheme of a loaded
// DLL called libraryName in memory space at address addr+size to allow us to customize it.
void hookLibrary(const char* libraryName, DWORD addr)
{
	DWORD dw=0;
	BYTE* offsetPESignature = addr + *(BYTE**)((BYTE*)addr + 0x3C);
	DWORD sizeOfCode = *(DWORD*)(offsetPESignature + 0x1C);
	BYTE* baseOfCode = addr + *(BYTE**)(offsetPESignature + 0x2C);
	if( !VirtualProtect(baseOfCode, sizeOfCode, PAGE_EXECUTE_READWRITE, &dw) )
	{
		log_msg("Failed to hook library : %s. (%08X,%08X)\n", libraryName ,baseOfCode, sizeOfCode);
		exit(-1);
	}
	log_msg("%s successfully hooked. (%08X,%08X)\n", libraryName ,baseOfCode, sizeOfCode);
}

void unhookLibrary(const char* libraryName, DWORD addr)
{
	DWORD dw=0;
	BYTE* offsetPESignature = addr + *(BYTE**)((BYTE*)addr + 0x3C);
	DWORD sizeOfCode = *(DWORD*)(offsetPESignature + 0x1C);
	BYTE* baseOfCode = addr + *(BYTE**)(offsetPESignature + 0x2C);
	if( !VirtualProtect(baseOfCode, sizeOfCode, PAGE_EXECUTE_READ, &dw) )
		log_msg("Failed to unhook library : %s. (%08X,%08X)\n", libraryName ,baseOfCode, sizeOfCode);
	else
		log_msg("%s successfully unhooked. (%08X,%08X)\n", libraryName ,baseOfCode, sizeOfCode);
}

void freeLibrary( DWORD library )
{
	if (library && library != offset_Game)
		FreeLibrary((HMODULE)library);
}

void freeD2Libraries()
{
	if (version_Game >= V114a)
		return;

	log_msg("***** Free Libraries *****\n");

//	freeLibrary( offset_binkw32 );
//	freeLibrary( offset_Bnclient );
	freeLibrary( offset_D2Client );
	freeLibrary( offset_D2CMP );
	freeLibrary( offset_D2Common );
//	freeLibrary( offset_D2DDraw );
//	freeLibrary( offset_D2Direct3D );
	freeLibrary( offset_D2Game );
//	freeLibrary( offset_D2Gdi );
	freeLibrary( offset_D2gfx );
//	freeLibrary( offset_D2Glide );
	freeLibrary( offset_D2Lang );
	freeLibrary( offset_D2Launch );
//	freeLibrary( offset_D2MCPClient );
//	freeLibrary( offset_D2Multi );
	freeLibrary( offset_D2Net );
//	freeLibrary( offset_D2sound );
	freeLibrary( offset_D2Win );
	freeLibrary( offset_Fog );
//	freeLibrary( offset_ijl11 );
//	freeLibrary( offset_SmackW32 );
	freeLibrary( offset_Storm );

	log_msg("\n\n");
}

void hookLibraries()
{
	log_msg("***** Unprotect Libraries *****\n");

	if (version_Game >= V114a)
		hookLibrary(S_Game, offset_Game);
	else
	{
		hookLibrary(S_D2Client,	offset_D2Client);
	//	hookLibrary(S_D2CMP,	offset_D2CMP);
		hookLibrary(S_D2Common,	offset_D2Common);
		hookLibrary(S_D2Game,	offset_D2Game);
		hookLibrary(S_D2gfx,	offset_D2gfx);
		hookLibrary(S_D2Lang,	offset_D2Lang);
		hookLibrary(S_D2Launch,	offset_D2Launch);
	//	hookLibrary(S_D2Net,	offset_D2Net);
	//	hookLibrary(S_D2Win,	offset_D2Win);
		hookLibrary(S_Fog,		offset_Fog);
		hookLibrary(S_Storm,	offset_Storm);
	}

	log_msg("\n\n");
}

void unhookLibraries()
{
	log_msg("***** Reprotect Libraries *****\n");

	if (version_Game >= V114a)
		unhookLibrary(S_Game,	offset_Game);
	else
	{
		unhookLibrary(S_D2Client,	offset_D2Client);
	//	unhookLibrary(S_D2CMP,		offset_D2CMP);
		unhookLibrary(S_D2Common,	offset_D2Common);
		unhookLibrary(S_D2Game,		offset_D2Game);
		unhookLibrary(S_D2gfx,		offset_D2gfx);
		unhookLibrary(S_D2Lang,		offset_D2Lang);
		unhookLibrary(S_D2Launch,	offset_D2Launch);
	//	unhookLibrary(S_D2Net,		offset_D2Net);
	//	unhookLibrary(S_D2Win,		offset_D2Win);
		unhookLibrary(S_Fog,		offset_Fog);
		unhookLibrary(S_Storm,		offset_Storm);
	}

	log_msg("\n\n");
}

void freeCustomLibraries()
{
	if (!customDlls)
		return;

	log_msg("***** Free custom libraries *****\n");

	TCustomDll* dll=customDlls;
	TCustomDll* nextDll;
	while (dll)
	{
		dll->release();
		freeLibrary(dll->offset);
		nextDll = dll->nextDll;
		delete(dll);
		dll = nextDll;
	}
}

void initCustomLibraries()
{
	log_msg("***** Init custom libraries *****\n");

	TCustomDll* dll=customDlls;
	while (dll)
	{
		dll->init();
		dll = dll->nextDll;
	}
}

void loadCustomLibraries()
{
	char* curString = NULL;
	TCustomDll* nextDll;
	DWORD offset_currentDll;

	log_msg("***** Custom libraries *****\n");

	if (dllFilenames)
		curString = strtok(dllFilenames,"|");

	if (!curString)
		log_msg("No custom libraries to load.\n");
	else
	{
		while (curString)
		{
			if (curString[0])
			{
				log_msg("Load custom library : %s\n", curString);
				offset_currentDll = (DWORD)LoadLibrary(curString);
				if (!offset_currentDll)
				{
					log_msg("Load library %s failed !\n", curString);
					exit(0);
				}
				nextDll = customDlls;
				customDlls = new(TCustomDll);
				customDlls->nextDll = nextDll;
				customDlls->initialize(offset_currentDll);
			}
			curString=strtok(NULL,"|");
		}
	}
	if(dllFilenames)
		D2FogMemDeAlloc(dllFilenames,__FILE__,__LINE__,0);

	log_msg("\n\n");
}

/*
void loadLibrary(LPCSTR libName, int* libVersion, DWORD* libOffset, int shift, DWORD v109b, DWORD v109d, DWORD v110, DWORD v111, DWORD v111b, DWORD v112, DWORD v113c)
{
	*libOffset = (DWORD)LoadLibrary(libName);
	if (*libOffset == NULL)
	{
		log_msg("Failed to load library : %s\n", libName);
		exit(-1);
	}
	log_msg("%s loaded at:\t%08X (", libName, *libOffset);

	DWORD addr = *(DWORD*)(*libOffset + shift);
	if (version_Game != UNKNOWN && (version_Game <= V108 || version_Game >= V113d))
		*libVersion = version_Game;
	else if (addr==v109b)
		*libVersion = V109b;
	else if (addr==v109d)
		*libVersion = V109d;
	else if (addr==v110)
		*libVersion = V110;
	else if (addr==v111)
		*libVersion = V111;
	else if (addr==v111b)
		*libVersion = V111b;
	else if (addr==v112)
		*libVersion = V112;
	else if (addr==v113c)
		*libVersion = V113c;
	else {
		*libVersion = version_Game != UNKNOWN ? version_Game : V113d;
		log_msg("unknown, try with ");
	}
	log_msg("%s)\n", GetVersionString(*libVersion));
}

#define GET_VERSION(F,S,A,B,C,D,E,G,H) loadLibrary(S_##F, &version_##F, &offset_##F, 0x##S, 0x##A, 0x##B, 0x##C, 0x##D, 0x##E, 0x##G, 0x##H)
void initD2modules()
{
	log_msg("***** Get D2 Modules address and version *****\n");
	offset_Game = (DWORD)GetModuleHandle(NULL);
	version_Game = GetD2Version((HMODULE)offset_Game);
	log_msg("Game.exe loaded at:\t%08X (%s)\n", offset_Game, GetVersionString(version_Game));

	if (version_Game >= V114a)
	{
//		offset_Bnclient		= offset_Game;	version_Bnclient	= version_Game;
		offset_D2Client		= offset_Game;	version_D2Client	= version_Game;
		offset_D2CMP		= offset_Game;	version_D2CMP		= version_Game;
		offset_D2Common		= offset_Game;	version_D2Common	= version_Game;
//		offset_D2DDraw		= offset_Game;	version_D2DDraw		= version_Game;
//		offset_D2Direct3D	= offset_Game;	version_D2Direct3D	= version_Game;
		offset_D2Game		= offset_Game;	version_D2Game		= version_Game;
//		offset_D2Gdi		= offset_Game;	version_D2Gdi		= version_Game;
		offset_D2gfx		= offset_Game;	version_D2gfx		= version_Game;
//		offset_D2Glide		= offset_Game;	version_D2Glide		= version_Game;
		offset_D2Lang		= offset_Game;	version_D2Lang		= version_Game;
		offset_D2Launch		= offset_Game;	version_D2Launch	= version_Game;
//		offset_D2MCPClient	= offset_Game;	version_D2MCPClient	= version_Game;
//		offset_D2Multi		= offset_Game;	version_D2Multi		= version_Game;
		offset_D2Net		= offset_Game;	version_D2Net		= version_Game;
//		offset_D2sound		= offset_Game;	version_D2sound		= version_Game;
		offset_D2Win		= offset_Game;	version_D2Win		= version_Game;
		offset_Fog			= offset_Game;	version_Fog			= version_Game;
		offset_Storm		= offset_Game;	version_Storm		= version_Game;
	}
	else
	{
//		GET_VERSION(Bnclient																					//0x15000	0x6FF00000 Already Loaded	-
		GET_VERSION(D2Client,	17F,	00000000, 14500000, 12500000, 0D814800, 0D812800, 0DA01000, 0DA03000);	//0xCC000	0x6FAA0000					0xCA000
		GET_VERSION(D2CMP,		1359,	3C686FE0, 38686FE0, 8BF78B56, 4C880424, 07C71824, CCCCCCCC, C7000005);	//0x18000	0x6FDF0000 Already Loaded	0x19000
		GET_VERSION(D2Common,	10CA,	A1E86FDC, B1E86FDC, 72D03B42, F883057E, 16746AC6, 00FE81C3, 74FE85DB);	//0x8D000	0x037A0000					0x7C000
//		GET_VERSION(D2DDraw		000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//
//		GET_VERSION(D2Direct3D	000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//
//		GET_VERSION(D2Game,		1010,	D22A78A1, D22910A1, D43FB0A1, 03E8506F, 53E8506F, 89E8506F, 63E8506F);	//0xF6000	0x6FC30000					0xCF000
		GET_VERSION(D2Game,		1092,	18968BF1, 38968BF1, 28968BF1, F6335608, C690C5B9, 895FD713, 56535700);	//0xF6000	0x6FC30000					0xCF000
//		GET_VERSION(D2Gdi,		105,	B4000000, 0B210E00, E4000000, 48000401, 2F000401, 00000000, B7000401);	//0x7000	0x6F830000 Already Loaded	-
		GET_VERSION(D2gfx,		10D,	EB000000, 006FA700, 00000010, 2A000401, 19000401, 0B210E00, 00000000);	//0xB000	0x6FA70000 Already Loaded	-
//		GET_VERSION(D2Glide		000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//
		GET_VERSION(D2Lang,		126D,	FC45048B, F445048B, 02C18313, C4830000, 00C6E045, 8B48408B, 0C75FF0C);	//0x0A000	0x6FC10000 Already Loaded	-
		GET_VERSION(D2Launch,	109A,	81E8526F, 01E8526F, 85E8526F, 247C8B00, 00FC6583, 15FF0424, E850E045);	//0x20000	0x6FA10000 Already Loaded	0x1E000
//		GET_VERSION(D2MCPClient	000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//0x6000	0x6F9F0000 Already Loaded	-
//		GET_VERSION(D2Multi		000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//0x1000	0x6F9A0000					?
		GET_VERSION(D2Net,		16E1,	78B8A73C, 68B8A73C, 10244C8B, 5349E808, 5EA9E808, 105D8B72, 53B9E808);	//0x6000	0x6FC00000 Already Loaded	-
//		GET_VERSION(D2sound		000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//0xC000	0x6F980000 Already Loaded	0xD000
		GET_VERSION(D2Win,		1699,	88686F8C, 84686F8C, D094686F, F0030000, 001435E8, 8B088F44, 0013F5E8);	//0x19000	0x6F8A0000 Already Loaded	0x1C000
		GET_VERSION(Fog,		102,	D0000006, 10000001, 00000006, 000042E6, 00004302, 0000483C, 00004B95);	//0x20000	0x6FF50000 Already Loaded	0x1F000
		GET_VERSION(Storm,		1190,	19E85082, 59E85082, 13C103F6, 0474F685, 8B000321, 3B1074C9, 0D896404);	//0x30000	0x6FFB0000 Already Loaded	-
		if (version_Game == UNKNOWN)
			version_Game = version_D2gfx;
	}
//	GET_VERSION(binkw32		000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//
//	GET_VERSION(ijl11		000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//0x24000	0x60000000 Already Loaded	-
//	GET_VERSION(SmackW32	000,	00000000, 00000000, 00000000, 00000000, 00000000, 00000000, 00000000);	//0xD000	0x03B90000 Already Loaded	-

	log_msg("\n\n");
}
*/

IMAGE_NT_HEADERS* GetHeader(LPBYTE pBase) {
	if (pBase == NULL)
		return NULL;

	IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)pBase;

	if (IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)))
		return NULL;

	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
		return NULL;

	IMAGE_NT_HEADERS* pHeader = (IMAGE_NT_HEADERS*)(pBase + pDosHeader->e_lfanew);
	if (IsBadReadPtr(pHeader, sizeof(IMAGE_NT_HEADERS)))
		return NULL;

	if (pHeader->Signature != IMAGE_NT_SIGNATURE)
		return NULL;

	return pHeader;
}

void initD2modules()
{
	log_msg("***** Get D2 Modules address and version *****\n\n");

	offset_D2Client		= (DWORD)LoadLibrary("D2Client.dll");
	offset_D2CMP		= (DWORD)LoadLibrary("D2CMP.dll");
	offset_D2Common		= (DWORD)LoadLibrary("D2Common.dll");
	offset_D2Game		= (DWORD)LoadLibrary("D2Game.dll");
	offset_D2gfx		= (DWORD)LoadLibrary("D2gfx.dll");
	offset_D2Lang		= (DWORD)LoadLibrary("D2Lang.dll");
	offset_D2Launch		= (DWORD)LoadLibrary("D2Launch.dll");
	offset_D2Net		= (DWORD)LoadLibrary("D2Net.dll");
	offset_D2Win		= (DWORD)LoadLibrary("D2Win.dll");
	offset_Fog			= (DWORD)LoadLibrary("Fog.dll");
	offset_Storm		= (DWORD)LoadLibrary("Storm.dll");

	int count_109b = 0;
	int count_109d = 0;
	int count_110f = 0;
	int count_111 = 0;
	int count_111b = 0;
	int count_112a = 0;
	int count_113c = 0;
	int count_113d = 0;
	int count_114a = 0;
	int count_114b = 0;
	int count_114c = 0;
	int count_114d = 0;

	IMAGE_NT_HEADERS* pHeader;

	if (offset_D2Client != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2Client);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000C234D) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000C16CD) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000C1C1D) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000045E6) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000045EE) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000045FA) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000045F6) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000045DE) count_113d++;
	}

	if (offset_D2CMP != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2CMP);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00011361) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00011361) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00010E61) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C23) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C23) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C23) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C23) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C23) count_113d++;
	}

	if (offset_D2Common != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2Common);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00074D1D) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00074E2D) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000856DD) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C94) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C8D) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C97) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C8F) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000047C7) count_113d++;
	}

	if (offset_D2Game != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2Game);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000C66AC) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000C6D5C) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000EDC2C) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000036E6) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000373D) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000374B) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000373C) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003747) count_113d++;
	}

	if (offset_D2gfx != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2gfx);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000054EB) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000054EB) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000054A5) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001807) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001807) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001807) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001807) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001807) count_113d++;
	}

	if (offset_D2Lang != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2Lang);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00005148) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00005138) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00005048) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A6A) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A5B) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A75) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A71) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A5A) count_113d++;
	}

	if (offset_D2Launch != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2Launch);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000172C3) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00017243) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00018DC7) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A84) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A85) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A85) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A87) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001A84) count_113d++;
	}

	if (offset_D2Net != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2Net);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002BCE) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002BCE) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00002C6E) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001676) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001676) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000167E) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001676) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000167E) count_113d++;
	}

	if (offset_D2Win != NULL) {
		pHeader = GetHeader((LPBYTE)offset_D2Win);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00014F38) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00014F38) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00012EC0) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000187E) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000187E) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000188E) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000187E) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00001887) count_113d++;
	}

	if (offset_Fog != NULL) {
		pHeader = GetHeader((LPBYTE)offset_Fog);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00013658) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000142E7) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000162B0) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003159) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003142) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000314A) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003162) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003142) count_113d++;
	}

	if (offset_Storm != NULL) {
		pHeader = GetHeader((LPBYTE)offset_Storm);
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00013658) count_109b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000142E7) count_109d++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x000162B0) count_110f++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003159) count_111++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003142) count_111b++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0000314A) count_112a++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00003162) count_113c++;
		if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x0003C3E0) count_113d++;
	}

	int minimum_match_dll = 7;

	if (count_109b >= minimum_match_dll) version_Game = V109b;
	if (count_109d >= minimum_match_dll) version_Game = V109d;
	if (count_110f >= minimum_match_dll) version_Game = V110;
	if (count_111 >= minimum_match_dll) version_Game = V111;
	if (count_111b >= minimum_match_dll) version_Game = V111b;
	if (count_112a >= minimum_match_dll) version_Game = V112;
	if (count_113c >= minimum_match_dll) version_Game = V113c;
	if (count_113d >= minimum_match_dll) version_Game = V113d;

	//version_SmackW32 = version_Game;
	version_D2Common = version_Game;
	//version_ijl11 = version_Game;
	//version_D2Gdi = version_Game;
	version_D2Win = version_Game;
	//version_D2sound = version_Game;
	//version_D2MCPCLI = version_Game;
	version_D2Launch = version_Game;
	version_D2gfx = version_Game;
	version_D2Client = version_Game;
	version_D2Net = version_Game;
	version_D2Lang = version_Game;
	version_D2Game = version_Game;
	version_D2CMP = version_Game;
	//version_Bnclient = version;
	version_Fog = version_Game;
	version_Storm = version_Game;

	log_msg("DLL match for version 1.09b :\t%d\n", count_109b);
	log_msg("DLL match for version 1.09d :\t%d\n", count_109d);
	log_msg("DLL match for version 1.10f :\t%d\n", count_110f);
	log_msg("DLL match for version 1.11  :\t%d\n", count_111);
	log_msg("DLL match for version 1.11b :\t%d\n", count_111b);
	log_msg("DLL match for version 1.12a :\t%d\n", count_112a);
	log_msg("DLL match for version 1.13c :\t%d\n", count_113c);
	log_msg("\n");

	offset_Game = (DWORD)GetModuleHandle("Game.exe");
	if (offset_Game != NULL) {
		version_Game = GetD2Version((HMODULE)offset_Game);
		log_msg("Game.exe loaded at:\t%08X (%s)\n", offset_Game, GetVersionString(version_Game));
		if (version_Game >= V114a)
		{
			//version_SmackW32 = version_Game;
			version_D2Common = version_Game;
			//version_ijl11 = version_Game;
			//version_D2Gdi = version_Game;
			version_D2Win = version_Game;
			//version_D2sound = version_Game;
			//version_D2MCPCLI = version_Game;
			version_D2Launch = version_Game;
			version_D2gfx = version_Game;
			version_D2Client = version_Game;
			version_D2Net = version_Game;
			version_D2Lang = version_Game;
			version_D2Game = version_Game;
			version_D2CMP = version_Game;
			//version_Bnclient = version;
			version_Fog = version_Game;
			version_Storm = version_Game;
		}
	}

	//if (offset_Game != NULL) {
	//	pHeader = GetHeader((LPBYTE)offset_Game);
	//	if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00291342) count_114a++;
	//	if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x002854F2) count_114b++;
	//	if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x002850E2) count_114c++;
	//	if (pHeader->OptionalHeader.AddressOfEntryPoint == 0x00282985) count_114d++;
	//}

	log_msg("Version game is:\t(%s)\n\n", GetVersionString(version_Game));

	if (version_Game == UNKNOWN)
	{
		MessageBoxA(NULL, "This version of Diablo II is not supported by Plugy. Please upgrade or downgrade to a supported version.", "Plugy 14.03", MB_OK);
	}
}

//////////////////////////////////// EXPORTS FUNCTIONS ////////////////////////////////////


extern "C" __declspec(dllexport) bool __stdcall Release()
{
	log_msg("\n***** FREE LIBRARIES *****\n\n" );

	freeCustomLibraries();
	freeD2Libraries();
	log_msg("***** END DIABLO II *****\n" );
	log_close();
	return true;
}

extern "C" __declspec(dllexport) void* __stdcall Init(LPSTR IniName)
{
	if (IniName) log_msg("* PlugY is called from D2mod.dll\n\n");

	static int isInstalled = false;
	if (isInstalled) return NULL;
	isInstalled=true;

	initD2modules();

	if (version_Game < V109 || version_Game > V113d && version_Game != V114d)
	{
		log_box("PlugY isn't compatible with this version : %s", GetVersionString(version_Game));
		Release();
		exit(0);
	}

	initD2functions();

	loadParameters();

	if (!active_plugin)	return NULL;

	loadCustomLibraries();

	hookLibraries();

	log_msg("***** INSTALL FUNCTIONS *****\n");

	Install_PlugYFiles();
	Install_VariableOnRealm();

	if (active_Commands)
		Install_Commands();

	if (active_ChangeLanguage || active_LanguageManagement)
		Install_LanguageManagement();

	if (active_VersionTextChange)
		Install_VersionChange();

	if (active_PrintPlugYVersion || active_Windowed)
		Install_PrintPlugYVersion();

	if (active_StatsPoints)
		Install_StatsPoints();
	else if (active_DisplayBaseStatsValue)
		Install_DisplayBaseStatsValue();

	if (active_SkillsPoints)
		Install_SkillsPoints();

	if (active_changingSavePath)
		Install_ChangingSavePath();

	if (active_AutoBackup)
		Install_SavePlayerData();

	if (active_StatsShiftClickLimit)
		Install_StatsLimitShiftClick();

	if (active_RunLODs)
		Install_RunLODs();

	if (active_bigStash)
		Install_BigStash();

	if (active_SkillPerLevelUpChange)
		Install_SkillPerLevelUp();

	if (active_StatPerLevelUpChange)
		Install_StatPerLevelUp();

	if (active_multiPageStash)
		Install_MultiPageStash();

	if (active_othersFeatures)
		Install_OthersFeatures();

	if (active_newInterfaces)
		Install_NewInterfaces();

	if (active_WorldEvent)
		Install_WorldEvent();

	if (active_UberQuest)
		Install_UberQuest();

	if (active_alwaysRegenMapInSP)
		Install_AlwaysRegenMapInSP();

	if (nbPlayersCommandByDefault)
		Install_SendPlayersCommand();

	if (active_DisplayItemLevel)
		Install_DisplayItemLevel();

	if (active_AlwaysDisplayLifeMana)
		Install_AlwaysDisplayLifeMana();

	if (active_EnabledTXTFilesWithMSExcel)
		Install_EnabledTXTFilesWithMSExcel();

	if (active_LadderRunewords)
		Install_LadderRunewords();

	if (active_EnabledCowPortalWhenCowKingWasKill)
		Install_EnabledCowPortalWhenCowKingWasKill();

	if (active_DoNotCloseNihlathakPortal)
		Install_DoNotCloseNihlathakPortal();

	if (active_MoveCainNearHarrogathWaypoint)
		Install_MoveCainNearHarrogathWaypoint();

	if (active_RemoveExperienceDiminushingReturn)
		Install_RemoveExperienceDiminushingReturn();

	log_msg("\nDLL patched sucessfully.\n\n\n");

	unhookLibraries();

	initCustomLibraries();

	//loadLocalizedStrings(D2GetLang());

	log_msg("***** ENTERING DIABLO II *****\n\n" );

	active_logFile--;
	if (active_logFile < 1)
		log_close();

	return NULL;
}

/*================================= END OF FILE =================================*/