#include "diablo.h" #include "../3rdParty/Storm/Source/storm.h" #include "../DiabloUI/diabloui.h" HWND ghMainWnd; int glMid1Seed[NUMLEVELS]; int glMid2Seed[NUMLEVELS]; int gnLevelTypeTbl[NUMLEVELS]; int MouseY; // idb int MouseX; // idb BOOL gbGameLoopStartup; // idb int glSeedTbl[NUMLEVELS]; int gbRunGame; // weak int glMid3Seed[NUMLEVELS]; int gbRunGameResult; // weak int zoomflag; // weak int gbProcessPlayers; // weak int glEndSeed[NUMLEVELS]; int gbLoadGame; // weak HINSTANCE ghInst; // idb int DebugMonsters[10]; char cineflag; // weak int force_redraw; // weak int visiondebug; // weak int scrollflag; /* unused */ int light4flag; // weak int leveldebug; // weak int monstdebug; // weak int trigdebug; /* unused */ int setseed; // weak int debugmonsttypes; // weak int PauseMode; // weak int sgnTimeoutCurs; char sgbMouseDown; // weak int color_cycle_timer; // weak /* rdata */ int fullscreen = 1; // weak #ifdef _DEBUG int showintrodebug = 1; int questdebug = -1; int debug_mode_key_s; int debug_mode_key_w; int debug_mode_key_inverted_v; int debug_mode_dollar_sign; int debug_mode_key_d; int debug_mode_key_i; int dbgplr; int dbgqst; int dbgmon; int arrowdebug; int frameflag; int frameend; int framerate; int framestart; #endif int FriendlyMode = 1; // weak char *spszMsgTbl[4] = { "I need help! Come Here!", "Follow me.", "Here's something for you.", "Now you DIE!" }; // weak char *spszMsgKeyTbl[4] = { "F9", "F10", "F11", "F12" }; // weak void FreeGameMem() { music_stop(); MemFreeDbg(pDungeonCels); MemFreeDbg(pMegaTiles); MemFreeDbg(pLevelPieces); MemFreeDbg(pSpecialCels); MemFreeDbg(pSpeedCels); FreeMissiles(); FreeMonsters(); FreeObjectGFX(); FreeMonsterSnd(); FreeTownerGFX(); } BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer) { BOOL fExitProgram; unsigned int uMsg; gbSelectProvider = 1; do { fExitProgram = FALSE; gbLoadGame = 0; if(!NetInit(bSinglePlayer, &fExitProgram)) { gbRunGameResult = fExitProgram == FALSE; break; } gbSelectProvider = 0; if(bNewGame || !gbValidSaveFile) { InitLevels(); InitQuests(); InitPortals(); InitDungMsgs(myplr); } if(!gbValidSaveFile || !gbLoadGame) uMsg = WM_DIABNEWGAME; else uMsg = WM_DIABLOADGAME; run_game_loop(uMsg); NetClose(); pfile_create_player_description(0, 0); } while(gbRunGameResult); SNetDestroy(); return gbRunGameResult; } void run_game_loop(unsigned int uMsg) { BOOL bLoop; WNDPROC saveProc; MSG msg; nthread_ignore_mutex(TRUE); start_game(uMsg); /// ASSERT: assert(ghMainWnd); saveProc = SetWindowProc(GM_Game); control_update_life_mana(); run_delta_info(); gbRunGame = TRUE; gbProcessPlayers = TRUE; gbRunGameResult = TRUE; force_redraw = 255; DrawAndBlit(); PaletteFadeIn(8); force_redraw = 255; gbGameLoopStartup = TRUE; nthread_ignore_mutex(FALSE); while(gbRunGame) { diablo_color_cyc_logic(); if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(msg.message == WM_QUIT) { gbRunGameResult = FALSE; gbRunGame = FALSE; break; } TranslateMessage(&msg); DispatchMessage(&msg); } bLoop = gbRunGame && nthread_has_500ms_passed(FALSE); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); if(!bLoop) { continue; } } else if(!nthread_has_500ms_passed(FALSE)) { #ifdef SLEEPFIX Sleep(1); #endif continue; } multi_process_network_packets(); game_loop(gbGameLoopStartup); msgcmd_send_chat(); gbGameLoopStartup = FALSE; DrawAndBlit(); } if(gbMaxPlayers > 1) { pfile_write_hero(); } pfile_flush_W(); PaletteFadeOut(8); SetCursor_(0); ClearScreenBuffer(); force_redraw = 255; scrollrt_draw_game_screen(TRUE); saveProc = SetWindowProc(saveProc); /// ASSERT: assert(saveProc == GM_Game); free_game(); if(cineflag) { cineflag = FALSE; DoEnding(); } } void start_game(unsigned int uMsg) { zoomflag = 1; cineflag = 0; InitCursor(); InitLightTable(); LoadDebugGFX(); /// ASSERT: assert(ghMainWnd); music_stop(); ShowProgress(uMsg); gmenu_init_menu(); InitLevelCursor(); sgnTimeoutCurs = 0; sgbMouseDown = 0; track_repeat_walk(0); } void free_game() { int i; FreeControlPan(); FreeInvGFX(); FreeGMenu(); FreeQuestText(); FreeStoreMem(); for(i = 0; i < MAX_PLRS; i++) { FreePlayerGFX(i); } FreeItemGFX(); FreeCursor(); FreeLightTable(); FreeDebugGFX(); FreeGameMem(); } BOOL diablo_get_not_running() { SetLastError(0); CreateEvent(NULL, FALSE, FALSE, "DiabloEvent"); return GetLastError() != ERROR_ALREADY_EXISTS; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HINSTANCE hInst; DWORD dwData; char szFileName[MAX_PATH]; hInst = hInstance; #ifndef DEBUGGER diablo_reload_process(hInstance); #endif ghInst = hInst; if(RestrictedTest()) ErrOkDlg(IDD_DIALOG10, 0, "C:\\Src\\Diablo\\Source\\DIABLO.CPP", 877); if(ReadOnlyTest()) { if(!GetModuleFileName(ghInst, szFileName, sizeof(szFileName))) szFileName[0] = '\0'; DirErrorDlg(szFileName); } ShowCursor(FALSE); srand(GetTickCount()); InitHash(); exception_get_filter(); BOOL bNoEvent = diablo_get_not_running(); if(!diablo_find_window("DIABLO") && bNoEvent) { #ifdef _DEBUG SFileEnableDirectAccess(TRUE); #endif diablo_init_screen(); diablo_parse_flags(lpCmdLine); init_create_window(nCmdShow); ui_sound_init(); UiInitialize(); #ifdef _DEBUG if(showintrodebug) #endif play_movie("gendata\\logo.smk", TRUE); char szValueName[] = "Intro"; if(!SRegLoadValue("Diablo", szValueName, 0, &dwData)) dwData = 1; if(dwData) play_movie("gendata\\diablo1.smk", TRUE); SRegSaveValue("Diablo", szValueName, 0, 0); #ifdef _DEBUG if(showintrodebug) { #endif UiTitleDialog(7); BlackPalette(); #ifdef _DEBUG } #endif mainmenu_loop(); UiDestroy(); SaveGamma(); if(ghMainWnd) { Sleep(300); DestroyWindow(ghMainWnd); } } return FALSE; } void diablo_parse_flags(char *args) { char c; #ifdef _DEBUG int i; #endif while(*args != '\0') { while(isspace(*args)) { args++; } if(_strnicmp("dd_emulate", args, strlen("dd_emulate")) == 0) { gbEmulate = 1; args += strlen("dd_emulate"); } else if(_strnicmp("dd_backbuf", args, strlen("dd_backbuf")) == 0) { gbBackBuf = 1; args += strlen("dd_backbuf"); } else if(_strnicmp("ds_noduplicates", args, strlen("ds_noduplicates")) == 0) { gbDupSounds = 0; args += strlen("ds_noduplicates"); } else { c = tolower(*args); args++; #ifdef _DEBUG switch(c) { case '^': debug_mode_key_inverted_v = 1; break; case '$': debug_mode_dollar_sign = 1; break; case 'b': /* debug_mode_key_b = 1; */ break; case 'd': showintrodebug = 0; debug_mode_key_d = 1; break; case 'f': EnableFrameCount(); break; case 'i': debug_mode_key_i = 1; break; case 'j': /* while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } debug_mode_key_J_trigger = i; */ break; case 'l': setlevel = 0; leveldebug = 1; while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } leveltype = i; while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } currlevel = i; plr[0].plrlevel = i; break; case 'm': monstdebug = 1; while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } DebugMonsters[debugmonsttypes++] = i; break; case 'n': showintrodebug = 0; break; case 'q': while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } questdebug = i; break; case 'r': while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } setseed = i; break; case 's': debug_mode_key_s = 1; break; case 't': leveldebug = 1; setlevel = 1; while(isspace(*args)) { args++; } i = 0; while(isdigit(*args)) { i = *args + 10 * i - '0'; args++; } setlvlnum = i; break; case 'v': visiondebug = 1; break; case 'w': debug_mode_key_w = 1; break; case 'x': fullscreen = 0; break; } #endif } } } void diablo_init_screen() { int i; MouseX = SCREEN_WIDTH / 2; MouseY = SCREEN_HEIGHT / 2; ScrollInfo._sdx = 0; ScrollInfo._sdy = 0; ScrollInfo._sxoff = 0; ScrollInfo._syoff = 0; ScrollInfo._sdir = 0; for(i = 0; i < 1024; i++) { PitchTbl[i] = i * BUFFER_WIDTH; } ClrDiabloMsg(); } BOOL diablo_find_window(LPCSTR lpClassName) { HWND result; // eax HWND v2; // esi HWND v3; // eax HWND v4; // edi result = FindWindow(lpClassName, 0); v2 = result; if ( !result ) return 0; v3 = GetLastActivePopup(result); if ( v3 ) v2 = v3; v4 = GetTopWindow(v2); if ( !v4 ) v4 = v2; SetForegroundWindow(v2); SetFocus(v4); return 1; } void diablo_reload_process(HINSTANCE hInstance) { DWORD dwSize, dwProcessId; BOOL bNoExist; char *s; long *plMap; HWND hWnd, hPrev; HANDLE hMap; STARTUPINFO si; SYSTEM_INFO sinf; PROCESS_INFORMATION pi; char szReload[MAX_PATH + 16]; char szFileName[MAX_PATH] = ""; GetModuleFileName(hInstance, szFileName, sizeof(szFileName)); wsprintf(szReload, "Reload-%s", szFileName); for(s = szReload; *s != '\0'; s++) { if(*s == '\\') { *s = '/'; } } GetSystemInfo(&sinf); dwSize = sinf.dwPageSize; if(dwSize < 4096) { dwSize = 4096; } hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE, 0, dwSize, szReload); bNoExist = GetLastError() != ERROR_ALREADY_EXISTS; if(hMap == NULL) { return; } plMap = (long *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, dwSize); if(plMap == NULL) { return; } if(bNoExist) { plMap[0] = -1; plMap[1] = 0; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); CreateProcess(szFileName, NULL, NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi); WaitForInputIdle(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); while(plMap[0] < 0) { Sleep(1000); } UnmapViewOfFile(plMap); CloseHandle(hMap); ExitProcess(0); } if(InterlockedIncrement(plMap) == 0) { plMap[1] = GetCurrentProcessId(); } else { hPrev = GetForegroundWindow(); hWnd = hPrev; while(1) { hPrev = GetWindow(hPrev, GW_HWNDPREV); if(hPrev == NULL) { break; } hWnd = hPrev; } while(1) { GetWindowThreadProcessId(hWnd, &dwProcessId); if(dwProcessId == plMap[1]) { SetForegroundWindow(hWnd); break; } hWnd = GetWindow(hWnd, GW_HWNDNEXT); if(hWnd == NULL) { break; } } UnmapViewOfFile(plMap); CloseHandle(hMap); ExitProcess(0); } } BOOL PressEscKey() { BOOL rv = FALSE; if(doomflag) { doom_close(); rv = TRUE; } if(helpflag) { helpflag = 0; rv = TRUE; } if(qtextflag) { qtextflag = 0; stream_stop(); rv = TRUE; } else if(stextflag) { STextESC(); rv = TRUE; } if(msgflag) { msgdelay = 0; rv = TRUE; } if(talkflag) { control_reset_talk(); rv = TRUE; } if(dropGoldFlag) { control_drop_gold(VK_ESCAPE); rv = TRUE; } if(spselflag) { spselflag = 0; rv = TRUE; } return rv; } LRESULT CALLBACK DisableInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_KEYDOWN: case WM_KEYUP: case WM_CHAR: case WM_SYSKEYDOWN: case WM_SYSCOMMAND: case WM_MOUSEMOVE: return 0; case WM_LBUTTONDOWN: if(sgbMouseDown == 0) { sgbMouseDown = 1; SetCapture(hWnd); } return 0; case WM_LBUTTONUP: if(sgbMouseDown == 1) { sgbMouseDown = 0; ReleaseCapture(); } return 0; case WM_RBUTTONDOWN: if(sgbMouseDown == 0) { sgbMouseDown = 2; SetCapture(hWnd); } return 0; case WM_RBUTTONUP: if(sgbMouseDown == 2) { sgbMouseDown = 0; ReleaseCapture(); } return 0; case WM_CAPTURECHANGED: if(hWnd != (HWND)lParam) sgbMouseDown = 0; return 0; } return MainWndProc(hWnd, uMsg, wParam, lParam); } LRESULT CALLBACK GM_Game(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_KEYDOWN: PressKey(wParam); return 0; case WM_KEYUP: ReleaseKey(wParam); return 0; case WM_CHAR: PressChar(wParam); return 0; case WM_SYSKEYDOWN: if(PressSysKey(wParam)) return 0; break; case WM_SYSCOMMAND: if(wParam == SC_CLOSE) { gbRunGame = FALSE; gbRunGameResult = FALSE; return 0; } break; case WM_MOUSEMOVE: MouseX = LOWORD(lParam); MouseY = HIWORD(lParam); gmenu_on_mouse_move(); return 0; case WM_LBUTTONDOWN: MouseX = LOWORD(lParam); MouseY = HIWORD(lParam); if(sgbMouseDown == 0) { sgbMouseDown = 1; SetCapture(hWnd); track_repeat_walk(LeftMouseDown(wParam)); } return 0; case WM_LBUTTONUP: MouseX = LOWORD(lParam); MouseY = HIWORD(lParam); if(sgbMouseDown == 1) { sgbMouseDown = 0; LeftMouseUp(); track_repeat_walk(FALSE); ReleaseCapture(); } return 0; case WM_RBUTTONDOWN: MouseX = LOWORD(lParam); MouseY = HIWORD(lParam); if(sgbMouseDown == 0) { sgbMouseDown = 2; SetCapture(hWnd); RightMouseDown(); } return 0; case WM_RBUTTONUP: MouseX = LOWORD(lParam); MouseY = HIWORD(lParam); if(sgbMouseDown == 2) { sgbMouseDown = 0; ReleaseCapture(); } return 0; case WM_CAPTURECHANGED: if(hWnd != (HWND)lParam) { sgbMouseDown = 0; track_repeat_walk(FALSE); } break; case WM_DIABNEXTLVL: case WM_DIABPREVLVL: case WM_DIABRTNLVL: case WM_DIABSETLVL: case WM_DIABWARPLVL: case WM_DIABTOWNWARP: case WM_DIABTWARPUP: case WM_DIABRETOWN: if(gbMaxPlayers > 1) pfile_write_hero(); nthread_ignore_mutex(TRUE); PaletteFadeOut(8); sound_stop(); music_stop(); track_repeat_walk(FALSE); sgbMouseDown = 0; ReleaseCapture(); ShowProgress(uMsg); force_redraw = 255; DrawAndBlit(); if(gbRunGame) PaletteFadeIn(8); nthread_ignore_mutex(FALSE); gbGameLoopStartup = TRUE; return 0; } return MainWndProc(hWnd, uMsg, wParam, lParam); } BOOL LeftMouseDown(int wParam) { if ( gmenu_left_mouse(1) || control_check_talk_btn() || sgnTimeoutCurs ) return 0; if ( deathflag ) { control_check_btn_press(); return 0; } if ( PauseMode == 2 ) return 0; if ( doomflag ) { doom_close(); return 0; } if ( spselflag ) { SetSpell(); return 0; } if ( stextflag ) { CheckStoreBtn(); return 0; } if ( MouseY >= 352 ) { if ( !talkflag && !dropGoldFlag ) { if ( !gmenu_is_active() ) CheckInvScrn(); } DoPanBtn(); if ( pcurs <= 1 || pcurs >= 12 ) return 0; goto LABEL_48; } if ( gmenu_is_active() || TryIconCurs() ) return 0; if ( questlog && MouseX > 32 && MouseX < 288 && MouseY > 32 && MouseY < 308 ) { QuestlogESC(); return 0; } if ( qtextflag ) { qtextflag = 0; stream_stop(); return 0; } if ( chrflag && MouseX < 320 ) { CheckChrBtns(); return 0; } if ( invflag && MouseX > 320 ) { if ( !dropGoldFlag ) CheckInvItem(); return 0; } if ( sbookflag && MouseX > 320 ) { CheckSBook(); return 0; } if ( pcurs >= CURSOR_FIRSTITEM ) { if ( !TryInvPut() ) return 0; NetSendCmdPItem(1u, CMD_PUTITEM, cursmx, cursmy); LABEL_48: SetCursor_(CURSOR_HAND); return 0; } if ( plr[myplr]._pStatPts && !spselflag ) CheckLvlBtn(); if ( !lvlbtndown ) return LeftMouseCmd(wParam == MK_SHIFT+MK_LBUTTON); return 0; } BOOL LeftMouseCmd(BOOL bShift) { BOOL bNear; /// ASSERT: assert(MouseY < 352); if(leveltype == DTYPE_TOWN) { if(pcursitem != -1 && pcurs == CURSOR_HAND) { NetSendCmdLocParam1(1, invflag ? CMD_GOTOGETITEM : CMD_GOTOAGETITEM, cursmx, cursmy, pcursitem); } if(pcursmonst != -1) { NetSendCmdLocParam1(1, CMD_TALKXY, cursmx, cursmy, pcursmonst); } if(pcursitem == -1 && pcursmonst == -1 && pcursplr == -1) { return TRUE; } } else { bNear = abs(plr[myplr].WorldX - cursmx) < 2 && abs(plr[myplr].WorldY - cursmy) < 2; if(pcursitem != -1 && pcurs == CURSOR_HAND && !bShift) { NetSendCmdLocParam1(1, invflag ? CMD_GOTOGETITEM : CMD_GOTOAGETITEM, cursmx, cursmy, pcursitem); } else if(pcursobj != -1 && (!bShift || bNear && object[pcursobj]._oBreak == 1)) { NetSendCmdLocParam1(1, pcurs == CURSOR_DISARM ? CMD_DISARMXY : CMD_OPOBJXY, cursmx, cursmy, pcursobj); } else if(plr[myplr]._pwtype == 1) { if(bShift) { NetSendCmdLoc(1, CMD_RATTACKXY, cursmx, cursmy); } else if(pcursmonst != -1) { if(CanTalkToMonst(pcursmonst)) { NetSendCmdParam1(1, CMD_ATTACKID, pcursmonst); } else { NetSendCmdParam1(1, CMD_RATTACKID, pcursmonst); } } else if(pcursplr != -1 && !FriendlyMode) { NetSendCmdParam1(1, CMD_RATTACKPID, pcursplr); } } else { if(bShift) { if(pcursmonst != -1) { if(CanTalkToMonst(pcursmonst)) { NetSendCmdParam1(1, CMD_ATTACKID, pcursmonst); } else { NetSendCmdLoc(1, CMD_SATTACKXY, cursmx, cursmy); } } else { NetSendCmdLoc(1, CMD_SATTACKXY, cursmx, cursmy); } } else if(pcursmonst != -1) { NetSendCmdParam1(1, CMD_ATTACKID, pcursmonst); } else if(pcursplr != -1 && !FriendlyMode) { NetSendCmdParam1(1, CMD_ATTACKPID, pcursplr); } } if(!bShift && pcursitem == -1 && pcursobj == -1 && pcursmonst == -1 && pcursplr == -1) { return TRUE; } } return FALSE; } BOOL TryIconCurs() { if(pcurs == CURSOR_RESURRECT) { NetSendCmdParam1(TRUE, CMD_RESURRECT, pcursplr); return TRUE; } else if(pcurs == CURSOR_HEALOTHER) { NetSendCmdParam1(TRUE, CMD_HEALOTHER, pcursplr); return TRUE; } else if(pcurs == CURSOR_TELEKINESIS) { DoTelekinesis(); return TRUE; } else if(pcurs == CURSOR_IDENTIFY) { if(pcursinvitem != -1) { CheckIdentify(myplr, pcursinvitem); } else { SetCursor_(CURSOR_HAND); } return TRUE; } else if(pcurs == CURSOR_REPAIR) { if(pcursinvitem != -1) { DoRepair(myplr, pcursinvitem); } else { SetCursor_(CURSOR_HAND); } return TRUE; } else if(pcurs == CURSOR_RECHARGE) { if(pcursinvitem != -1) { DoRecharge(myplr, pcursinvitem); } else { SetCursor_(CURSOR_HAND); } return TRUE; } else if(pcurs == CURSOR_TELEPORT) { if(pcursmonst != -1) { NetSendCmdParam3(TRUE, CMD_TSPELLID, pcursmonst, plr[myplr]._pTSpell, GetSpellLevel(myplr, plr[myplr]._pTSpell)); } else if(pcursplr != -1) { NetSendCmdParam3(TRUE, CMD_TSPELLPID, pcursplr, plr[myplr]._pTSpell, GetSpellLevel(myplr, plr[myplr]._pTSpell)); } else { NetSendCmdLocParam2(TRUE, CMD_TSPELLXY, cursmx, cursmy, plr[myplr]._pTSpell, GetSpellLevel(myplr, plr[myplr]._pTSpell)); } SetCursor_(CURSOR_HAND); return TRUE; } else if(pcurs == CURSOR_DISARM && pcursobj == -1) { SetCursor_(CURSOR_HAND); return TRUE; } return FALSE; } void LeftMouseUp() { gmenu_left_mouse(0); control_release_talk_btn(); if ( panbtndown ) CheckBtnUp(); if ( chrbtnactive ) ReleaseChrBtns(); if ( lvlbtndown ) ReleaseLvlBtn(); if ( stextflag ) ReleaseStoreBtn(); } void RightMouseDown() { if ( !gmenu_is_active() && sgnTimeoutCurs == CURSOR_NONE && PauseMode != 2 && !plr[myplr]._pInvincible ) { if ( doomflag ) { doom_close(); } else if ( !stextflag ) { if ( spselflag ) { SetSpell(); } else if ( MouseY >= 352 || (!sbookflag || MouseX <= 320) && !TryIconCurs() && (pcursinvitem == -1 || !UseInvItem(myplr, pcursinvitem)) ) { if ( pcurs == 1 ) { if ( pcursinvitem == -1 || !UseInvItem(myplr, pcursinvitem) ) CheckPlrSpell(); } else if ( pcurs > 1 && pcurs < 12 ) { SetCursor_(CURSOR_HAND); } } } } } BOOL PressSysKey(int wParam) { if ( gmenu_is_active() || wParam != VK_F10 ) return FALSE; diablo_hotkey_msg(1); return TRUE; } void diablo_hotkey_msg(DWORD dwMsg) { char *s; char szFileName[MAX_PATH]; char szMsg[MAX_SEND_STR_LEN]; if(gbMaxPlayers == 1) { return; } if(GetModuleFileName(ghInst, szFileName, sizeof(szFileName)) == 0) { app_fatal("Can't get program name"); } s = strrchr(szFileName, '\\'); if(s != NULL) { *s = '\0'; } strcat(szFileName, "\\Diablo.ini"); /// ASSERT: assert(dwMsg < sizeof(spszMsgTbl) / sizeof(spszMsgTbl[0])); GetPrivateProfileString("NetMsg", spszMsgKeyTbl[dwMsg], spszMsgTbl[dwMsg], szMsg, sizeof(szMsg), szFileName); NetSendCmdString(-1, szMsg); } void ReleaseKey(int vkey) { if ( vkey == VK_SNAPSHOT ) CaptureScreen(); } void PressKey(int vkey) { if(gmenu_presskeys(vkey) || control_presskeys(vkey)) { return; } if(deathflag) { if(sgnTimeoutCurs != 0) { return; } if(vkey == VK_F9) { diablo_hotkey_msg(0); } if(vkey == VK_F10) { diablo_hotkey_msg(1); } if(vkey == VK_F11) { diablo_hotkey_msg(2); } if(vkey == VK_F12) { diablo_hotkey_msg(3); } if(vkey == VK_RETURN) { control_type_message(); } if(vkey != VK_ESCAPE) { return; } } if(vkey == VK_ESCAPE) { if(!PressEscKey()) { track_repeat_walk(0); gamemenu_on(); } return; } if(sgnTimeoutCurs != 0 || dropGoldFlag) { return; } if(vkey == VK_PAUSE) { diablo_pause_game(); return; } if(PauseMode == 2) { return; } if(vkey == VK_RETURN) { if(stextflag) { STextEnter(); } else if(questlog) { QuestlogEnter(); } else { control_type_message(); } } else if(vkey == VK_F1) { if(helpflag) { helpflag = 0; } else if(stextflag) { ClearPanel(); AddPanelString("No help available", 1); /// BUGFIX: message isn't displayed AddPanelString("while in stores", 1); track_repeat_walk(0); } else { invflag = 0; chrflag = 0; sbookflag = 0; spselflag = 0; if(qtextflag && leveltype == DTYPE_TOWN) { qtextflag = 0; stream_stop(); } questlog = 0; automapflag = 0; msgdelay = 0; gamemenu_off(); DisplayHelp(); doom_close(); } } #ifdef _DEBUG else if(vkey == VK_F2) { } #endif #ifdef _DEBUG else if(vkey == VK_F3) { if(pcursitem != -1) { sprintf( tempstr, "IDX = %i : Seed = %i : CF = %i", item[pcursitem].IDidx, item[pcursitem]._iSeed, item[pcursitem]._iCreateInfo); NetSendCmdString(1 << myplr, tempstr); } sprintf(tempstr, "Numitems : %i", numitems); NetSendCmdString(1 << myplr, tempstr); } #endif #ifdef _DEBUG else if(vkey == VK_F4) { PrintDebugQuest(); } #endif else if(vkey == VK_F5) { if(spselflag) { SetSpeedSpell(0); } else { ToggleSpell(0); } } else if(vkey == VK_F6) { if(spselflag) { SetSpeedSpell(1); } else { ToggleSpell(1); } } else if(vkey == VK_F7) { if(spselflag) { SetSpeedSpell(2); } else { ToggleSpell(2); } } else if(vkey == VK_F8) { if(spselflag) { SetSpeedSpell(3); } else { ToggleSpell(3); } } else if(vkey == VK_F9) { diablo_hotkey_msg(0); } else if(vkey == VK_F10) { diablo_hotkey_msg(1); } else if(vkey == VK_F11) { diablo_hotkey_msg(2); } else if(vkey == VK_F12) { diablo_hotkey_msg(3); } else if(vkey == VK_UP) { if(stextflag) { STextUp(); } else if(questlog) { QuestlogUp(); } else if(helpflag) { HelpScrollUp(); } else if(automapflag) { AutomapUp(); } } else if(vkey == VK_DOWN) { if(stextflag) { STextDown(); } else if(questlog) { QuestlogDown(); } else if(helpflag) { HelpScrollDown(); } else if(automapflag) { AutomapDown(); } } else if(vkey == VK_PRIOR) { if(stextflag) { STextPrior(); } } else if(vkey == VK_NEXT) { if(stextflag) { STextNext(); } } else if(vkey == VK_LEFT) { if(automapflag && !talkflag) { AutomapLeft(); } } else if(vkey == VK_RIGHT) { if(automapflag && !talkflag) { AutomapRight(); } } else if(vkey == VK_TAB) { DoAutoMap(); } else if(vkey == VK_SPACE) { if(!chrflag && invflag && MouseX < 480 && MouseY < 352) { SetCursorPos(MouseX + 160, MouseY); } if(!invflag && chrflag && MouseX > 160 && MouseY < 352) { SetCursorPos(MouseX - 160, MouseY); } helpflag = 0; invflag = 0; chrflag = 0; sbookflag = 0; spselflag = 0; if(qtextflag && leveltype == DTYPE_TOWN) { qtextflag = 0; stream_stop(); } questlog = 0; automapflag = 0; msgdelay = 0; gamemenu_off(); doom_close(); } } void diablo_pause_game() { if ( (unsigned char)gbMaxPlayers <= 1u ) { if ( PauseMode ) { PauseMode = 0; } else { PauseMode = 2; sound_stop(); track_repeat_walk(0); } force_redraw = 255; } } /* NOTE: `return` must be used instead of `break` to be bin exact as C++ */ void PressChar(int vkey) { if(gmenu_is_active() || control_talk_last_key(vkey) || sgnTimeoutCurs != 0 || deathflag) { return; } if((char)vkey == 'p' || (char)vkey == 'P') { diablo_pause_game(); return; } if(PauseMode == 2) { return; } if(doomflag) { doom_close(); return; } if(dropGoldFlag) { control_drop_gold(vkey); return; } switch(vkey) { case 'G': case 'g': DecreaseGamma(); return; case 'F': case 'f': IncreaseGamma(); return; case 'I': case 'i': if(!stextflag) { sbookflag = 0; invflag = invflag == 0; if(!invflag || chrflag) { if(MouseX < 480 && MouseY < 352) { SetCursorPos(MouseX + 160, MouseY); } } else { if(MouseX > 160 && MouseY < 352) { SetCursorPos(MouseX - 160, MouseY); } } } return; case 'C': case 'c': if(!stextflag) { questlog = 0; chrflag = chrflag == 0; if(!chrflag || invflag) { if(MouseX > 160 && MouseY < 352) { SetCursorPos(MouseX - 160, MouseY); } } else { if(MouseX < 480 && MouseY < 352) { SetCursorPos(MouseX + 160, MouseY); } } } return; case 'Q': case 'q': if(!stextflag) { chrflag = 0; if(!questlog) { StartQuestlog(); } else { questlog = 0; } } return; case 'Z': case 'z': zoomflag = zoomflag == 0; return; case 'S': case 's': if(!stextflag) { invflag = 0; if(!spselflag) { DoSpeedBook(); } else { spselflag = 0; } track_repeat_walk(0); } return; case 'B': case 'b': if(!stextflag) { invflag = 0; sbookflag = sbookflag == 0; } return; case '+': case '=': if(automapflag) { AutomapZoomIn(); } return; case '-': case '_': if(automapflag) { AutomapZoomOut(); } return; case 'v': NetSendCmdString(1 << myplr, gszProductName); return; case 'V': NetSendCmdString(1 << myplr, gszVersionNumber); return; case '!': case '1': if(plr[myplr].SpdList[0]._itype != -1 && plr[myplr].SpdList[0]._itype != 11) { UseInvItem(myplr, 47); } return; case '@': case '2': if(plr[myplr].SpdList[1]._itype != -1 && plr[myplr].SpdList[1]._itype != 11) { UseInvItem(myplr, 48); } return; case '#': case '3': if(plr[myplr].SpdList[2]._itype != -1 && plr[myplr].SpdList[2]._itype != 11) { UseInvItem(myplr, 49); } return; case '$': case '4': if(plr[myplr].SpdList[3]._itype != -1 && plr[myplr].SpdList[3]._itype != 11) { UseInvItem(myplr, 50); } return; case '%': case '5': if(plr[myplr].SpdList[4]._itype != -1 && plr[myplr].SpdList[4]._itype != 11) { UseInvItem(myplr, 51); } return; case '^': case '6': if(plr[myplr].SpdList[5]._itype != -1 && plr[myplr].SpdList[5]._itype != 11) { UseInvItem(myplr, 52); } return; case '&': case '7': if(plr[myplr].SpdList[6]._itype != -1 && plr[myplr].SpdList[6]._itype != 11) { UseInvItem(myplr, 53); } return; case '*': case '8': #ifdef _DEBUG if(debug_mode_key_inverted_v || debug_mode_key_w) { NetSendCmd(TRUE, CMD_CHEAT_EXPERIENCE); return; } #endif if(plr[myplr].SpdList[7]._itype != -1 && plr[myplr].SpdList[7]._itype != 11) { UseInvItem(myplr, 54); } return; #ifdef _DEBUG case ')': case '0': if(debug_mode_key_inverted_v) { if(arrowdebug > 2) { arrowdebug = 0; } if(arrowdebug == 0) { plr[myplr]._pIFlags &= ~ISPL_FIRE_ARROWS; plr[myplr]._pIFlags &= ~ISPL_LIGHT_ARROWS; } if(arrowdebug == 1) { plr[myplr]._pIFlags |= ISPL_FIRE_ARROWS; } if(arrowdebug == 2) { plr[myplr]._pIFlags |= ISPL_LIGHT_ARROWS; } arrowdebug++; } return; case ':': if(currlevel == 0 && debug_mode_key_w) { SetAllSpellsCheat(); } return; case '[': if(currlevel == 0 && debug_mode_key_w) { TakeGoldCheat(); } return; case ']': if(currlevel == 0 && debug_mode_key_w) { MaxSpellsCheat(); } return; case 'a': if(debug_mode_key_inverted_v) { spelldata[SPL_TELEPORT].sTownSpell = 1; plr[myplr]._pSplLvl[plr[myplr]._pSpell]++; } return; case 'D': PrintDebugPlayer(1); return; case 'd': PrintDebugPlayer(0); return; case 'e': if(debug_mode_key_d) { sprintf(tempstr, "EFlag = %i", plr[myplr]._peflag); NetSendCmdString(1 << myplr, tempstr); } return; case 'L': case 'l': if(debug_mode_key_inverted_v) { ToggleLighting(); } return; case 'M': NextDebugMonster(); return; case 'm': GetDebugMonster(); return; case 'R': case 'r': sprintf(tempstr, "seed = %i", glSeedTbl[currlevel]); NetSendCmdString(1 << myplr, tempstr); sprintf(tempstr, "Mid1 = %i : Mid2 = %i : Mid3 = %i", glMid1Seed[currlevel], glMid2Seed[currlevel], glMid3Seed[currlevel]); NetSendCmdString(1 << myplr, tempstr); sprintf(tempstr, "End = %i", glEndSeed[currlevel]); NetSendCmdString(1 << myplr, tempstr); return; case 'T': case 't': if(debug_mode_key_inverted_v) { sprintf(tempstr, "PX = %i PY = %i", plr[myplr].WorldX, plr[myplr].WorldY); NetSendCmdString(1 << myplr, tempstr); sprintf(tempstr, "CX = %i CY = %i DP = %i", cursmx, cursmy, dungeon[cursmx][cursmy]); NetSendCmdString(1 << myplr, tempstr); } return; case '|': if(currlevel == 0 && debug_mode_key_w) { GiveGoldCheat(); } return; case '~': if(currlevel == 0 && debug_mode_key_w) { StoresCheat(); } return; #endif } } void LoadLvlGFX() { /// ASSERT: assert(! pDungeonCels); switch((unsigned char)leveltype) { case DTYPE_TOWN: pDungeonCels = DiabLoad("Levels\\TownData\\Town.CEL", NULL, 'TILE'); pMegaTiles = DiabLoad("Levels\\TownData\\Town.TIL", NULL, 'TILE'); pLevelPieces = DiabLoad("Levels\\TownData\\Town.MIN", NULL, 'TILE'); pSpecialCels = DiabLoad("Levels\\TownData\\TownS.CEL", NULL, 'TILE'); break; case DTYPE_CATHEDRAL: pDungeonCels = DiabLoad("Levels\\L1Data\\L1.CEL", NULL, 'TILE'); pMegaTiles = DiabLoad("Levels\\L1Data\\L1.TIL", NULL, 'TILE'); pLevelPieces = DiabLoad("Levels\\L1Data\\L1.MIN", NULL, 'TILE'); pSpecialCels = DiabLoad("Levels\\L1Data\\L1S.CEL", NULL, 'TILE'); break; case DTYPE_CATACOMBS: pDungeonCels = DiabLoad("Levels\\L2Data\\L2.CEL", NULL, 'TILE'); pMegaTiles = DiabLoad("Levels\\L2Data\\L2.TIL", NULL, 'TILE'); pLevelPieces = DiabLoad("Levels\\L2Data\\L2.MIN", NULL, 'TILE'); pSpecialCels = DiabLoad("Levels\\L2Data\\L2S.CEL", NULL, 'TILE'); break; case DTYPE_CAVES: pDungeonCels = DiabLoad("Levels\\L3Data\\L3.CEL", NULL, 'TILE'); pMegaTiles = DiabLoad("Levels\\L3Data\\L3.TIL", NULL, 'TILE'); pLevelPieces = DiabLoad("Levels\\L3Data\\L3.MIN", NULL, 'TILE'); pSpecialCels = DiabLoad("Levels\\L1Data\\L1S.CEL", NULL, 'TILE'); break; case DTYPE_HELL: pDungeonCels = DiabLoad("Levels\\L4Data\\L4.CEL", NULL, 'TILE'); pMegaTiles = DiabLoad("Levels\\L4Data\\L4.TIL", NULL, 'TILE'); pLevelPieces = DiabLoad("Levels\\L4Data\\L4.MIN", NULL, 'TILE'); pSpecialCels = DiabLoad("Levels\\L2Data\\L2S.CEL", NULL, 'TILE'); break; default: app_fatal("LoadLvlGFX"); break; } } void LoadAllGFX() { /// ASSERT: assert(! pSpeedCels); pSpeedCels = DiabloAllocPtr(0x100000); IncProgress(); IncProgress(); InitObjectGFX(); IncProgress(); InitMissileGFX(); IncProgress(); } void CreateLevel(int lvldir) { switch((unsigned char)leveltype) { case DTYPE_TOWN: CreateTown(lvldir); InitTownTriggers(); LoadRndLvlPal(0); break; case DTYPE_CATHEDRAL: CreateL5Dungeon(glSeedTbl[currlevel], lvldir); InitL1Triggers(); Freeupstairs(); LoadRndLvlPal(1); break; case DTYPE_CATACOMBS: CreateL2Dungeon(glSeedTbl[currlevel], lvldir); InitL2Triggers(); Freeupstairs(); LoadRndLvlPal(2); break; case DTYPE_CAVES: CreateL3Dungeon(glSeedTbl[currlevel], lvldir); InitL3Triggers(); Freeupstairs(); LoadRndLvlPal(3); break; case DTYPE_HELL: CreateL4Dungeon(glSeedTbl[currlevel], lvldir); InitL4Triggers(); Freeupstairs(); LoadRndLvlPal(4); break; default: app_fatal("CreateLevel"); break; } } void LoadGameLevel(BOOL firstflag, int lvldir) { int i, j; BOOL visited; if(setseed) glSeedTbl[currlevel] = setseed; music_stop(); SetCursor_(CURSOR_HAND); SetRndSeed(glSeedTbl[currlevel]); IncProgress(); MakeLightTable(); LoadLvlGFX(); IncProgress(); if(firstflag) { InitInv(); InitItemGFX(); InitQuestText(); for(i = 0; i < gbMaxPlayers; i++) InitPlrGFXMem(i); InitStores(); InitAutomapOnce(); InitHelp(); } SetRndSeed(glSeedTbl[currlevel]); if(leveltype == DTYPE_TOWN) SetupTownStores(); IncProgress(); InitAutomap(); if(leveltype != DTYPE_TOWN && lvldir != 4) { InitLighting(); InitVision(); } InitLevelMonsters(); IncProgress(); if(!setlevel) { CreateLevel(lvldir); IncProgress(); FillSolidBlockTbls(); SetRndSeed(glSeedTbl[currlevel]); if(leveltype != DTYPE_TOWN) { GetLevelMTypes(); InitThemes(); LoadAllGFX(); } else { InitMissileGFX(); } IncProgress(); if(lvldir == 3) GetReturnLvlPos(); if(lvldir == 5) GetPortalLvlPos(); IncProgress(); for(i = 0; i < MAX_PLRS; i++) { if(plr[i].plractive && currlevel == plr[i].plrlevel) { InitPlayerGFX(i); if(lvldir != 4) InitPlayer(i, firstflag); } } PlayDungMsgs(); InitMultiView(); IncProgress(); visited = FALSE; for(i = 0; i < gbMaxPlayers; i++) { if(plr[i].plractive) visited = visited || plr[i]._pLvlVisited[currlevel]; } SetRndSeed(glSeedTbl[currlevel]); if(leveltype != DTYPE_TOWN) { if(firstflag || lvldir == 4 || !plr[myplr]._pLvlVisited[currlevel] || gbMaxPlayers != 1) { HoldThemeRooms(); glMid1Seed[currlevel] = GetRndSeed(); InitMonsters(); glMid2Seed[currlevel] = GetRndSeed(); InitObjects(); InitItems(); CreateThemeRooms(); glMid3Seed[currlevel] = GetRndSeed(); InitMissiles(); InitDead(); glEndSeed[currlevel] = GetRndSeed(); if(gbMaxPlayers != 1) DeltaLoadLevel(); IncProgress(); SavePreLighting(); } else { InitMonsters(); InitMissiles(); InitDead(); IncProgress(); LoadLevel(); IncProgress(); } } else { for(i = 0; i < MAXDUNX; i++) { for(j = 0; j < MAXDUNY; j++) dFlags[i][j] |= 0x40; } InitTowners(); InitItems(); InitMissiles(); IncProgress(); if(!firstflag && lvldir != 4 && plr[myplr]._pLvlVisited[currlevel] && gbMaxPlayers == 1) LoadLevel(); if(gbMaxPlayers != 1) DeltaLoadLevel(); IncProgress(); } if(gbMaxPlayers == 1) ResyncQuests(); else ResyncMPQuests(); } else { /// ASSERT: assert(! pSpeedCels); pSpeedCels = DiabloAllocPtr(0x100000); LoadSetMap(); IncProgress(); GetLevelMTypes(); InitMonsters(); InitMissileGFX(); InitDead(); FillSolidBlockTbls(); IncProgress(); if(lvldir == 5) GetPortalLvlPos(); for(i = 0; i < MAX_PLRS; i++) { if(plr[i].plractive && currlevel == plr[i].plrlevel) { InitPlayerGFX(i); if(lvldir != 4) InitPlayer(i, firstflag); } } InitMultiView(); IncProgress(); if(firstflag || lvldir == 4 || !plr[myplr]._pSLvlVisited[(unsigned char)setlvlnum]) { InitItems(); SavePreLighting(); } else { LoadLevel(); } InitMissiles(); IncProgress(); } SyncPortals(); for(i = 0; i < MAX_PLRS; i++) { if(plr[i].plractive && plr[i].plrlevel == currlevel && (!plr[i]._pLvlChanging || i == myplr)) { if(plr[i]._pHitPoints > 0) { if(gbMaxPlayers == 1) dPlayer[plr[i].WorldX][plr[i].WorldY] = i + 1; else SyncInitPlrPos(i); } else { dFlags[plr[i].WorldX][plr[i].WorldY] |= 4; } } } if(leveltype != DTYPE_TOWN) SetDungeonMicros(); InitLightMax(); IncProgress(); IncProgress(); if(firstflag) { InitControlPan(); IncProgress(); } if(leveltype != DTYPE_TOWN) { ProcessLightList(); ProcessVisionList(); } music_start((unsigned char)leveltype); while(!IncProgress()); if(setlevel && setlvlnum == SL_SKELKING && quests[12]._qactive == 2) PlaySFX(USFX_SKING1); } void game_loop(BOOL bStartup) { int i; i = bStartup ? 60 : 3; while(i--) { if(!multi_handle_delta()) { timeout_cursor(1); break; } else { timeout_cursor(0); game_logic(); } if(!gbRunGame || gbMaxPlayers == 1 || !nthread_has_500ms_passed(1)) break; } } void game_logic() { if(PauseMode == 2) { return; } if(PauseMode == 1) { PauseMode = 2; } if(gbMaxPlayers == 1 && gmenu_is_active()) { force_redraw |= 1; return; } if(!gmenu_is_active() && sgnTimeoutCurs == 0) { CheckCursMove(); track_process(); } if(gbProcessPlayers) { ProcessPlayers(); } if(leveltype != DTYPE_TOWN) { ProcessMonsters(); ProcessObjects(); ProcessMissiles(); ProcessItems(); ProcessLightList(); ProcessVisionList(); } else { ProcessTowners(); ProcessItems(); ProcessMissiles(); } #ifdef _DEBUG if(debug_mode_key_inverted_v && GetAsyncKeyState(VK_SHIFT) & 0x8000) { ScrollView(); } #endif sound_update(); ClearPlrMsg(); CheckTriggers(); CheckQuests(); force_redraw |= 1; pfile_update(FALSE); } void timeout_cursor(BOOL bTimeout) { if ( bTimeout ) { if ( sgnTimeoutCurs == CURSOR_NONE && !sgbMouseDown ) { sgnTimeoutCurs = pcurs; multi_net_ping(); ClearPanel(); AddPanelString("-- Network timeout --", 1); AddPanelString("-- Waiting for players --", 1); SetCursor_(CURSOR_HOURGLASS); force_redraw = 255; } scrollrt_draw_game_screen(1); } else if ( sgnTimeoutCurs ) { SetCursor_(sgnTimeoutCurs); sgnTimeoutCurs = 0; ClearPanel(); force_redraw = 255; } } void diablo_color_cyc_logic() { DWORD v0; // eax v0 = GetTickCount(); if ( v0 - color_cycle_timer >= 0x32 ) { color_cycle_timer = v0; if ( palette_get_colour_cycling() ) { if ( leveltype == DTYPE_HELL ) { lighting_color_cycling(); } else if ( leveltype == DTYPE_CAVES ) { if ( fullscreen ) palette_update_caves(); } } } }