devilutionX/Source/init.cpp
Anders Jenbo 20621a0642
add all.h and use in place of diablo.h (#2005)
Now diablo.h is treated in the same way as all other header files of
Source, as it only contains the declarations of global variables and
functions of diablo.cpp.

Besides consistency, this also enables mods to include diablo.h just
like any other header file without having to include every header file
(and without having to include C++ specific aspects of the now all.h).
2020-02-14 13:12:54 +01:00

472 lines
11 KiB
C++

#include "all.h"
#include "../3rdParty/Storm/Source/storm.h"
#include "../DiabloUI/diabloui.h"
_SNETVERSIONDATA fileinfo;
int gbActive;
char diablo_exe_path[MAX_PATH];
HANDLE hellfire_mpq;
char patch_rt_mpq_path[MAX_PATH];
WNDPROC CurrentProc;
HANDLE diabdat_mpq;
char diabdat_mpq_path[MAX_PATH];
HANDLE patch_rt_mpq;
BOOL killed_mom_parent;
BOOLEAN screensaver_enabled_prev;
/* data */
char gszVersionNumber[MAX_PATH] = "internal version unknown";
char gszProductName[MAX_PATH] = "Diablo v1.09";
void init_cleanup(BOOL show_cursor)
{
pfile_flush_W();
init_disable_screensaver(0);
init_run_office_from_start_menu();
if (diabdat_mpq) {
SFileCloseArchive(diabdat_mpq);
diabdat_mpq = NULL;
}
if (patch_rt_mpq) {
SFileCloseArchive(patch_rt_mpq);
patch_rt_mpq = NULL;
}
if (hellfire_mpq) {
SFileCloseArchive(hellfire_mpq);
hellfire_mpq = NULL;
}
UiDestroy();
effects_cleanup_sfx();
sound_cleanup();
NetClose();
dx_cleanup();
engine_debug_trap(show_cursor);
StormDestroy();
if (show_cursor)
ShowCursor(TRUE);
}
void init_run_office_from_start_menu()
{
LPITEMIDLIST idl;
if (!killed_mom_parent) {
return;
}
killed_mom_parent = FALSE;
char szPath[256] = ""; /// BUGFIX: size should be at least 'MAX_PATH'
idl = NULL;
if (SHGetSpecialFolderLocation(GetDesktopWindow(), CSIDL_STARTMENU, &idl) == NOERROR) {
SHGetPathFromIDList(idl, szPath);
init_run_office(szPath);
}
}
void init_run_office(char *dir)
{
HANDLE hSearch;
WIN32_FIND_DATA find;
char szFirst[MAX_PATH];
strcpy(szFirst, dir);
if (szFirst[0] != '\0' && szFirst[strlen(szFirst) - 1] == '\\') {
strcat(szFirst, "*");
} else {
strcat(szFirst, "\\*");
}
hSearch = FindFirstFile(szFirst, &find);
if (hSearch == INVALID_HANDLE_VALUE) {
return;
}
while (1) {
if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (strcmp(find.cFileName, ".") != 0 && strcmp(find.cFileName, "..") != 0) {
char szNext[MAX_PATH] = "";
if (dir[0] != '\0' && dir[strlen(dir) - 1] == '\\') {
sprintf(szNext, "%s%s\\", dir, find.cFileName);
} else {
sprintf(szNext, "%s\\%s\\", dir, find.cFileName);
}
init_run_office(szNext);
}
} else if (_strcmpi(find.cFileName, "Microsoft Office Shortcut Bar.lnk") == 0) {
ShellExecute(GetDesktopWindow(), "open", find.cFileName, "", dir, SW_SHOWNORMAL);
}
if (!FindNextFile(hSearch, &find)) {
break;
}
}
FindClose(hSearch);
}
void init_disable_screensaver(BOOLEAN disable)
{
BOOLEAN enabled;
char Data[16];
DWORD Type, cbData;
HKEY phkResult;
LRESULT success;
// BUGFIX: this is probably the worst possible way to do this. Alternatives: ExtEscape() with SETPOWERMANAGEMENT,
// SystemParametersInfo() with SPI_SETSCREENSAVEACTIVE/SPI_SETPOWEROFFACTIVE/SPI_SETLOWPOWERACTIVE
success = RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, KEY_READ | KEY_WRITE, (PHKEY)&phkResult);
if (success != ERROR_SUCCESS) {
return;
}
if (disable) {
cbData = 16;
success = RegQueryValueEx(phkResult, "ScreenSaveActive", 0, &Type, (LPBYTE)Data, &cbData);
if (success == ERROR_SUCCESS)
screensaver_enabled_prev = Data[0] != '0';
enabled = FALSE;
} else {
enabled = screensaver_enabled_prev;
}
Data[1] = 0;
Data[0] = enabled ? '1' : '0';
RegSetValueEx(phkResult, "ScreenSaveActive", 0, REG_SZ, (const BYTE *)Data, 2);
RegCloseKey(phkResult);
}
void init_create_window(int nCmdShow)
{
int nWidth, nHeight;
HWND hWnd;
WNDCLASSEXA wcex;
init_kill_mom_parent();
pfile_init_save_directory();
memset(&wcex, 0, sizeof(wcex));
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = ghInst;
wcex.hIcon = LoadIcon(ghInst, MAKEINTRESOURCE(IDI_ICON1));
wcex.hCursor = LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = GAME_NAME;
wcex.lpszClassName = "DIABLO";
wcex.hIconSm = (HICON)LoadImage(ghInst, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
if (!RegisterClassEx(&wcex))
app_fatal("Unable to register window class");
if (GetSystemMetrics(SM_CXSCREEN) < SCREEN_WIDTH)
nWidth = SCREEN_WIDTH;
else
nWidth = GetSystemMetrics(SM_CXSCREEN);
if (GetSystemMetrics(SM_CYSCREEN) < SCREEN_HEIGHT)
nHeight = SCREEN_HEIGHT;
else
nHeight = GetSystemMetrics(SM_CYSCREEN);
hWnd = CreateWindowEx(0, "DIABLO", GAME_NAME, WS_POPUP, 0, 0, nWidth, nHeight, NULL, NULL, ghInst, NULL);
if (!hWnd)
app_fatal("Unable to create main window");
ShowWindow(hWnd, SW_SHOWNORMAL); // nCmdShow used only in beta: ShowWindow(hWnd, nCmdShow)
UpdateWindow(hWnd);
init_await_mom_parent_exit();
dx_init(hWnd);
BlackPalette();
snd_init(hWnd);
init_archives();
init_disable_screensaver(1);
}
void init_kill_mom_parent()
{
HWND handle;
handle = init_find_mom_parent();
if (handle) {
PostMessage(handle, WM_CLOSE, 0, 0);
killed_mom_parent = TRUE;
}
}
HWND init_find_mom_parent()
{
HWND i, handle;
char ClassName[256];
for (i = GetForegroundWindow();; i = GetWindow(handle, GW_HWNDNEXT)) {
handle = i;
if (!i)
break;
GetClassName(i, ClassName, 255);
if (!_strcmpi(ClassName, "MOM Parent"))
break;
}
return handle;
}
void init_await_mom_parent_exit()
{
DWORD tick;
tick = GetTickCount();
if (!init_find_mom_parent()) {
return;
}
do {
Sleep(250);
} while (GetTickCount() - tick <= 4000 && init_find_mom_parent());
}
void init_archives()
{
HANDLE fh;
#ifdef COPYPROT
int result;
#endif
memset(&fileinfo, 0, sizeof(fileinfo));
fileinfo.size = sizeof(fileinfo);
fileinfo.versionstring = gszVersionNumber;
fileinfo.executablefile = diablo_exe_path;
fileinfo.originalarchivefile = diabdat_mpq_path;
fileinfo.patcharchivefile = patch_rt_mpq_path;
init_get_file_info();
#ifdef COPYPROT
while (1) {
#endif
#ifdef SPAWN
diabdat_mpq = init_test_access(diabdat_mpq_path, "\\spawn.mpq", "DiabloSpawn", 1000, FS_PC);
#else
#ifdef COPYPROT
diabdat_mpq = init_test_access(diabdat_mpq_path, "\\diabdat.mpq", "DiabloCD", 1000, FS_CD);
#else
diabdat_mpq = init_test_access(diabdat_mpq_path, "\\diabdat.mpq", "DiabloCD", 1000, FS_PC);
#endif
#endif
#ifdef COPYPROT
if (diabdat_mpq != NULL)
break;
UiCopyProtError(&result);
if (result == COPYPROT_CANCEL)
FileErrDlg("diabdat.mpq");
}
#endif
if (!WOpenFile("ui_art\\title.pcx", &fh, TRUE))
#ifdef SPAWN
FileErrDlg("Main program archive: spawn.mpq");
#else
FileErrDlg("Main program archive: diabdat.mpq");
#endif
WCloseFile(fh);
#ifdef SPAWN
patch_rt_mpq = init_test_access(patch_rt_mpq_path, "\\patch_sh.mpq", "DiabloSpawn", 2000, FS_PC);
#else
patch_rt_mpq = init_test_access(patch_rt_mpq_path, "\\patch_rt.mpq", "DiabloInstall", 2000, FS_PC);
#endif
}
HANDLE init_test_access(char *mpq_path, char *mpq_name, char *reg_loc, int dwPriority, int fs)
{
char *last_slash_pos;
char Filename[MAX_PATH];
char Buffer[MAX_PATH];
char archive_path[MAX_PATH];
HANDLE archive;
if (!GetCurrentDirectory(sizeof(Buffer), Buffer))
app_fatal("Can't get program path");
init_strip_trailing_slash(Buffer);
if (!SFileSetBasePath(Buffer))
app_fatal("SFileSetBasePath");
if (!GetModuleFileName(ghInst, Filename, sizeof(Filename)))
app_fatal("Can't get program name");
last_slash_pos = strrchr(Filename, '\\');
if (last_slash_pos)
*last_slash_pos = '\0';
init_strip_trailing_slash(Filename);
strcpy(mpq_path, Buffer);
strcat(mpq_path, mpq_name);
if (SFileOpenArchive(mpq_path, dwPriority, fs, &archive))
return archive;
if (strcmp(Filename, Buffer)) {
strcpy(mpq_path, Filename);
strcat(mpq_path, mpq_name);
if (SFileOpenArchive(mpq_path, dwPriority, fs, &archive))
return archive;
}
archive_path[0] = '\0';
if (reg_loc) {
if (SRegLoadString("Archives", reg_loc, 0, archive_path, sizeof(archive_path))) {
init_strip_trailing_slash(archive_path);
strcpy(mpq_path, archive_path);
strcat(mpq_path, mpq_name);
if (SFileOpenArchive(mpq_path, dwPriority, fs, &archive))
return archive;
}
}
if (fs != FS_PC && init_read_test_file(archive_path, mpq_name, dwPriority, &archive)) {
strcpy(mpq_path, archive_path);
return archive;
}
return NULL;
}
char *init_strip_trailing_slash(char *path)
{
char *result;
result = strrchr(path, '\\');
if (result) {
if (!result[1])
*result = 0;
}
return result;
}
BOOL init_read_test_file(char *pszPath, char *pszArchive, int dwPriority, HANDLE *phArchive)
{
DWORD dwSize;
char *pszDrive, *pszRoot;
char szDrive[MAX_PATH];
dwSize = GetLogicalDriveStrings(sizeof(szDrive), szDrive);
if (dwSize == 0 || dwSize > sizeof(szDrive)) {
return FALSE;
}
while (*pszArchive == '\\') {
pszArchive++;
}
pszDrive = szDrive;
if (*pszDrive == '\0') {
return FALSE;
}
while (1) {
pszRoot = pszDrive;
while (*pszDrive++ != '\0')
;
if (GetDriveType(pszRoot) == DRIVE_CDROM) {
strcpy(pszPath, pszRoot);
strcat(pszPath, pszArchive);
if (SFileOpenArchive(pszPath, dwPriority, FS_CD, phArchive)) {
break;
}
}
if (*pszDrive == '\0') {
return FALSE;
}
}
return TRUE;
}
void init_get_file_info()
{
DWORD dwLen;
void *pBlock;
unsigned int uBytes;
DWORD dwHandle;
VS_FIXEDFILEINFO *lpBuffer;
if (GetModuleFileName(ghInst, diablo_exe_path, sizeof(diablo_exe_path))) {
dwLen = GetFileVersionInfoSize(diablo_exe_path, &dwHandle);
if (dwLen) {
pBlock = DiabloAllocPtr(dwLen);
if (GetFileVersionInfo(diablo_exe_path, 0, dwLen, pBlock)) {
if (VerQueryValue(pBlock, "\\", (LPVOID *)&lpBuffer, &uBytes))
sprintf(
gszVersionNumber,
"version %d.%d.%d.%d",
lpBuffer->dwProductVersionMS >> 16,
lpBuffer->dwProductVersionMS & 0xFFFF,
lpBuffer->dwProductVersionLS >> 16,
lpBuffer->dwProductVersionLS & 0xFFFF);
}
mem_free_dbg(pBlock);
}
}
}
LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg) {
case WM_ERASEBKGND:
return 0;
case WM_CREATE:
ghMainWnd = hWnd;
break;
case WM_DESTROY:
init_cleanup(TRUE);
ghMainWnd = 0;
PostQuitMessage(0);
break;
case WM_PAINT:
force_redraw = 255;
break;
case WM_CLOSE:
return 0;
case WM_ACTIVATEAPP:
init_activate_window(hWnd, wParam);
break;
#ifdef _DEBUG
case WM_SYSKEYUP:
if (wParam == VK_RETURN) {
fullscreen = !fullscreen;
dx_reinit();
return 0;
}
break;
#endif
case WM_QUERYNEWPALETTE:
SDrawRealizePalette();
return 1;
case WM_PALETTECHANGED:
if ((HWND)wParam != hWnd)
SDrawRealizePalette();
break;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
void init_activate_window(HWND hWnd, BOOL bActive)
{
LONG dwNewLong;
gbActive = bActive;
UiAppActivate(bActive);
dwNewLong = GetWindowLong(hWnd, GWL_STYLE);
if (gbActive && fullscreen)
dwNewLong &= ~WS_SYSMENU;
else
dwNewLong |= WS_SYSMENU;
SetWindowLong(hWnd, GWL_STYLE, dwNewLong);
if (gbActive) {
force_redraw = 255;
ResetPal();
}
}
LRESULT __stdcall WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
if (CurrentProc)
return CurrentProc(hWnd, Msg, wParam, lParam);
return MainWndProc(hWnd, Msg, wParam, lParam);
}
WNDPROC SetWindowProc(WNDPROC NewProc)
{
WNDPROC OldProc;
OldProc = CurrentProc;
CurrentProc = NewProc;
return OldProc;
}