mirror of
https://github.com/jmarshall23/Hellfire.git
synced 2026-08-12 07:50:53 +02:00
3098 lines
71 KiB
Plaintext
3098 lines
71 KiB
Plaintext
/*-----------------------------------------------------------------------**
|
|
** Diablo
|
|
**
|
|
** Main file
|
|
**
|
|
** (C)1995 Condor, Inc. All rights reserved.
|
|
**
|
|
**-----------------------------------------------------------------------**
|
|
** $Header: /Diablo/DIABLO.CPP 16 3/29/97 9:09p Pwyatt $
|
|
**-----------------------------------------------------------------------*/
|
|
|
|
#include "diablo.h"
|
|
#pragma hdrstop
|
|
#include "storm.h"
|
|
#include "sound.h"
|
|
#include "mainmenu.h"
|
|
#include "interfac.h"
|
|
#include "inv.h"
|
|
#include "msg.h"
|
|
#include "multi.h"
|
|
#include "engine.h"
|
|
#include "palette.h"
|
|
#include "scrollrt.h"
|
|
#include "gendung.h"
|
|
#include "setmaps.h"
|
|
#include "debug.h"
|
|
#include "effects.h"
|
|
|
|
#include "dead.h"
|
|
#include "lighting.h"
|
|
#include "control.h"
|
|
#include "gamemenu.h"
|
|
|
|
#include "items.h"
|
|
#include "player.h"
|
|
#include "monster.h"
|
|
#include "objects.h"
|
|
#include "missiles.h"
|
|
#include "trigs.h"
|
|
#include "spelldat.h"
|
|
#include "spells.h"
|
|
#include "cursor.h"
|
|
|
|
#include "town.h"
|
|
#include "towners.h"
|
|
#include "drlg_l1.h"
|
|
#include "drlg_l2.h"
|
|
#include "drlg_l3.h"
|
|
#include "drlg_l4.h"
|
|
#include "quests.h"
|
|
#include "minitext.h"
|
|
#include "themes.h"
|
|
#include "stores.h"
|
|
#include "packplr.h"
|
|
#include "portal.h"
|
|
#include "doom.h"
|
|
|
|
#include "automap.h"
|
|
#include "help.h"
|
|
#include "error.h"
|
|
#include "diabloui.h"
|
|
#include "textdat.h"
|
|
// pjw.patch1.start
|
|
#include "mpqapi.h"
|
|
#include <stddef.h>
|
|
// pjw.patch1.end
|
|
#include "mono.h"
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
** Registration info
|
|
**-----------------------------------------------------------------------*/
|
|
#include "regconst.h"
|
|
char sgszTblSig[TBL_LEN] = "REGISTRATION_TABLE";
|
|
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
** Global Variables
|
|
**-----------------------------------------------------------------------*/
|
|
extern char gszProgKey[];
|
|
BYTE gbDoEnding;
|
|
void DoEnding();
|
|
|
|
int StripPlayer(int pnum);
|
|
|
|
DWORD glSeedTbl[NUMLEVELS];
|
|
int gnLevelTypeTbl[NUMLEVELS];
|
|
|
|
// window vars
|
|
HWND ghMainWnd;
|
|
HINSTANCE ghInst;
|
|
|
|
// video vars
|
|
BOOL fullscreen = TRUE;
|
|
|
|
|
|
// mouse
|
|
int MouseX, MouseY;
|
|
|
|
// program vars
|
|
int force_redraw = NODRAW;
|
|
|
|
BOOL svgamode;
|
|
|
|
// Temp vars (delete all uses before final compile)
|
|
long gv1;
|
|
long gv2;
|
|
long gv3;
|
|
long gv4;
|
|
long gv5;
|
|
|
|
#ifndef NDEBUG
|
|
// do not change this flag -- USE 'n' on the command line
|
|
static BOOL cineflag = TRUE;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
BOOL gbDumpDropLog = FALSE;
|
|
BOOL davedebug = FALSE;
|
|
BOOL cheatflag = FALSE; // Turn invincibility and all spells on/off
|
|
BOOL simplecheat = FALSE; // like cheatflag, but doesn't screw up game
|
|
BOOL gbNoDropInactive = FALSE; // don't drop players on timeout
|
|
int tstQMsgSpd;
|
|
int tstQMsgIndex = 0;
|
|
BOOL tstQMsgFlag = FALSE;
|
|
BOOL tstQMsgIndexFlag = FALSE;
|
|
BOOL itemcheat = FALSE;
|
|
BOOL uniqcheat = FALSE;
|
|
#endif
|
|
|
|
BOOL visiondebug = FALSE; // Vision debugging
|
|
BOOL scrollflag = FALSE; // Scroll when at edge of screen with mouse
|
|
BOOL light4flag = FALSE; // 4 levels of light instead of 16
|
|
BOOL leveldebug = FALSE;
|
|
BOOL monstdebug = FALSE;
|
|
BOOL trigdebug = FALSE;
|
|
int setseed = 0;
|
|
|
|
int debugmonsttypes = 0;
|
|
int DebugMonsters[10];
|
|
|
|
BOOL PauseMode = FALSE;
|
|
BOOL FriendlyMode = TRUE;
|
|
|
|
BOOL gbRunGame;
|
|
BOOL gbRunGameResult;
|
|
BOOL gbProcessPlayers;
|
|
BOOL gbGameLoopStartup;
|
|
|
|
bool gbTheo = false;
|
|
bool gbCowsuit = false;
|
|
bool gbOurNest = false;
|
|
bool gbAllowBard = false;
|
|
bool gbAllowMultiPlayer = false;
|
|
|
|
//int glEndSeed[17]; // @@@ drb temp
|
|
//int glMid1Seed[17];
|
|
//int glMid2Seed[17];
|
|
//int glMid3Seed[17];
|
|
|
|
int glEndSeed[NUMLEVELS+1]; // @@@ drb temp
|
|
int glMid1Seed[NUMLEVELS+1];
|
|
int glMid2Seed[NUMLEVELS+1];
|
|
int glMid3Seed[NUMLEVELS+1]; //JKE 7/30 adds new levels
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
** timeout cursor
|
|
**-----------------------------------------------------------------------*/
|
|
#define TIMEOUT_CURSOR WATCH_CURS
|
|
static int sgnTimeoutCurs = NO_CURSOR;
|
|
|
|
#define LMOUSE_DOWN 1
|
|
#define RMOUSE_DOWN 2
|
|
// drb.patch1.start.1/24/97
|
|
// static BYTE sgbMouseDown = 0;
|
|
BYTE sgbMouseDown = 0;
|
|
// drb.patch1.end.1/24/97
|
|
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
** Function stubs
|
|
**-----------------------------------------------------------------------*/
|
|
// pjw.patch1.start
|
|
// static void try_game_loop(BOOL bStartup);
|
|
static void alloc_plr();
|
|
static void DoTimedEvents();
|
|
static void game_loop(BOOL bStartup);
|
|
static void plr_encrypt(BOOL bEncrypt);
|
|
void InitializeHashSource();
|
|
void Decrypt(LPDWORD data, DWORD bytes, DWORD key);
|
|
void Encrypt(LPDWORD data, DWORD bytes, DWORD key);
|
|
// pjw.patch1.end
|
|
|
|
|
|
void BlackPalette();
|
|
void enable_frame_counter();
|
|
void init_window(int nCmdShow);
|
|
void play_movie(const char * pszMovie,BOOL bAllowCancel);
|
|
void play_quotes();
|
|
void play_quit();
|
|
void FreeCursor();
|
|
void InitDebugGFX();
|
|
void FreeDebugGFX();
|
|
void ShowProgress(UINT uMsg);
|
|
static LRESULT CALLBACK GM_Game(HWND, UINT, WPARAM, LPARAM);
|
|
void TrackInit(BOOL bMouseDown);
|
|
void TrackMouse();
|
|
void run_delta_info();
|
|
void toggle_frame_counter();
|
|
WNDPROC my_SetWindowProc(WNDPROC wndProc);
|
|
void plrmsg_update();
|
|
void screen_capture();
|
|
void SavePaletteSettings();
|
|
void menu_music();
|
|
void NetStartTimeout();
|
|
void menusnd_init();
|
|
void InitLevels();
|
|
void SyncInitPlrPos(int pnum);
|
|
|
|
void OpenCloseAllDoors();
|
|
void OpenNaKrul();
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void FlushMsgs() {
|
|
// turn tracking off
|
|
TrackInit(FALSE);
|
|
sgbMouseDown = FALSE;
|
|
ReleaseCapture();
|
|
|
|
// keep flushing messages until all key and mouse msgs are gone
|
|
BOOL bLoop = TRUE;
|
|
while (bLoop) {
|
|
bLoop = FALSE;
|
|
MSG msg;
|
|
while (PeekMessage(&msg,NULL,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE))
|
|
bLoop = TRUE;
|
|
while (PeekMessage(&msg,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
|
|
bLoop = TRUE;
|
|
}
|
|
}
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void CommandLine(const char * s) {
|
|
int val;
|
|
(val);
|
|
|
|
while (*s) {
|
|
|
|
// skip over any space characters
|
|
while (isspace(*s))
|
|
s++;
|
|
|
|
// check for direct draw emulation mode
|
|
// pjw.patch1.start.1/13/97
|
|
static const char sszEmulate[] = "dd_emulate";
|
|
if (! _strnicmp(sszEmulate,s,strlen(sszEmulate))) {
|
|
extern BYTE gbUseDDEmulation;
|
|
gbUseDDEmulation = TRUE;
|
|
s += strlen(sszEmulate);
|
|
continue;
|
|
}
|
|
|
|
// check for direct draw offscreen buffer
|
|
static const char sszBackBuf[] = "dd_backbuf";
|
|
if (! _strnicmp(sszBackBuf,s,strlen(sszBackBuf))) {
|
|
extern BYTE gbForceBackBuf;
|
|
gbForceBackBuf = TRUE;
|
|
s += strlen(sszBackBuf);
|
|
continue;
|
|
}
|
|
|
|
static const char sszDupSound[] = "ds_noduplicates";
|
|
if (! _strnicmp(sszDupSound,s,strlen(sszDupSound))) {
|
|
extern BYTE gbDupSounds;
|
|
gbDupSounds = FALSE;
|
|
s += strlen(sszDupSound);
|
|
continue;
|
|
}
|
|
|
|
char const sszTheoFlag[] = "Theoquest";
|
|
if (! _strnicmp(sszTheoFlag, s, strlen(sszTheoFlag))) {
|
|
gbTheo = true;
|
|
s += strlen(sszTheoFlag);
|
|
continue;
|
|
}
|
|
|
|
char const sszCowQuestFlag[] = "Cowquest";
|
|
if (!_strnicmp(sszCowQuestFlag, s, strlen(sszCowQuestFlag))) {
|
|
gbCowsuit = true;
|
|
s += strlen(sszCowQuestFlag);
|
|
continue;
|
|
}
|
|
|
|
char const sszOurNestFlag[] = "NestArt";
|
|
if (!_strnicmp(sszOurNestFlag, s, strlen(sszOurNestFlag))) {
|
|
gbOurNest = true;
|
|
s += strlen(sszOurNestFlag);
|
|
continue;
|
|
}
|
|
|
|
char const sszAllowBardFlag[] = "Bardtest";
|
|
if (!_strnicmp(sszAllowBardFlag, s, strlen(sszAllowBardFlag))) {
|
|
gbAllowBard = true;
|
|
s += strlen(sszAllowBardFlag);
|
|
continue;
|
|
}
|
|
|
|
char const sszAllowMultiPlayerFlag[] = "Multitest";
|
|
if (!_strnicmp(sszAllowMultiPlayerFlag, s, strlen(sszAllowMultiPlayerFlag))) {
|
|
gbAllowMultiPlayer = true;
|
|
s += strlen(sszAllowMultiPlayerFlag);
|
|
continue;
|
|
}
|
|
|
|
// pjw.patch1.end.1/13/97
|
|
|
|
// extract next character -- do not do ++ inside macro
|
|
// some versions of C may have nasty side effects...
|
|
char c = tolower(*s); s++;
|
|
switch (c) {
|
|
#if CHEATS
|
|
case 'b':
|
|
gbDumpDropLog = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'i':
|
|
gbNoDropInactive = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
// this cheat flag is for testing without having your
|
|
// character die every two seconds -- doesn't have
|
|
// all the nasty side effects of the cheat flag
|
|
case '$':
|
|
simplecheat = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
// this cheat flag is the do-everything cheat for programmers
|
|
// it has all sorts of nasty side effects which may hide bugs
|
|
case '^':
|
|
cheatflag = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'd':
|
|
davedebug = TRUE;
|
|
cineflag = FALSE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'w':
|
|
davecheat = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS && !IS_VERSION(SHAREWARE)
|
|
case 'l':
|
|
leveldebug = TRUE;
|
|
setlevel = FALSE;
|
|
|
|
// get level type
|
|
while (isspace(*s))
|
|
s++;
|
|
val = 0;
|
|
while (isdigit(*s)) {
|
|
val *= 10;
|
|
val += *s - '0';
|
|
s++;
|
|
}
|
|
leveltype = val;
|
|
|
|
// get level num
|
|
while (isspace(*s))
|
|
s++;
|
|
val = 0;
|
|
while (isdigit(*s)) {
|
|
val *= 10;
|
|
val += *s - '0';
|
|
s++;
|
|
}
|
|
currlevel = val;
|
|
plr[0].plrlevel = val;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'm':
|
|
monstdebug = TRUE;
|
|
|
|
// get monster number
|
|
while (isspace(*s))
|
|
s++;
|
|
val = 0;
|
|
while (isdigit(*s)) {
|
|
val *= 10;
|
|
val += *s - '0';
|
|
s++;
|
|
}
|
|
DebugMonsters[debugmonsttypes++] = val;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'q':
|
|
// get quest number
|
|
while(isspace(*s))
|
|
s++;
|
|
val = 0;
|
|
while (isdigit(*s)) {
|
|
val *= 10;
|
|
val += *s - '0';
|
|
s++;
|
|
}
|
|
extern int questcheat;
|
|
questcheat = val;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'r':
|
|
while(isspace(*s))
|
|
s++;
|
|
val = 0;
|
|
while(isdigit(*s)) {
|
|
val *= 10;
|
|
val += *s - '0';
|
|
s++;
|
|
}
|
|
setseed = val;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 's':
|
|
scrollflag = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS && !IS_VERSION(SHAREWARE)
|
|
case 't':
|
|
leveldebug = TRUE;
|
|
setlevel = TRUE;
|
|
while (isspace(*s))
|
|
s++;
|
|
val = 0;
|
|
while (isdigit(*s)) {
|
|
val *= 10;
|
|
val += *s - '0';
|
|
s++;
|
|
}
|
|
setlvlnum = val;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'j':
|
|
while (isspace(*s))
|
|
s++;
|
|
val = 0;
|
|
while (isdigit(*s)) {
|
|
val *= 10;
|
|
val += *s - '0';
|
|
s++;
|
|
}
|
|
trigdebug = val;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'v':
|
|
visiondebug = TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
case 'f':
|
|
toggle_frame_counter();
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
case 'x':
|
|
fullscreen = FALSE;
|
|
break;
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
case 'n':
|
|
cineflag = FALSE;
|
|
break;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case '7':
|
|
itemcheat = TRUE;
|
|
break;
|
|
|
|
case '8':
|
|
uniqcheat = TRUE;
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
void FreeGameMem() {
|
|
music_stop();
|
|
|
|
DiabloFreePtr(pDungeonCels);
|
|
DiabloFreePtr(pMegaTiles);
|
|
DiabloFreePtr(pMiniTiles);
|
|
DiabloFreePtr(pSpecialCels);
|
|
DiabloFreePtr(pSpeedCels);
|
|
FreeMissileGFX();
|
|
|
|
FreeMonsterGFX();
|
|
FreeObjectGFX();
|
|
FreeMonsterSnd();
|
|
FreeTownerGFX();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// stuff done every time a game is started/ended
|
|
//******************************************************************
|
|
static void start_game(UINT uMsg) {
|
|
gbDoEnding = FALSE;
|
|
svgamode = TRUE;
|
|
InitCursor();
|
|
InitLightTable();
|
|
InitDebugGFX();
|
|
app_assert(ghMainWnd);
|
|
music_stop();
|
|
ShowProgress(uMsg);
|
|
gmenu_init();
|
|
InitLevelCursor();
|
|
sgnTimeoutCurs = NO_CURSOR;
|
|
sgbMouseDown = 0;
|
|
TrackInit(FALSE);
|
|
}
|
|
static void free_game() {
|
|
FreeControlPan();
|
|
FreeInvGFX();
|
|
gmenu_free();
|
|
FreeQuestText();
|
|
FreeStoreMem();
|
|
for (int i = 0; i < MAX_PLRS; i++)
|
|
FreePlayerGFX(i);
|
|
FreeItemGFX();
|
|
|
|
FreeCursor();
|
|
FreeLightTable();
|
|
FreeDebugGFX();
|
|
FreeGameMem();
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
**-----------------------------------------------------------------------*/
|
|
static void run_game_loop(UINT uMsg) {
|
|
nthread_perform_keepalive(TRUE);
|
|
start_game(uMsg);
|
|
app_assert(ghMainWnd);
|
|
WNDPROC saveProc = my_SetWindowProc(GM_Game);
|
|
CalcInitBallPer();
|
|
// pjw.patch2.start
|
|
// nthread_perform_keepalive(FALSE);
|
|
// pjw.patch2.end
|
|
run_delta_info();
|
|
|
|
gbRunGame = TRUE;
|
|
gbProcessPlayers = TRUE;
|
|
gbRunGameResult = TRUE;
|
|
force_redraw = FULLDRAW;
|
|
DrawAndBlit();
|
|
PaletteFadeIn(FADE_FAST);
|
|
force_redraw = FULLDRAW;
|
|
gbGameLoopStartup = TRUE;
|
|
|
|
// pjw.patch2.start
|
|
nthread_perform_keepalive(FALSE);
|
|
// pjw.patch2.end
|
|
|
|
|
|
// pjw.patch1.start
|
|
MSG msg;
|
|
plr_encrypt(TRUE);
|
|
while (gbRunGame) {
|
|
DoTimedEvents(); // palette cycling
|
|
|
|
// pjw.patch2.start
|
|
// if there are any messages in the queue, process them all
|
|
if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) {
|
|
// bump thread priority to make sure that
|
|
// during peekmessage loop we are less likely
|
|
// to yield to another process
|
|
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL);
|
|
plr_encrypt(FALSE);
|
|
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
|
|
if (msg.message == WM_QUIT) {
|
|
gbRunGame = gbRunGameResult = FALSE;
|
|
break;
|
|
}
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
BOOL bRun = gbRunGame && nthread_run_gameloop(FALSE);
|
|
if (! bRun) plr_encrypt(TRUE);
|
|
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
|
|
if (! bRun) continue;
|
|
}
|
|
else if (! nthread_run_gameloop(FALSE)) {
|
|
// not enough time has elapsed since last gameloop
|
|
continue;
|
|
}
|
|
// pjw.patch2.end
|
|
|
|
// actual game logic
|
|
plr_encrypt(FALSE);
|
|
NetReceivePackets();
|
|
game_loop(gbGameLoopStartup);
|
|
gbGameLoopStartup = FALSE;
|
|
DrawAndBlit();
|
|
plr_encrypt(TRUE);
|
|
}
|
|
plr_encrypt(FALSE);
|
|
// pjw.patch1.end
|
|
|
|
// save character in multiplayer mode
|
|
if (gbMaxPlayers > 1) {
|
|
void UpdatePlayerFile();
|
|
UpdatePlayerFile();
|
|
}
|
|
void ReleasePlayerFile();
|
|
ReleasePlayerFile();
|
|
|
|
PaletteFadeOut(FADE_FAST);
|
|
SetCursor(NO_CURSOR);
|
|
ClrDraw();
|
|
force_redraw = FULLDRAW;
|
|
FullBlit(TRUE);
|
|
|
|
// restore old window procedure
|
|
saveProc = my_SetWindowProc(saveProc);
|
|
app_assert(saveProc == GM_Game);
|
|
|
|
free_game();
|
|
|
|
if (gbDoEnding) {
|
|
gbDoEnding = FALSE;
|
|
DoEnding();
|
|
}
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
// return FALSE to quit game
|
|
// return TRUE to continue game
|
|
**-----------------------------------------------------------------------*/
|
|
BOOL StartGame(BOOL bNewGame, BOOL bSinglePlayer) {
|
|
|
|
extern BYTE gbSelectProvider;
|
|
gbSelectProvider = TRUE;
|
|
|
|
while (1) {
|
|
|
|
// initialize network
|
|
BOOL fExitProgram = FALSE;
|
|
if (! NetInit(bSinglePlayer,&fExitProgram)) {
|
|
gbRunGameResult = !fExitProgram;
|
|
break;
|
|
}
|
|
|
|
gbSelectProvider = FALSE;
|
|
|
|
UINT uMsg;
|
|
if (bNewGame || !gbValidSaveFile) {
|
|
|
|
InitLevels();
|
|
InitQuests();
|
|
InitPortals();
|
|
InitDungMsgs(myplr);
|
|
if (!gbValidSaveFile && gbSaveFileExists)
|
|
{
|
|
// clear the items from the character's inventory
|
|
StripPlayer(myplr);
|
|
}
|
|
uMsg = WM_DIABNEWGAME;
|
|
}
|
|
else {
|
|
uMsg = WM_DIABLOADGAME;
|
|
}
|
|
|
|
run_game_loop(uMsg);
|
|
NetClose();
|
|
|
|
// in single player mode, exit this loop
|
|
if (gbMaxPlayers == 1) break;
|
|
|
|
// in multiplayer mode, only break out of the
|
|
// loop if the player wants to exit the game, otherwise
|
|
// the loop will be exited based on results from NetInit()
|
|
if (! gbRunGameResult) break;
|
|
}
|
|
|
|
TRACE_FCN("SNetDestroy");
|
|
SNetDestroy();
|
|
TRACE_FCN(NULL);
|
|
|
|
return gbRunGameResult;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void InitOnce() {
|
|
MouseX = TOTALX >> 1;
|
|
MouseY = TOTALY >> 1;
|
|
|
|
ScrollInfo._sdx = 0;
|
|
ScrollInfo._sdy = 0;
|
|
ScrollInfo._sxoff = 0;
|
|
ScrollInfo._syoff = 0;
|
|
ScrollInfo._sdir = SCRL_NONE;
|
|
for (int i = 0; i < 1024; i++)
|
|
nBuffWTbl[i] = i * BUFFERX;
|
|
|
|
// Init engine vars
|
|
ClrDiabloMsg();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
/* pjw.patch2.start
|
|
static const char sgszErrFile[] = "c:\\helfire_.err";
|
|
static void write_exception(struct _EXCEPTION_POINTERS *pep) {
|
|
FILE * f = fopen(sgszErrFile,"wb");
|
|
if (! f) return;
|
|
|
|
PEXCEPTION_RECORD per = pep->ExceptionRecord;
|
|
while (per) {
|
|
fprintf(
|
|
f,
|
|
"exception: 0x%08x\r\ncode address: 0x%08x\r\n",
|
|
per->ExceptionCode,
|
|
per->ExceptionAddress
|
|
);
|
|
|
|
if (per->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
|
|
if (per->ExceptionInformation[0])
|
|
fprintf(f,"write access violation at 0x%08x\r\n",per->ExceptionInformation[1]);
|
|
else
|
|
fprintf(f,"read access violation at 0x%08x\r\n",per->ExceptionInformation[1]);
|
|
}
|
|
|
|
per = per->ExceptionRecord;
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
pjw.patch2.end */
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// pjw.patch2.start
|
|
void cleanup(BOOL bNormalExit);
|
|
static LPTOP_LEVEL_EXCEPTION_FILTER sg_previousFilter;
|
|
static LONG WINAPI DiabloUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *pep) {
|
|
void free_directx();
|
|
free_directx();
|
|
cleanup(FALSE);
|
|
// write_exception(pep);
|
|
if (sg_previousFilter) return sg_previousFilter(pep);
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
// pjw.patch2.end
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
BOOL grab_event() {
|
|
// NOTE: this event never gets cleaned up by our code
|
|
// we rely upon windows to clean up this event so that it
|
|
// occurs as late as possible in the program exit. This is
|
|
// a really nasty hack to make sure that SMACKER doesn't
|
|
// initialize improperly
|
|
SetLastError(0);
|
|
HANDLE hExtraEvent = CreateEvent(NULL,FALSE,FALSE,"DiabloEvent");
|
|
HANDLE hEvent = CreateEvent(NULL,FALSE,FALSE,"HellfireEvent");
|
|
return ERROR_ALREADY_EXISTS != GetLastError();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static BOOL ActivatePreviousInstance(const char * pszAppClass) {
|
|
// find main application window
|
|
HWND hWnd;
|
|
HWND hWndTop;
|
|
HWND hWndPopup;
|
|
|
|
// get parent window
|
|
if (NULL == (hWnd = FindWindow(pszAppClass,NULL)))
|
|
return FALSE;
|
|
|
|
// get popup window (if any)
|
|
if (NULL != (hWndPopup = GetLastActivePopup(hWnd)))
|
|
hWnd = hWndPopup;
|
|
|
|
// get topmost control window of topmost window
|
|
hWndTop = GetTopWindow(hWnd);
|
|
if (! hWndTop) hWndTop = hWnd;
|
|
|
|
// bring to the front
|
|
SetForegroundWindow(hWnd);
|
|
SetFocus(hWndTop);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
typedef struct _SHAREDDATA {
|
|
LONG status;
|
|
DWORD processid;
|
|
} SHAREDDATA, *SHAREDDATAPTR;
|
|
|
|
|
|
//===========================================================================
|
|
// pjw.patch2.start
|
|
#ifdef NDEBUG
|
|
static void inline ReloadSelf (HINSTANCE instance) {
|
|
|
|
// GET THE MODULE FILENAME
|
|
char filename[MAX_PATH] = "";
|
|
GetModuleFileName((HMODULE)instance,filename,MAX_PATH);
|
|
|
|
|
|
// OPEN NAMED SHARED MEMORY
|
|
char name[MAX_PATH+16];
|
|
wsprintf(name,"Reload-%s",filename);
|
|
for (LPSTR curr = name; *curr; ++curr)
|
|
if (*curr == '\\')
|
|
*curr = '/';
|
|
SYSTEM_INFO sysinfo;
|
|
GetSystemInfo(&sysinfo);
|
|
DWORD bytes = max(4096,sysinfo.dwPageSize);
|
|
|
|
|
|
HANDLE map = CreateFileMapping((HANDLE)0xFFFFFFFF,
|
|
NULL,
|
|
PAGE_READWRITE | SEC_COMMIT,
|
|
0,
|
|
bytes,
|
|
name);
|
|
BOOL first = (GetLastError() != ERROR_ALREADY_EXISTS);
|
|
if (!map)
|
|
return;
|
|
|
|
// Open secondary named shared memory to fool Diablo into not autorunning
|
|
char tmpname[MAX_PATH+16];
|
|
strcpy(tmpname,"Reload-Diablo");
|
|
HANDLE tmpmap = CreateFileMapping((HANDLE)0xFFFFFFFF,
|
|
NULL,
|
|
PAGE_READWRITE | SEC_COMMIT,
|
|
0,
|
|
bytes,
|
|
tmpname);
|
|
// end of hack
|
|
|
|
LPVOID view = MapViewOfFile(map,FILE_MAP_ALL_ACCESS,0,0,bytes);
|
|
if (!view)
|
|
return;
|
|
SHAREDDATAPTR ptr = (SHAREDDATAPTR)view;
|
|
|
|
// IF WE ARE THE FIRST INSTANCE, THEN RELOAD OURSELVES, WAIT FOR THE
|
|
// SECOND INSTANCE TO INITIALIZE, THEN QUIT
|
|
if (first) {
|
|
ptr->status = -1;
|
|
ptr->processid = 0;
|
|
STARTUPINFO startupinfo;
|
|
ZeroMemory(&startupinfo,sizeof(STARTUPINFO));
|
|
startupinfo.cb = sizeof(STARTUPINFO);
|
|
PROCESS_INFORMATION processinfo;
|
|
CreateProcess(filename,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_NEW_PROCESS_GROUP,
|
|
NULL,
|
|
NULL,
|
|
&startupinfo,
|
|
&processinfo);
|
|
WaitForInputIdle(processinfo.hProcess,INFINITE);
|
|
CloseHandle(processinfo.hThread);
|
|
CloseHandle(processinfo.hProcess);
|
|
while (ptr->status < 0)
|
|
Sleep(1000);
|
|
UnmapViewOfFile(view);
|
|
CloseHandle(map);
|
|
ExitProcess(0);
|
|
}
|
|
|
|
// OTHERWISE, ALLOW ONE INSTANCE TO RUN, AND MAKE ANY ADDITIONAL
|
|
// INSTANCES JUST REACTIVATE THE RUNNING INSTANCE
|
|
if (!InterlockedIncrement(&ptr->status))
|
|
ptr->processid = GetCurrentProcessId();
|
|
else {
|
|
HWND window = GetForegroundWindow();
|
|
HWND prev;
|
|
while ((prev = GetNextWindow(window,GW_HWNDPREV)) != (HWND)0)
|
|
window = prev;
|
|
do {
|
|
DWORD processid;
|
|
GetWindowThreadProcessId(window,&processid);
|
|
if (processid == ptr->processid) {
|
|
SetForegroundWindow(window);
|
|
break;
|
|
}
|
|
} while ((window = GetNextWindow(window,GW_HWNDNEXT)) != (HWND)0);
|
|
UnmapViewOfFile(view);
|
|
CloseHandle(map);
|
|
ExitProcess(0);
|
|
}
|
|
}
|
|
#endif
|
|
// pjw.patch2.end
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow){
|
|
// pjw.patch2.start
|
|
#ifdef NDEBUG
|
|
ReloadSelf(hInstance);
|
|
#endif
|
|
// pjw.patch2.end
|
|
|
|
MonoDevice::Printf("Command line: %s", lpCmdLine);
|
|
ghInst = hInstance;
|
|
ShowCursor(FALSE);
|
|
// pjw.patch1.start
|
|
srand(GetTickCount());
|
|
InitializeHashSource();
|
|
alloc_plr();
|
|
// pjw.patch1.end
|
|
|
|
// delete any previous error file created by exception
|
|
// handler and then install exception handler
|
|
// pjw.patch2.start
|
|
// DeleteFile(sgszErrFile);
|
|
sg_previousFilter = SetUnhandledExceptionFilter(DiabloUnhandledExceptionFilter);
|
|
// pjw.patch2.end
|
|
|
|
// if another instance of Diablo is already running,
|
|
// then activate it and exit this instance
|
|
BOOL bGotEvent = grab_event();
|
|
if (ActivatePreviousInstance("DIABLO")) // conflict with parent is bad
|
|
return FALSE;
|
|
if (ActivatePreviousInstance(gszAppName))
|
|
return FALSE;
|
|
if (!bGotEvent) return FALSE;
|
|
|
|
|
|
#ifndef NDEBUG
|
|
SFileEnableDirectAccess(1);
|
|
#endif
|
|
|
|
InitOnce();
|
|
char cpCmdLine[255];
|
|
if (!lpCmdLine[0]) {
|
|
cpCmdLine[0] = 0;
|
|
FILE * const fp = fopen("command.txt","r");
|
|
if (fp) {
|
|
fgets(cpCmdLine, sizeof(cpCmdLine)/sizeof(char), fp);
|
|
lpCmdLine = cpCmdLine;
|
|
fclose(fp);
|
|
}
|
|
}
|
|
CommandLine(lpCmdLine);
|
|
init_window(nCmdShow);
|
|
|
|
menusnd_init();
|
|
UiInitialize();
|
|
|
|
#if IS_VERSION(SHAREWARE)
|
|
UiSetSpawned(TRUE);
|
|
#endif
|
|
|
|
|
|
// play logo
|
|
#ifndef NDEBUG
|
|
if (cineflag) play_movie("gendata\\logo.smk",TRUE);
|
|
#else
|
|
play_movie("gendata\\logo.smk",TRUE);
|
|
#endif
|
|
|
|
// play magazine quotes
|
|
/*
|
|
#if IS_VERSION(SHAREWARE)
|
|
#ifndef NDEBUG
|
|
if (cineflag) play_quotes();
|
|
#else
|
|
play_quotes();
|
|
#endif
|
|
#endif
|
|
*/
|
|
|
|
// play main intro
|
|
#if !IS_VERSION(SHAREWARE)
|
|
const char sgszMovie[] = "Intro";
|
|
DWORD dwPlayMovie;
|
|
if (! SRegLoadValue(gszProgKey,sgszMovie,0,&dwPlayMovie))
|
|
dwPlayMovie = 1;
|
|
//if (dwPlayMovie)
|
|
play_movie("gendata\\Hellfire.smk",TRUE);
|
|
SRegSaveValue(gszProgKey,sgszMovie,0,0);
|
|
#endif
|
|
|
|
|
|
// play title screen
|
|
#ifndef NDEBUG
|
|
if (cineflag) {
|
|
#endif
|
|
UiTitleDialog(7); // DKT this needs to change to ours
|
|
BlackPalette();
|
|
#ifndef NDEBUG
|
|
}
|
|
#endif
|
|
|
|
// play beta warning
|
|
#if IS_VERSION(BETA)
|
|
#ifndef NDEBUG
|
|
if (cineflag) {
|
|
#endif
|
|
UiBetaDisclaimer(5);
|
|
BlackPalette();
|
|
#ifndef NDEBUG
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
// main game menu (finally)
|
|
DiabloMenu();
|
|
|
|
// play "buy me" screens
|
|
/*
|
|
#if IS_VERSION(SHAREWARE)
|
|
#ifndef NDEBUG
|
|
if (cineflag) play_quit();
|
|
#else
|
|
play_quit();
|
|
#endif
|
|
#endif
|
|
*/
|
|
|
|
UiDestroy();
|
|
SavePaletteSettings();
|
|
|
|
if (ghMainWnd) {
|
|
// sleep before we destroy window so
|
|
// that SFX have time to finish before exit
|
|
Sleep(300);
|
|
DestroyWindow(ghMainWnd);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
**-----------------------------------------------------------------------*/
|
|
static BOOL CheckPlrLBtn(BOOL ShiftDown) {
|
|
BOOL adjacent;
|
|
|
|
app_assert(MouseY < 352);
|
|
if (leveltype == 0) {
|
|
//
|
|
// Town Level
|
|
//
|
|
ShiftDown = FALSE; // no attacking in town
|
|
if ((cursitem != -1) && (curs == GLOVE_CURS))
|
|
NetSendCmdLocParam1(TRUE,invflag ? CMD_GOTOGETITEM : CMD_GOTOAGETITEM,cursmx,cursmy,cursitem);
|
|
if (cursmonst != -1)
|
|
NetSendCmdLocParam1(TRUE,CMD_TALKXY,cursmx,cursmy,cursmonst);
|
|
if ((cursitem == -1) && (cursmonst == -1) && (cursplr == -1))
|
|
return TRUE;
|
|
}
|
|
else {
|
|
//
|
|
// NOT Town Level
|
|
//
|
|
adjacent = abs(plr[myplr]._px - cursmx) < 2
|
|
&& abs(plr[myplr]._py - cursmy) < 2;
|
|
if ((cursitem != -1) && (curs == GLOVE_CURS) && !ShiftDown)
|
|
NetSendCmdLocParam1(TRUE,invflag ? CMD_GOTOGETITEM : CMD_GOTOAGETITEM,cursmx,cursmy,cursitem);
|
|
else if ((cursobj != -1)
|
|
&& (!ShiftDown // allow barrel busting even with shift key down
|
|
|| (adjacent && object[cursobj]._oBreak == OBJ_BREAKABLE)))
|
|
NetSendCmdLocParam1(TRUE,(curs == DISARM_CURS) ? CMD_DISARMXY : CMD_OPOBJXY,cursmx,cursmy,cursobj);
|
|
|
|
else if (plr[myplr]._pwtype == WEAP_RANGE) {
|
|
if (ShiftDown)
|
|
NetSendCmdLoc(TRUE,CMD_RATTACKXY, cursmx, cursmy);
|
|
else if (cursmonst != -1) {
|
|
if (CanTalkToMonst(cursmonst))
|
|
// walk over to monster to talk to him
|
|
NetSendCmdParam1(TRUE,CMD_ATTACKID,cursmonst);
|
|
else
|
|
// Attack
|
|
NetSendCmdParam1(TRUE,CMD_RATTACKID,cursmonst);
|
|
} else if (cursplr != -1 && !FriendlyMode)
|
|
NetSendCmdParam1(TRUE,CMD_RATTACKPID, cursplr);
|
|
}
|
|
|
|
else { // pwtype == WEAP_H2H
|
|
if (ShiftDown) {
|
|
if (cursmonst != -1) {
|
|
if (CanTalkToMonst(cursmonst))
|
|
NetSendCmdParam1(TRUE,CMD_ATTACKID,cursmonst);
|
|
else
|
|
NetSendCmdLoc(TRUE,CMD_SATTACKXY, cursmx, cursmy);
|
|
} else
|
|
NetSendCmdLoc(TRUE,CMD_SATTACKXY, cursmx, cursmy);
|
|
}
|
|
else if (cursmonst != -1)
|
|
NetSendCmdParam1(TRUE,CMD_ATTACKID,cursmonst);
|
|
else if (cursplr != -1 && !FriendlyMode)
|
|
NetSendCmdParam1(TRUE,CMD_ATTACKPID,cursplr);
|
|
}
|
|
|
|
if ((!ShiftDown) && (cursitem == -1) && (cursobj == -1) && (cursmonst == -1) && (cursplr == -1))
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
** Game message processing
|
|
**-----------------------------------------------------------------------*/
|
|
static BOOL TryIconCurs() {
|
|
if (curs == RESURRECT_CURS) {
|
|
NetSendCmdParam1(TRUE,CMD_RESURRECT, cursplr);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (curs == HEALOTHER_CURS) {
|
|
NetSendCmdParam1(TRUE,CMD_HEALOTHER, cursplr);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (curs == TELE_CURS) {
|
|
DoTelekinesis();
|
|
return(TRUE);
|
|
}
|
|
if (curs == IDENTIFY_CURS) {
|
|
if (cursinvitem != -1)
|
|
CheckIdentify(myplr, cursinvitem);
|
|
else
|
|
NewCursor(GLOVE_CURS);
|
|
return(TRUE);
|
|
}
|
|
if (curs == REPAIR_CURS) {
|
|
if (cursinvitem != -1)
|
|
DoRepair(myplr, cursinvitem);
|
|
else
|
|
NewCursor(GLOVE_CURS);
|
|
return(TRUE);
|
|
}
|
|
if (curs == RECHARGE_CURS) {
|
|
if (cursinvitem != -1)
|
|
DoRecharge(myplr, cursinvitem);
|
|
else
|
|
NewCursor(GLOVE_CURS);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (curs == OIL_CURS) {
|
|
if (cursinvitem != -1)
|
|
DoOil(myplr, cursinvitem);
|
|
else
|
|
NewCursor(GLOVE_CURS);
|
|
return(TRUE);
|
|
}
|
|
|
|
if (curs == TARGET_CURS) {
|
|
if (cursmonst != -1)
|
|
NetSendCmdParam3(TRUE,CMD_TSPELLID,cursmonst,plr[myplr]._pTSpell, GetSpellLevel(myplr, plr[myplr]._pTSpell));
|
|
else if (cursplr != -1)
|
|
NetSendCmdParam3(TRUE,CMD_TSPELLPID,cursplr,plr[myplr]._pTSpell,GetSpellLevel(myplr, plr[myplr]._pTSpell));
|
|
else
|
|
NetSendCmdLocParam2(TRUE,CMD_TSPELLXY,cursmx,cursmy,plr[myplr]._pTSpell,GetSpellLevel(myplr, plr[myplr]._pTSpell));
|
|
NewCursor(GLOVE_CURS);
|
|
return(TRUE);
|
|
}
|
|
if ((curs == DISARM_CURS) && (cursobj == -1)) {
|
|
NewCursor(GLOVE_CURS);
|
|
return(TRUE);
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static BOOL wm_lbuttondown(WPARAM wParam) {
|
|
if (gmenu_click(TRUE))
|
|
return FALSE;
|
|
|
|
BOOL talk_click();
|
|
if (talk_click())
|
|
return FALSE;
|
|
|
|
// don't accept input in timeout mode
|
|
if (sgnTimeoutCurs != NO_CURSOR)
|
|
return FALSE;
|
|
|
|
if (deathflag) {
|
|
CheckDeadButtons();
|
|
return FALSE;
|
|
}
|
|
|
|
if (PauseMode == 2)
|
|
return FALSE;
|
|
|
|
if (drawmapofdoom) {
|
|
EndMapOfDoomView();
|
|
return FALSE;
|
|
}
|
|
|
|
if (spselflag) {
|
|
SetSpell();
|
|
return FALSE;
|
|
}
|
|
|
|
if (stextflag != STORE_NONE) {
|
|
CheckStoreBtn();
|
|
return FALSE;
|
|
}
|
|
|
|
if (MouseY < 352) {
|
|
if (gmenu_is_on())
|
|
return FALSE;
|
|
|
|
if (TryIconCurs())
|
|
return FALSE;
|
|
|
|
if (questlog) {
|
|
if ((MouseX > 32) && (MouseX < 288) && (MouseY > 32) && (MouseY < 308)) {
|
|
CheckQLogBtn();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (qtextflag) {
|
|
qtextflag = FALSE;
|
|
stream_stop();
|
|
return FALSE;
|
|
}
|
|
|
|
if ((chrflag) && (MouseX < 320)) {
|
|
CheckChrBtns();
|
|
return FALSE;
|
|
}
|
|
else if ((invflag) && (MouseX > 320)) {
|
|
if (!dropGoldFlag) CheckInvScrn();
|
|
return FALSE;
|
|
}
|
|
else if ((sbookflag) && (MouseX > 320)) {
|
|
CheckSBook();
|
|
return FALSE;
|
|
}
|
|
else if (curs >= ICSTART) {
|
|
if (TryInvPut()) {
|
|
NetSendCmdPItem(TRUE,CMD_PUTITEM,cursmx,cursmy);
|
|
NewCursor(GLOVE_CURS);
|
|
}
|
|
return FALSE;
|
|
}
|
|
else {
|
|
if ((plr[myplr]._pStatPts != 0) && (!spselflag))
|
|
CheckLvlBtn();
|
|
if (!lvlbtndown)
|
|
return CheckPlrLBtn(wParam == (MK_LBUTTON | MK_SHIFT));
|
|
}
|
|
}
|
|
else {
|
|
if (!talkflag && !dropGoldFlag && !gmenu_is_on())
|
|
CheckSpdBar();
|
|
CheckPanelBtns();
|
|
if ((curs > GLOVE_CURS) && (curs < ICSTART))
|
|
NewCursor(GLOVE_CURS);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void wm_lbuttonup() {
|
|
gmenu_click(FALSE);
|
|
void talk_release();
|
|
talk_release();
|
|
if (panbtndown) ReleasePanelBtn();
|
|
if (chrbtndown) ReleaseChrBtn();
|
|
if (lvlbtndown) ReleaseLvlBtn();
|
|
if (stextflag != STORE_NONE) ReleaseStoreBtn();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void wm_rbuttondown() {
|
|
|
|
// don't allow input while the menu is active
|
|
if (gmenu_is_on()) return;
|
|
|
|
// don't accept input in timeout mode
|
|
if (sgnTimeoutCurs != NO_CURSOR)
|
|
return;
|
|
|
|
if (PauseMode == 2) return;
|
|
|
|
if (plr[myplr]._pInvincible) return;
|
|
|
|
if (drawmapofdoom) {
|
|
EndMapOfDoomView();
|
|
return;
|
|
}
|
|
|
|
if (stextflag != STORE_NONE) return;
|
|
|
|
if (spselflag) {
|
|
SetSpell();
|
|
return;
|
|
}
|
|
// if (sbookflag && CheckSBookCast())
|
|
// return;
|
|
if (sbookflag && MouseX > 320) return;
|
|
|
|
if (MouseY < 352) {
|
|
if (TryIconCurs())
|
|
return;
|
|
if (cursinvitem != -1 && UseInvItem(myplr, cursinvitem))
|
|
return;
|
|
}
|
|
if (curs == GLOVE_CURS) {
|
|
if (cursinvitem != -1 && UseInvItem(myplr, cursinvitem))
|
|
return;
|
|
// else if (cursitem != -1 && (wParam & WM_SHIFT))
|
|
// UseGroundItem(cursitem);
|
|
else
|
|
CheckPlrSpell();
|
|
}
|
|
else if ((curs > GLOVE_CURS) && (curs < ICSTART)) NewCursor(GLOVE_CURS);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void wm_mousemove() {
|
|
// check for menu sliders
|
|
if (gmenu_mousemove()) return;
|
|
|
|
// don't accept input in timeout mode
|
|
if (sgnTimeoutCurs != NO_CURSOR) return;
|
|
|
|
// do game mousemove here
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void TogglePause() {
|
|
// no pause in multiplayer
|
|
if (gbMaxPlayers > 1) return;
|
|
|
|
if (PauseMode) {
|
|
PauseMode = 0;
|
|
}
|
|
else {
|
|
PauseMode = 2;
|
|
sound_stop();
|
|
TrackInit(FALSE);
|
|
}
|
|
force_redraw = FULLDRAW;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void SendTaunt(DWORD dwMsg) {
|
|
// don't send taunts in single player mode
|
|
if (gbMaxPlayers == 1) return;
|
|
|
|
// get program directory
|
|
char szPath[MAX_PATH];
|
|
if (! GetModuleFileName(ghInst,szPath,MAX_PATH))
|
|
app_fatal("Can't get program name");
|
|
char * pszName = strrchr(szPath,'\\');
|
|
if (pszName) *pszName = 0;
|
|
strcat(szPath,"\\hellfire.ini");
|
|
|
|
static const char * spszMsgTbl[] = {
|
|
"I need help! Heal me!",
|
|
"Go through that door first.",
|
|
"Give me some gold please.",
|
|
"Look out behind you!",
|
|
};
|
|
static const char * spszKeyTbl[] = {
|
|
"F9","F10","F11","F12"
|
|
};
|
|
|
|
char szBuf[MAX_SEND_STR_LEN];
|
|
app_assert(dwMsg < sizeof(spszMsgTbl) / sizeof(spszMsgTbl[0]));
|
|
GetPrivateProfileString(
|
|
"NetMsg", // section name
|
|
spszKeyTbl[dwMsg], // key name
|
|
spszMsgTbl[dwMsg], // default string
|
|
szBuf, // dest buffer
|
|
sizeof(szBuf) / sizeof(szBuf[0]),
|
|
szPath
|
|
);
|
|
|
|
// send message to other players
|
|
NetSendString(SEND_ALL_MASK,szBuf);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static BOOL wm_syskeydown(WPARAM wKey) {
|
|
// don't allow input while the menu is active
|
|
if (gmenu_is_on())
|
|
return FALSE;
|
|
|
|
// note: this identical code is in the keydown case also, but
|
|
// F10 seems to come through as a system key sometimes...
|
|
if (wKey == VK_F10) {
|
|
SendTaunt(1);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void wm_keyup(WPARAM wKey) {
|
|
// can't ever get keydown for snapshot, but we do get keyup
|
|
if (wKey == VK_SNAPSHOT)
|
|
screen_capture();
|
|
|
|
// if any more cases are added here, then make sure menu is not active
|
|
// if (gmenu_is_on()) return;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
BOOL clear_windows() {
|
|
BOOL bResult = FALSE;
|
|
|
|
if (drawmapofdoom) {
|
|
EndMapOfDoomView();
|
|
bResult = TRUE;
|
|
}
|
|
if (helpflag) {
|
|
helpflag = FALSE;
|
|
bResult = TRUE;
|
|
}
|
|
if (qtextflag) {
|
|
qtextflag = FALSE;
|
|
stream_stop();
|
|
#if CHEATS
|
|
if ((currlevel == 0) && (davecheat)) {
|
|
tstQMsgFlag = FALSE;
|
|
tstQMsgIndexFlag = TRUE;
|
|
}
|
|
#endif
|
|
bResult = TRUE;
|
|
} else
|
|
if (stextflag) {
|
|
STextESC();
|
|
bResult = TRUE;
|
|
}
|
|
if (msgflag) {
|
|
msgdelay = 0;
|
|
bResult = TRUE;
|
|
}
|
|
if (talkflag) {
|
|
TalkEnd();
|
|
bResult = TRUE;
|
|
}
|
|
if (dropGoldFlag) {
|
|
DropGoldType(VK_ESCAPE);
|
|
bResult = TRUE;
|
|
}
|
|
if (spselflag) {
|
|
spselflag = FALSE;
|
|
bResult = TRUE;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void wm_keydown(WPARAM wKey) {
|
|
// allow use of menu even when character is dead
|
|
if (gmenu_key(wKey))
|
|
return;
|
|
|
|
// allow user to finish current string even in timeout mode
|
|
if (Talk_wm_keydown(wKey))
|
|
return;
|
|
|
|
// don't allow dead player to do anything except turn on gamemenu
|
|
if (deathflag) {
|
|
// no input while in timeout mode
|
|
if (sgnTimeoutCurs != NO_CURSOR) return;
|
|
if (wKey == VK_F9) SendTaunt(0);
|
|
if (wKey == VK_F10) SendTaunt(1);
|
|
if (wKey == VK_F11) SendTaunt(2);
|
|
if (wKey == VK_F12) SendTaunt(3);
|
|
if (wKey == VK_RETURN) TalkStart();
|
|
if (wKey != VK_ESCAPE) return;
|
|
}
|
|
|
|
if (wKey == VK_ESCAPE) {
|
|
if (! clear_windows()) {
|
|
TrackInit(FALSE);
|
|
gamemenu_on();
|
|
}
|
|
#if CHEATS
|
|
if ((currlevel == 0) && (davecheat) &&
|
|
((tstQMsgFlag) || (tstQMsgIndexFlag))) {
|
|
tstQMsgFlag = FALSE;
|
|
tstQMsgIndexFlag = FALSE;
|
|
sprintf(tempstr, "STOP QUEST TEXT MODE");
|
|
NetSendString((1 << myplr), tempstr);
|
|
return;
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// don't accept input in timeout mode
|
|
if (sgnTimeoutCurs != NO_CURSOR)
|
|
return;
|
|
|
|
// Don't accept input when in drop gold mode
|
|
if (dropGoldFlag)
|
|
return;
|
|
|
|
// in pause mode the only thing we can do is unpause
|
|
if (wKey == VK_PAUSE) {
|
|
TogglePause();
|
|
return;
|
|
}
|
|
if (PauseMode == 2) return;
|
|
|
|
if (wKey == VK_RETURN) {
|
|
if (stextflag) STextEnter();
|
|
else if (questlog) QuestlogEnter();
|
|
#if CHEATS
|
|
else if ((currlevel == 0) && (davecheat)) {
|
|
if (tstQMsgIndexFlag) {
|
|
tstQMsgIndexFlag = FALSE;
|
|
tstQMsgFlag = TRUE;
|
|
tstQMsgSpd = 5;
|
|
DaveQuestText();
|
|
sprintf(tempstr, "Message Speed = %i", tstQMsgSpd);
|
|
NetSendString((1 << myplr), tempstr);
|
|
} else if (tstQMsgFlag) {
|
|
sprintf(tempstr, "[ MESSAGE = %i ]", tstQMsgIndex);
|
|
NetSendString((1 << myplr), tempstr);
|
|
sprintf(tempstr, "[ MESSAGE SPEED = %i ]", tstQMsgSpd);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
}
|
|
#endif
|
|
else TalkStart();
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_F1) {
|
|
if (helpflag) {
|
|
helpflag = FALSE;
|
|
}
|
|
else if (stextflag != STORE_NONE) {
|
|
ClearPanel();
|
|
AddPanelString("No help available", TEXT_CENTER);
|
|
AddPanelString("while in stores", TEXT_CENTER);
|
|
TrackInit(FALSE);
|
|
}
|
|
else {
|
|
invflag = FALSE;
|
|
chrflag = FALSE;
|
|
sbookflag = FALSE;
|
|
spselflag = FALSE;
|
|
if ((qtextflag) && (leveltype == 0)) {
|
|
qtextflag = FALSE;
|
|
stream_stop();
|
|
}
|
|
questlog = FALSE;
|
|
automapflag = FALSE;
|
|
msgdelay = 0;
|
|
gamemenu_off();
|
|
StartHelp();
|
|
EndMapOfDoomView();
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if CHEATS
|
|
if (wKey == VK_F2) {
|
|
void PrintDaveCheck2();
|
|
PrintDaveCheck2();
|
|
}
|
|
|
|
/* if (wKey == VK_F3) {
|
|
extern BOOL syncdebug;
|
|
syncdebug = !syncdebug;
|
|
if (syncdebug)
|
|
strcpy(tempstr, "Item drop debug on");
|
|
else
|
|
strcpy(tempstr, "Item drop debug off");
|
|
NetSendString((1 << myplr), tempstr);
|
|
}*/
|
|
if (wKey == VK_F3) {
|
|
if (cursitem != -1) {
|
|
sprintf(tempstr, "IDX = %i : Seed = %i : CF = %i", item[cursitem].IDidx, item[cursitem]._iSeed, item[cursitem]._iCreateInfo);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
sprintf(tempstr, "Numitems : %i", numitems);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
|
|
if (wKey == VK_F4) {
|
|
void PrintQuestDebug();
|
|
PrintQuestDebug();
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* #if CHEATS
|
|
if (wKey == VK_F4) {
|
|
if (cheatflag) toggle_frame_counter();
|
|
return;
|
|
}
|
|
#endif*/
|
|
|
|
if (wKey == VK_F5) {
|
|
if (spselflag) SetSpellHK(0);
|
|
else GetSpellHK(0);
|
|
return;
|
|
}
|
|
if (wKey == VK_F6) {
|
|
if (spselflag) SetSpellHK(1);
|
|
else GetSpellHK(1);
|
|
return;
|
|
}
|
|
if (wKey == VK_F7) {
|
|
if (spselflag) SetSpellHK(2);
|
|
else GetSpellHK(2);
|
|
return;
|
|
}
|
|
if (wKey == VK_F8) {
|
|
if (spselflag) SetSpellHK(3);
|
|
else GetSpellHK(3);
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_F9) {
|
|
SendTaunt(0);
|
|
return;
|
|
}
|
|
if (wKey == VK_F10) {
|
|
SendTaunt(1);
|
|
return;
|
|
}
|
|
if (wKey == VK_F11) {
|
|
SendTaunt(2);
|
|
return;
|
|
}
|
|
if (wKey == VK_F12) {
|
|
SendTaunt(3);
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_UP) {
|
|
if (stextflag) STextUp();
|
|
else if (questlog) QuestlogUp();
|
|
else if (helpflag) HelpScrollUp();
|
|
else if (automapflag) AutomapUp();
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_DOWN) {
|
|
if (stextflag) STextDown();
|
|
else if (questlog) QuestlogDown();
|
|
else if (helpflag) HelpScrollDown();
|
|
else if (automapflag) AutomapDown();
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_PRIOR) {
|
|
if (stextflag) STextPgUp();
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_NEXT) {
|
|
if (stextflag) STextPgDown();
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_LEFT) {
|
|
if (automapflag && !talkflag) AutomapLeft();
|
|
return;
|
|
}
|
|
if (wKey == VK_RIGHT) {
|
|
if (automapflag && !talkflag) AutomapRight();
|
|
return;
|
|
}
|
|
|
|
if (wKey == VK_TAB) {
|
|
void DoAutoMap();
|
|
DoAutoMap();
|
|
return;
|
|
}
|
|
|
|
/* if (wKey == VK_CAPITAL) {
|
|
FriendlyMode = !FriendlyMode;
|
|
drawbtnflag = TRUE;
|
|
return;
|
|
}*/
|
|
|
|
if (wKey == 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 = FALSE;
|
|
invflag = FALSE;
|
|
chrflag = FALSE;
|
|
sbookflag = FALSE;
|
|
spselflag = FALSE;
|
|
if ((qtextflag) && (leveltype == 0)) {
|
|
qtextflag = FALSE;
|
|
stream_stop();
|
|
}
|
|
questlog = FALSE;
|
|
automapflag = FALSE;
|
|
msgdelay = 0;
|
|
gamemenu_off();
|
|
EndMapOfDoomView();
|
|
//Never clear the cursor, else we lose a scroll or a staff charge
|
|
//for a spell we've cast.
|
|
// if ((curs != GLOVE_CURS) && (curs < ICSTART)) NewCursor(GLOVE_CURS);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void wm_char(WPARAM wKey) {
|
|
#ifdef _DEBUG
|
|
BOOL is_pat_debug_cmd(WPARAM wKey);
|
|
if (is_pat_debug_cmd(wKey))
|
|
return;
|
|
#endif
|
|
|
|
// don't allow input while the menu is active
|
|
if (gmenu_is_on())
|
|
return;
|
|
|
|
if (Talk_wm_char(wKey))
|
|
return;
|
|
|
|
// don't accept input in timeout mode
|
|
if (sgnTimeoutCurs != NO_CURSOR)
|
|
return;
|
|
|
|
// dead players can't perform input
|
|
if (deathflag)
|
|
return;
|
|
|
|
// in pause mode the only thing we can do is unpause
|
|
if ((TCHAR) wKey == 'p' || (TCHAR) wKey == 'P') {
|
|
TogglePause();
|
|
return;
|
|
}
|
|
if (PauseMode == 2) return;
|
|
|
|
if (drawmapofdoom) {
|
|
EndMapOfDoomView();
|
|
return;
|
|
}
|
|
|
|
if (dropGoldFlag) {
|
|
DropGoldType((char) wKey);
|
|
return;
|
|
}
|
|
|
|
switch(wKey) {
|
|
case 'g':
|
|
case 'G':
|
|
GammaDown();
|
|
return;
|
|
|
|
case 'f':
|
|
case 'F':
|
|
GammaUp();
|
|
return;
|
|
|
|
case 'i':
|
|
case 'I':
|
|
if (stextflag != STORE_NONE) return;
|
|
sbookflag = FALSE;
|
|
invflag = !invflag;
|
|
if (dropGoldFlag) {
|
|
dropGoldFlag = FALSE;
|
|
dropGoldValue = 0;
|
|
}
|
|
if (invflag && !chrflag) {
|
|
if (MouseX > 160 && MouseY < 352) SetCursorPos(MouseX-160,MouseY);
|
|
}
|
|
else {
|
|
if (MouseX < 480 && MouseY < 352) SetCursorPos(MouseX+160, MouseY);
|
|
}
|
|
return;
|
|
|
|
case 'c':
|
|
case 'C':
|
|
if (stextflag != STORE_NONE) return;
|
|
questlog = FALSE;
|
|
chrflag = !chrflag;
|
|
if (chrflag && !invflag) {
|
|
if (MouseX < 480 && MouseY < 352) SetCursorPos(MouseX+160,MouseY);
|
|
}
|
|
else {
|
|
if (MouseX > 160 && MouseY < 352) SetCursorPos(MouseX-160, MouseY);
|
|
}
|
|
return;
|
|
|
|
#ifndef NDEBUG
|
|
case 'r':
|
|
case 'R':
|
|
sprintf(tempstr, "seed = %i", glSeedTbl[currlevel]);
|
|
NetSendString((1 << myplr), tempstr);
|
|
sprintf(tempstr, "Mid1 = %i : Mid2 = %i : Mid3 = %i",
|
|
glMid1Seed[currlevel], glMid2Seed[currlevel], glMid3Seed[currlevel]);
|
|
NetSendString((1 << myplr), tempstr);
|
|
sprintf(tempstr, "End = %i", glEndSeed[currlevel]);
|
|
NetSendString((1 << myplr), tempstr);
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'A':
|
|
if (cheatflag) {
|
|
sprintf(tempstr, "Mid: %i", dMonster[cursmx][cursmy] - 1);
|
|
NetSendString((1 << myplr), tempstr);
|
|
if (dMonster[cursmx][cursmy] > 0) {
|
|
monster[(dMonster[cursmx][cursmy] - 1)]._mFlags |= MFLAG_MKILLER;
|
|
void M_Enemy(int);
|
|
M_Enemy((dMonster[cursmx][cursmy] - 1));
|
|
}
|
|
}
|
|
return;
|
|
case 'a':
|
|
if (cheatflag) {
|
|
plr[myplr]._pSplLvl[(plr[myplr]._pSpell)]++;
|
|
spelldata[SPL_TELE].sTownSpell = TRUE;
|
|
}
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case ')':
|
|
case '0':
|
|
if (cheatflag) {
|
|
if (gv1 > 2) gv1 = 0;
|
|
if (gv1 == 0) {
|
|
plr[myplr]._pIFlags &= ~IAF_FIREARROW;
|
|
plr[myplr]._pIFlags &= ~IAF_LARROW;
|
|
}
|
|
if (gv1 == 1) plr[myplr]._pIFlags |= IAF_FIREARROW;
|
|
if (gv1 == 2) plr[myplr]._pIFlags |= IAF_LARROW;
|
|
gv1++;
|
|
}
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'l':
|
|
case 'L':
|
|
if (cheatflag) ToggleLight();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 't':
|
|
case 'T':
|
|
if (cheatflag) {
|
|
sprintf(tempstr, "PX = %i PY = %i", plr[myplr]._px, plr[myplr]._py);
|
|
NetSendString((1 << myplr), tempstr);
|
|
sprintf(tempstr, "CX = %i CY = %i DP = %i", cursmx, cursmy, dungeon[cursmx][cursmy]);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
return;
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
case 'D':
|
|
void BlipDebug(BOOL);
|
|
BlipDebug(TRUE);
|
|
return;
|
|
case 'd':
|
|
BlipDebug(FALSE);
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case 'e':
|
|
if (davedebug) {
|
|
sprintf(tempstr, "EFlag = %i", plr[myplr]._peflag);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
return;
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
case 'm':
|
|
void DaveDebugMonst();
|
|
DaveDebugMonst();
|
|
return;
|
|
case 'M':
|
|
void DaveDebugMonst2();
|
|
DaveDebugMonst2();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case '|':
|
|
if ((currlevel == 0) && (davecheat)) DaveGold();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case '~':
|
|
if ((currlevel == 0) && (davecheat)) DaveNewPremium();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case '[':
|
|
if ((currlevel == 0) && (davecheat)) DaveCleanUp();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case ']':
|
|
if ((currlevel == 0) && (davecheat)) DaveSpells();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case ':':
|
|
if ((currlevel == 0) && (davecheat)) DaveSpells2();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case '.':
|
|
void DaveDungDebug();
|
|
DaveDungDebug();
|
|
return;
|
|
#endif
|
|
|
|
#if CHEATS
|
|
case '?':
|
|
if ((currlevel == 0) && (davecheat)) {
|
|
tstQMsgFlag = FALSE;
|
|
tstQMsgIndexFlag = TRUE;
|
|
sprintf(tempstr, "START QUEST TEXT MODE");
|
|
NetSendString((1 << myplr), tempstr);
|
|
sprintf(tempstr, "Message = %i", tstQMsgIndex);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
return;
|
|
#endif
|
|
|
|
case 'q':
|
|
case 'Q':
|
|
if (stextflag != STORE_NONE) return;
|
|
chrflag = FALSE;
|
|
if (!questlog) StartQuestlog();
|
|
else questlog = FALSE;
|
|
return;
|
|
|
|
case 'z':
|
|
case 'Z':
|
|
svgamode = !svgamode;
|
|
return;
|
|
|
|
case 's':
|
|
case 'S':
|
|
if (stextflag != STORE_NONE) return;
|
|
invflag = FALSE;
|
|
if (!spselflag) SetupSpellSel();
|
|
else spselflag = FALSE;
|
|
TrackInit(FALSE);
|
|
return;
|
|
|
|
case 'b':
|
|
case 'B':
|
|
if (stextflag != STORE_NONE) return;
|
|
invflag = FALSE;
|
|
if (dropGoldFlag) {
|
|
dropGoldFlag = FALSE;
|
|
dropGoldValue = 0;
|
|
}
|
|
sbookflag = !sbookflag;
|
|
return;
|
|
|
|
case '+':
|
|
case '=':
|
|
if (automapflag) AutomapZoomIn();
|
|
#if CHEATS
|
|
else if ((currlevel == 0) && (davecheat)) {
|
|
if (tstQMsgIndexFlag) {
|
|
tstQMsgIndex++;
|
|
if (tstQMsgIndex > (int)(gdwAllTextEntries-1)) tstQMsgIndex = 0;
|
|
sprintf(tempstr, "Message = %i", tstQMsgIndex);
|
|
NetSendString((1 << myplr), tempstr);
|
|
} else if (tstQMsgFlag) {
|
|
tstQMsgSpd++;
|
|
if (tstQMsgSpd > 9) tstQMsgSpd = 9;
|
|
qtextSpd = qtextDelaySpd[tstQMsgSpd-1];
|
|
qtextflag = FALSE;
|
|
stream_stop();
|
|
DaveQuestText();
|
|
sprintf(tempstr, "Message Speed = %i", tstQMsgSpd);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
}
|
|
#endif
|
|
return;
|
|
|
|
case '_':
|
|
case '-':
|
|
if (automapflag) AutomapZoomOut();
|
|
#if CHEATS
|
|
else if ((currlevel == 0) && (davecheat)) {
|
|
if (tstQMsgIndexFlag) {
|
|
tstQMsgIndex--;
|
|
if (tstQMsgIndex < 0) tstQMsgIndex = (int)(gdwAllTextEntries-1);
|
|
sprintf(tempstr, "Message = %i", tstQMsgIndex);
|
|
NetSendString((1 << myplr), tempstr);
|
|
} else if (tstQMsgFlag){
|
|
tstQMsgSpd--;
|
|
if (tstQMsgSpd < 1) tstQMsgSpd = 1;
|
|
qtextSpd = qtextDelaySpd[tstQMsgSpd-1];
|
|
qtextflag = FALSE;
|
|
stream_stop();
|
|
DaveQuestText();
|
|
sprintf(tempstr, "Message Speed = %i", tstQMsgSpd);
|
|
NetSendString((1 << myplr), tempstr);
|
|
}
|
|
}
|
|
#endif
|
|
return;
|
|
|
|
case 'v':
|
|
extern char gszPrintVersion[];
|
|
{
|
|
char *pszaDif[] = {"Normal", "Nightmare", "Hell"};
|
|
char tmpbuf[120];
|
|
sprintf(tmpbuf, "%s, mode = %s", gszPrintVersion,
|
|
pszaDif[gnDifficulty]);
|
|
NetSendString((1 << myplr), tmpbuf);
|
|
}
|
|
// NetSendString((1 << myplr), gszPrintVersion);
|
|
break;
|
|
|
|
case 'V':
|
|
extern char gszVersionNumber[];
|
|
NetSendString((1 << myplr), gszVersionNumber);
|
|
return;
|
|
|
|
case '!':
|
|
case '1':
|
|
if ((plr[myplr].SpdList[0]._itype != -1) &&
|
|
(plr[myplr].SpdList[0]._itype != IT_GOLD)) UseInvItem(myplr, 47);
|
|
return;
|
|
|
|
case '@':
|
|
case '2':
|
|
if ((plr[myplr].SpdList[1]._itype != -1) &&
|
|
(plr[myplr].SpdList[1]._itype != IT_GOLD)) UseInvItem(myplr, 48);
|
|
return;
|
|
|
|
case '#':
|
|
case '3':
|
|
if ((plr[myplr].SpdList[2]._itype != -1) &&
|
|
(plr[myplr].SpdList[2]._itype != IT_GOLD)) UseInvItem(myplr, 49);
|
|
return;
|
|
|
|
case '$':
|
|
case '4':
|
|
if ((plr[myplr].SpdList[3]._itype != -1) &&
|
|
(plr[myplr].SpdList[3]._itype != IT_GOLD)) UseInvItem(myplr, 50);
|
|
return;
|
|
|
|
case '%':
|
|
case '5':
|
|
if ((plr[myplr].SpdList[4]._itype != -1) &&
|
|
(plr[myplr].SpdList[4]._itype != IT_GOLD)) UseInvItem(myplr, 51);
|
|
return;
|
|
|
|
case '^':
|
|
case '6':
|
|
if ((plr[myplr].SpdList[5]._itype != -1) &&
|
|
(plr[myplr].SpdList[5]._itype != IT_GOLD)) UseInvItem(myplr, 52);
|
|
return;
|
|
|
|
case '&':
|
|
case '7':
|
|
if ((plr[myplr].SpdList[6]._itype != -1) &&
|
|
(plr[myplr].SpdList[6]._itype != IT_GOLD)) UseInvItem(myplr, 53);
|
|
return;
|
|
|
|
case '*':
|
|
case '8':
|
|
#if CHEATS
|
|
if (cheatflag || davecheat) {
|
|
NetSendCmd(TRUE,CMD_CHEAT_EXPERIENCE);
|
|
return;
|
|
}
|
|
#endif
|
|
if ((plr[myplr].SpdList[7]._itype != -1) &&
|
|
(plr[myplr].SpdList[7]._itype != IT_GOLD)) UseInvItem(myplr, 54);
|
|
return;
|
|
/*
|
|
// testing diablo death
|
|
case 'k':
|
|
#define MT_DIABLO 110
|
|
for (int i = 0; i < nummonsters; i++) {
|
|
int mi = monstactive[i];
|
|
if (monster[mi].MType->mtype == MT_DIABLO)
|
|
M_StartKill(mi, myplr);
|
|
}
|
|
return;
|
|
*/
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
LRESULT CALLBACK DisableInputWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) {
|
|
switch (uMsg) {
|
|
// don't let input go to game window proc
|
|
case WM_SYSKEYDOWN:
|
|
case WM_SYSCOMMAND:
|
|
case WM_KEYUP:
|
|
case WM_KEYDOWN:
|
|
case WM_CHAR:
|
|
case WM_MOUSEMOVE:
|
|
return 0;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
if (sgbMouseDown) return 0;
|
|
sgbMouseDown = LMOUSE_DOWN;
|
|
SetCapture(hWnd);
|
|
return 0;
|
|
|
|
case WM_LBUTTONUP:
|
|
if (sgbMouseDown != LMOUSE_DOWN) return 0;
|
|
sgbMouseDown = 0;
|
|
ReleaseCapture();
|
|
return 0;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
if (sgbMouseDown) return 0;
|
|
sgbMouseDown = RMOUSE_DOWN;
|
|
SetCapture(hWnd);
|
|
return 0;
|
|
|
|
case WM_RBUTTONUP:
|
|
if (sgbMouseDown != RMOUSE_DOWN) return 0;
|
|
sgbMouseDown = 0;
|
|
ReleaseCapture();
|
|
return 0;
|
|
|
|
case WM_CAPTURECHANGED:
|
|
if (hWnd != (HWND) lParam)
|
|
sgbMouseDown = 0;
|
|
return 0;
|
|
}
|
|
|
|
return DiabloDefProc(hWnd,uMsg,wParam,lParam);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static LRESULT CALLBACK GM_Game(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam) {
|
|
switch (uMsg) {
|
|
case WM_SYSKEYDOWN:
|
|
if (wm_syskeydown(wParam)) return 0;
|
|
break;
|
|
|
|
case WM_KEYUP:
|
|
wm_keyup(wParam);
|
|
return 0;
|
|
|
|
case WM_KEYDOWN:
|
|
wm_keydown(wParam);
|
|
return 0;
|
|
|
|
case WM_CHAR:
|
|
wm_char(wParam);
|
|
return 0;
|
|
|
|
case WM_MOUSEMOVE:
|
|
MouseX = LOWORD(lParam);
|
|
MouseY = HIWORD(lParam);
|
|
wm_mousemove();
|
|
return 0;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
MouseX = LOWORD(lParam);
|
|
MouseY = HIWORD(lParam);
|
|
|
|
// if the mouse is already down, wait for mouse up
|
|
if (sgbMouseDown) return 0;
|
|
sgbMouseDown = LMOUSE_DOWN;
|
|
SetCapture(hWnd);
|
|
|
|
TrackInit(wm_lbuttondown(wParam));
|
|
return 0;
|
|
|
|
case WM_LBUTTONUP:
|
|
MouseX = LOWORD(lParam);
|
|
MouseY = HIWORD(lParam);
|
|
|
|
// don't accept mouse up unless it went down in our window
|
|
if (sgbMouseDown != LMOUSE_DOWN) return 0;
|
|
sgbMouseDown = 0;
|
|
|
|
wm_lbuttonup();
|
|
TrackInit(FALSE);
|
|
ReleaseCapture();
|
|
return 0;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
MouseX = LOWORD(lParam);
|
|
MouseY = HIWORD(lParam);
|
|
|
|
// if the mouse is already down, wait for mouse up
|
|
if (sgbMouseDown) return 0;
|
|
sgbMouseDown = RMOUSE_DOWN;
|
|
SetCapture(hWnd);
|
|
|
|
wm_rbuttondown();
|
|
return 0;
|
|
|
|
case WM_RBUTTONUP:
|
|
MouseX = LOWORD(lParam);
|
|
MouseY = HIWORD(lParam);
|
|
|
|
// don't accept mouse up unless it went down in our window
|
|
if (sgbMouseDown != RMOUSE_DOWN) return 0;
|
|
sgbMouseDown = 0;
|
|
ReleaseCapture();
|
|
return 0;
|
|
|
|
case WM_CAPTURECHANGED:
|
|
if (hWnd != (HWND) lParam) {
|
|
sgbMouseDown = 0;
|
|
TrackInit(FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_DIABNEXTLVL:
|
|
case WM_DIABPREVLVL:
|
|
case WM_DIABSETLVL:
|
|
case WM_DIABRTNLVL:
|
|
case WM_DIABWARPLVL:
|
|
case WM_DIABTOWNWARP:
|
|
case WM_DIABTWARPUP:
|
|
case WM_DIABRETOWN:
|
|
// save character in multiplayer mode
|
|
if (gbMaxPlayers > 1) {
|
|
void UpdatePlayerFile();
|
|
UpdatePlayerFile();
|
|
}
|
|
nthread_perform_keepalive(TRUE);
|
|
PaletteFadeOut(FADE_FAST);
|
|
sound_stop();
|
|
music_stop();
|
|
TrackInit(FALSE);
|
|
sgbMouseDown = FALSE;
|
|
ReleaseCapture();
|
|
ShowProgress(uMsg);
|
|
force_redraw = FULLDRAW;
|
|
DrawAndBlit();
|
|
if (gbRunGame) PaletteFadeIn(FADE_FAST);
|
|
nthread_perform_keepalive(FALSE);
|
|
gbGameLoopStartup = TRUE;
|
|
return 0;
|
|
|
|
case WM_SYSCOMMAND:
|
|
if (wParam == SC_CLOSE) {
|
|
gbRunGame = FALSE;
|
|
gbRunGameResult = FALSE;
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return DiabloDefProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
**-----------------------------------------------------------------------*/
|
|
void LoadLvlGFX() {
|
|
app_assert(! pDungeonCels);
|
|
switch (leveltype) {
|
|
case 0:
|
|
pDungeonCels = LoadFileInMemSig("NLevels\\TownData\\Town.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("NLevels\\TownData\\Town.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("NLevels\\TownData\\Town.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("Levels\\TownData\\TownS.CEL",NULL,'TILE');
|
|
break;
|
|
|
|
case 1:
|
|
/* pDungeonCels = LoadFileInMemSig("Levels\\L1Data\\L1.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("Levels\\L1Data\\L1.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("Levels\\L1Data\\L1.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("Levels\\L1Data\\L1S.CEL",NULL,'TILE');
|
|
break;*/
|
|
if (currlevel < CRYPTSTART)
|
|
{
|
|
pDungeonCels = LoadFileInMemSig("Levels\\L1Data\\L1.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("Levels\\L1Data\\L1.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("Levels\\L1Data\\L1.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("Levels\\L1Data\\L1S.CEL",NULL,'TILE');
|
|
}
|
|
else
|
|
{
|
|
pDungeonCels = LoadFileInMemSig("NLevels\\L5Data\\L5.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("NLevels\\L5Data\\L5.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("NLevels\\L5Data\\L5.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("NLevels\\L5Data\\L5S.CEL",NULL,'TILE');
|
|
}
|
|
break;
|
|
|
|
#if IS_VERSION(RETAIL) || IS_VERSION(BETA)
|
|
case 2:
|
|
pDungeonCels = LoadFileInMemSig("Levels\\L2Data\\L2.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("Levels\\L2Data\\L2.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("Levels\\L2Data\\L2.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("Levels\\L2Data\\L2S.CEL",NULL,'TILE');
|
|
break;
|
|
#endif
|
|
|
|
#if IS_VERSION(RETAIL)
|
|
case 3:
|
|
if (currlevel < HIVESTART)
|
|
{
|
|
pDungeonCels = LoadFileInMemSig("Levels\\L3Data\\L3.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("Levels\\L3Data\\L3.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("Levels\\L3Data\\L3.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("Levels\\L1Data\\L1S.CEL",NULL,'TILE');
|
|
}
|
|
else
|
|
{
|
|
pDungeonCels = LoadFileInMemSig("NLevels\\L6Data\\L6.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("NLevels\\L6Data\\L6.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("NLevels\\L6Data\\L6.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("Levels\\L1Data\\L1S.CEL",NULL,'TILE');
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#if IS_VERSION(RETAIL)
|
|
case 4:
|
|
pDungeonCels = LoadFileInMemSig("Levels\\L4Data\\L4.CEL",NULL,'TILE');
|
|
pMegaTiles = LoadFileInMemSig("Levels\\L4Data\\L4.TIL",NULL,'TILE');
|
|
pMiniTiles = LoadFileInMemSig("Levels\\L4Data\\L4.MIN",NULL,'TILE');
|
|
pSpecialCels = LoadFileInMemSig("Levels\\L2Data\\L2S.CEL",NULL,'TILE');
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
app_fatal("LoadLvlGFX");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
**-----------------------------------------------------------------------*/
|
|
|
|
void LoadAllGFX()
|
|
{
|
|
app_assert(! pSpeedCels);
|
|
pSpeedCels = DiabloAllocPtrSig(SPEEDSIZE,'SPED');
|
|
// InitMonsterGFX();
|
|
IntCheck();
|
|
// InitMonsterSND();
|
|
IntCheck();
|
|
InitObjectGFX();
|
|
IntCheck();
|
|
InitMissileGFX();
|
|
IntCheck();
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
**-----------------------------------------------------------------------*/
|
|
|
|
void CreateLevel(int lvldir)
|
|
{
|
|
switch (leveltype) {
|
|
case 0:
|
|
CreateTown(lvldir);
|
|
InitTownTriggers();
|
|
LoadRndLvlPal(0);
|
|
break;
|
|
|
|
case 1:
|
|
CreateL5Dungeon(glSeedTbl[currlevel], lvldir);
|
|
InitL1Triggers();
|
|
Freeupstairs();
|
|
if (currlevel < CRYPTSTART) // JKE load correct pallet
|
|
LoadRndLvlPal(1);
|
|
else
|
|
LoadRndLvlPal(5);
|
|
break;
|
|
|
|
#if IS_VERSION(RETAIL) || IS_VERSION(BETA)
|
|
case 2:
|
|
CreateL2Dungeon(glSeedTbl[currlevel], lvldir);
|
|
InitL2Triggers();
|
|
Freeupstairs();
|
|
LoadRndLvlPal(2);
|
|
break;
|
|
#endif
|
|
|
|
#if IS_VERSION(RETAIL)
|
|
case 3:
|
|
CreateL3Dungeon(glSeedTbl[currlevel], lvldir);
|
|
InitL3Triggers();
|
|
Freeupstairs();
|
|
if (currlevel < HIVESTART)
|
|
LoadRndLvlPal(3);
|
|
else
|
|
LoadRndLvlPal(6);
|
|
break;
|
|
#endif
|
|
|
|
#if IS_VERSION(RETAIL)
|
|
case 4:
|
|
CreateL4Dungeon(glSeedTbl[currlevel], lvldir);
|
|
InitL4Triggers();
|
|
Freeupstairs();
|
|
LoadRndLvlPal(4);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
app_fatal("CreateLevel");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------**
|
|
**-----------------------------------------------------------------------*/
|
|
|
|
void LoadGameLevel(BOOL firstflag, int lvldir)
|
|
{
|
|
int i,j;
|
|
|
|
if (setseed)
|
|
glSeedTbl[currlevel] = setseed;
|
|
|
|
music_stop();
|
|
SetCursor(GLOVE_CURS);
|
|
SetRndSeed(glSeedTbl[currlevel]);
|
|
IntCheck();
|
|
|
|
MakeLightTable();
|
|
LoadLvlGFX();
|
|
IntCheck();
|
|
|
|
if (firstflag) {
|
|
InitInv();
|
|
InitItemGFX();
|
|
InitQuestText();
|
|
for (i = 0; i < gbMaxPlayers; i++)
|
|
InitPlrGFXMem(i);
|
|
InitStores();
|
|
InitAutomapOnce();
|
|
InitHelpSys();
|
|
}
|
|
|
|
SetRndSeed(glSeedTbl[currlevel]);
|
|
if (leveltype == 0) SetupTownStores();
|
|
IntCheck();
|
|
|
|
InitAutomap();
|
|
|
|
if ((leveltype != 0) && (lvldir != LVL_NODIR)) {
|
|
InitLighting();
|
|
InitVision();
|
|
}
|
|
InitLevelMonsters();
|
|
IntCheck();
|
|
|
|
if (!setlevel) {
|
|
CreateLevel(lvldir);
|
|
IntCheck();
|
|
|
|
// Open Tiles file
|
|
FillSolidBlockTbls();
|
|
|
|
SetRndSeed(glSeedTbl[currlevel]);
|
|
|
|
if (leveltype != 0) {
|
|
GetLevelMTypes();
|
|
InitThemes();
|
|
LoadAllGFX();
|
|
} else {
|
|
InitMissileGFX();
|
|
}
|
|
IntCheck();
|
|
|
|
if (lvldir == LVL_RTN) GetReturnLvlPos();
|
|
if (lvldir == LVL_WARP) GetPortalLvlPos();
|
|
IntCheck();
|
|
|
|
// Init Player info
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
if (! plr[i].plractive) continue;
|
|
if (currlevel != plr[i].plrlevel) continue;
|
|
InitPlayerGFX(i);
|
|
if (lvldir != LVL_NODIR) InitPlayer(i, firstflag);
|
|
}
|
|
|
|
PlayDungMsgs();
|
|
InitMultiView();
|
|
IntCheck();
|
|
|
|
BOOL visited = FALSE;
|
|
for (i = 0; i < gbMaxPlayers; i++)
|
|
if (plr[i].plractive) visited = visited || plr[i]._pLvlVisited[currlevel];
|
|
|
|
// Resync after level changing bug
|
|
// This bug occurs when 2 players change levels one after the other. The first player
|
|
// down thinks the other player is one level above, because the change level msg has
|
|
// not been processed during loading. The second player knows that they are both
|
|
// on the same level, so more players get inited, and randoms desync.
|
|
SetRndSeed(glSeedTbl[currlevel]);
|
|
|
|
if (leveltype != 0) {
|
|
if (!firstflag && (lvldir != LVL_NODIR) && plr[myplr]._pLvlVisited[currlevel] && (gbMaxPlayers == 1)) {
|
|
// Init monsters so uniques are loaded
|
|
InitMonsters ();
|
|
// Init missiles
|
|
InitMissiles();
|
|
// Init dead info, not dungeon layout though
|
|
InitDead();
|
|
IntCheck ();
|
|
// Load where things were
|
|
LoadLevel();
|
|
IntCheck ();
|
|
} else {
|
|
// Save theme room areas
|
|
HoldThemeRooms();
|
|
glMid1Seed[currlevel] = GetRndSeed(); // @@@ drb temp
|
|
// Init monsters into dungeon
|
|
// if (currlevel < HIVESTART) InitMonsters (); // temp hack to test failure JKE
|
|
InitMonsters ();
|
|
glMid2Seed[currlevel] = GetRndSeed(); // @@@ drb temp
|
|
// Init objects
|
|
// if (currlevel < CRYPTSTART) InitObjects(); // temp hack to test failure JKE
|
|
InitObjects();
|
|
// Init items
|
|
// if (currlevel < HIVESTART) InitItems(); // Temp hack to test failure JKE
|
|
InitItems();
|
|
// Fill theme rooms
|
|
if (currlevel < HIVESTART) CreateThemeRooms(); // Temp hack for failure JKE
|
|
// CreateThemeRooms();
|
|
glMid3Seed[currlevel] = GetRndSeed(); // @@@ drb temp
|
|
// Init missiles
|
|
InitMissiles();
|
|
// Init dead info, not dungeon layout though
|
|
InitDead();
|
|
glEndSeed[currlevel] = GetRndSeed(); // @@@ drb temp
|
|
// if multiplayer resync level
|
|
if (gbMaxPlayers != 1) DeltaLoadLevel();
|
|
IntCheck();
|
|
SavePreLighting();
|
|
}
|
|
} else {
|
|
// Make everything visible
|
|
for (i = 0; i < DMAXX; i++)
|
|
for (j = 0; j < DMAXY; j++)
|
|
dFlags[i][j] |= BFLAG_VISIBLE;
|
|
// Init town people
|
|
InitTowners();
|
|
// Init items
|
|
InitItems();
|
|
// Init missiles
|
|
InitMissiles();
|
|
IntCheck();
|
|
|
|
// Load items
|
|
if (!firstflag && (lvldir != LVL_NODIR) && plr[myplr]._pLvlVisited[currlevel] && (gbMaxPlayers == 1))
|
|
LoadLevel();
|
|
if (gbMaxPlayers != 1) DeltaLoadLevel();
|
|
IntCheck ();
|
|
}
|
|
if (gbMaxPlayers == 1)
|
|
ResyncQuests();
|
|
else
|
|
ResyncMPQuests();
|
|
|
|
}
|
|
#if !IS_VERSION(SHAREWARE)
|
|
else {
|
|
// Preset levels
|
|
app_assert(! pSpeedCels);
|
|
pSpeedCels = DiabloAllocPtrSig(SPEEDSIZE,'SPED');
|
|
|
|
LoadSetMap();
|
|
IntCheck();
|
|
|
|
GetLevelMTypes();
|
|
|
|
InitMonsters();
|
|
|
|
//SetDungeonMicros();
|
|
|
|
InitMissileGFX();
|
|
|
|
// Init dead info, not dungeon layout though
|
|
InitDead();
|
|
|
|
// Open Tiles file
|
|
FillSolidBlockTbls ();
|
|
IntCheck();
|
|
|
|
if (lvldir == LVL_WARP) GetPortalLvlPos();
|
|
|
|
// Init Player info
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
if (! plr[i].plractive) continue;
|
|
if (currlevel != plr[i].plrlevel) continue;
|
|
InitPlayerGFX(i);
|
|
if (lvldir != LVL_NODIR) InitPlayer(i, firstflag);
|
|
}
|
|
|
|
InitMultiView();
|
|
IntCheck();
|
|
|
|
if ((!firstflag) && (lvldir != LVL_NODIR) && (plr[myplr]._pSLvlVisited[setlvlnum])) {
|
|
// Load where things were
|
|
LoadLevel();
|
|
} else {
|
|
// Init items
|
|
InitItems();
|
|
SavePreLighting();
|
|
}
|
|
// Init missiles
|
|
InitMissiles();
|
|
IntCheck();
|
|
}
|
|
#endif
|
|
|
|
SyncPortals();
|
|
|
|
for (i = 0; i < MAX_PLRS; i++) {
|
|
if (! plr[i].plractive) continue;
|
|
if (plr[i].plrlevel != currlevel) continue;
|
|
if (plr[i]._pLvlChanging && (i != myplr)) continue;
|
|
if (plr[i]._pHitPoints > 0) {
|
|
if (gbMaxPlayers == 1)
|
|
dPlayer[plr[i]._px][plr[i]._py] = i + 1;
|
|
else
|
|
SyncInitPlrPos(i);
|
|
} else
|
|
dFlags[plr[i]._px][plr[i]._py] |= BFLAG_DEADPLR;
|
|
}
|
|
|
|
if (leveltype != 0) {
|
|
SetDungeonMicros();
|
|
}
|
|
|
|
InitLightMax(); // Set up 4 or 16 level lighting
|
|
IntCheck();
|
|
|
|
/*
|
|
if ((leveltype != 0) && (lvldir != LVL_NODIR)) {
|
|
SavePreLighting();
|
|
}
|
|
*/
|
|
IntCheck();
|
|
|
|
if (firstflag) {
|
|
// Get Control panel graphics and decompress panel to BtmBuff
|
|
// Has to be after init player because of bars/spells/equipment etc.
|
|
InitControlPan();
|
|
IntCheck();
|
|
}
|
|
|
|
if (leveltype != 0) {
|
|
ProcessLightList();
|
|
ProcessVisionList();
|
|
}
|
|
if (currlevel >= CRYPTSTART)
|
|
{
|
|
// OpenCloseAllDoors(); // JKE Stupid!!!
|
|
if (currlevel == CORNERSTONE_LEVEL)
|
|
CornerstoneRestore(CornerStone.x, CornerStone.y);
|
|
if ((quests[Q_NA_KRUL]._qactive == QUEST_DONE)&&(currlevel == NA_KRUL_LEVEL))
|
|
OpenNaKrul();
|
|
|
|
}
|
|
|
|
// start appropriate sound track
|
|
if (currlevel >= HIVESTART) // fix this later JKE
|
|
{
|
|
music_start((currlevel > HIVEEND)? 5 : 6);
|
|
}
|
|
else
|
|
music_start(leveltype);
|
|
|
|
// finish progress bar
|
|
while (! IntCheck())
|
|
NULL;
|
|
|
|
#if !IS_VERSION(SHAREWARE)
|
|
if ((setlevel) && (setlvlnum == SL_SKELKING) && (quests[Q_SKELKING]._qactive == QUEST_NOTDONE))
|
|
PlaySFX(USFX_SKING1);
|
|
#endif
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// this parameter is the maximum number of game loops which can be run
|
|
// in a row without redrawing the screen
|
|
#define MAX_CONSECUTIVE_LOOPS 3
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void game_logic() {
|
|
if (PauseMode == 2) return;
|
|
if (PauseMode == 1) PauseMode = 2;
|
|
|
|
// pause when menu is active in single player mode
|
|
if (gbMaxPlayers == 1 && gmenu_is_on()) {
|
|
force_redraw |= VIEWDRAW;
|
|
return;
|
|
}
|
|
|
|
if (! gmenu_is_on() && (sgnTimeoutCurs == NO_CURSOR)) {
|
|
CheckCursMove();
|
|
TrackMouse();
|
|
}
|
|
|
|
if (gbProcessPlayers)
|
|
ProcessPlayers();
|
|
if (leveltype) {
|
|
ProcessMonsters();
|
|
ProcessObjects();
|
|
ProcessMissiles();
|
|
ProcessItems();
|
|
ProcessLightList();
|
|
ProcessVisionList();
|
|
}
|
|
else {
|
|
ProcessTowners();
|
|
ProcessItems();
|
|
ProcessMissiles();
|
|
}
|
|
|
|
#if CHEATS
|
|
if ((cheatflag) && ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0))
|
|
CheckForScroll();
|
|
#endif
|
|
|
|
sound_update();
|
|
plrmsg_update();
|
|
CheckTriggers();
|
|
CheckQuests();
|
|
force_redraw |= VIEWDRAW;
|
|
|
|
void TimedUpdatePlayerFile(BOOL bForce);
|
|
TimedUpdatePlayerFile(FALSE);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void timeout_cursor(BOOL bTimeout) {
|
|
if (bTimeout) {
|
|
// if we weren't in a timeout state, set timeout
|
|
if (sgnTimeoutCurs == NO_CURSOR && ! sgbMouseDown) {
|
|
sgnTimeoutCurs = curs;
|
|
|
|
NetStartTimeout();
|
|
|
|
// display timeout error
|
|
ClearPanel();
|
|
AddPanelString("-- Network timeout --", TEXT_CENTER);
|
|
AddPanelString("-- Waiting for players --", TEXT_CENTER);
|
|
|
|
// fix up the cursor
|
|
NewCursor(TIMEOUT_CURSOR);
|
|
|
|
// we probably made a mess of the screen
|
|
force_redraw = FULLDRAW;
|
|
}
|
|
|
|
FullBlit(TRUE);
|
|
}
|
|
else if (sgnTimeoutCurs != NO_CURSOR) {
|
|
// ending timeout
|
|
SetCursor(sgnTimeoutCurs);
|
|
sgnTimeoutCurs = NO_CURSOR;
|
|
ClearPanel();
|
|
force_redraw = FULLDRAW;
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void game_loop(BOOL bStartup) {
|
|
int nMaxLoops = bStartup ? GAME_FRAMES_PER_SECOND * 3 : MAX_CONSECUTIVE_LOOPS;
|
|
while (nMaxLoops--) {
|
|
// wait for synchronous network message
|
|
if (! NetEndSendCycle()) {
|
|
timeout_cursor(TRUE);
|
|
break;
|
|
}
|
|
timeout_cursor(FALSE);
|
|
|
|
// run logic at GAME_FRAMES_PER_SECOND
|
|
game_logic();
|
|
|
|
// if the game mode changed, then don't continue loop
|
|
if (! gbRunGame)
|
|
break;
|
|
|
|
// don't run multiple loops in single player mode
|
|
if (gbMaxPlayers == 1)
|
|
break;
|
|
|
|
// have we been in the loop too long?
|
|
if (! nthread_run_gameloop(TRUE))
|
|
break;
|
|
|
|
#if CHEATS
|
|
static DWORD sdwSkips = 0;
|
|
sdwSkips++;
|
|
HDC hDC;
|
|
HRESULT ddr = lpDDSPrimary->GetDC(&hDC);
|
|
if (ddr == DD_OK) {
|
|
char szBuf[16];
|
|
wsprintf(szBuf,"%u",sdwSkips);
|
|
TextOut(hDC,5,370,szBuf,strlen(szBuf));
|
|
lpDDSPrimary->ReleaseDC(hDC);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void DoTimedEvents() {
|
|
static DWORD sdwCurrTime = 0;
|
|
DWORD dwCurrTime = GetTickCount();
|
|
if (dwCurrTime - sdwCurrTime < 1000/GAME_FRAMES_PER_SECOND)
|
|
return;
|
|
sdwCurrTime = dwCurrTime;
|
|
|
|
if (leveltype == 4)
|
|
BloodCycle();
|
|
else if (currlevel >= CRYPTSTART)
|
|
TwinCycleCrypt();
|
|
else if (currlevel >= HIVESTART)
|
|
TwinCycleNest();
|
|
else if (leveltype == 3 && fullscreen)
|
|
LavaCycle();
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
/* pjw.patch1.start
|
|
static void try_game_loop(BOOL bStartup) {
|
|
DoTimedEvents();
|
|
NetReceivePackets();
|
|
|
|
if (! nthread_run_gameloop(FALSE))
|
|
return;
|
|
|
|
// run game loop
|
|
game_loop(bStartup);
|
|
|
|
// redraw the screen if necessary
|
|
DrawAndBlit();
|
|
}
|
|
pjw.patch1.end */
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// pjw.patch1.start
|
|
#define RAND_MASK (32*1024-1)
|
|
#define PLR_BYTES (sizeof(PlayerStruct) * MAX_PLRS)
|
|
static PlayerStruct * alloc_plr_chunk(PlayerStruct * p1) {
|
|
|
|
// make sure p2 ends up in different locations
|
|
LPVOID pTemp = malloc(rand() & RAND_MASK);
|
|
PlayerStruct * p2 = (PlayerStruct *) malloc(PLR_BYTES);
|
|
if (pTemp) free(pTemp);
|
|
|
|
if (! p2) return p1;
|
|
if (p1) {
|
|
CopyMemory(p2,p1,PLR_BYTES);
|
|
free(p1);
|
|
}
|
|
return p2;
|
|
}
|
|
// pjw.patch1.end
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// pjw.patch1.start
|
|
static void alloc_plr() {
|
|
if (NULL == (plr = alloc_plr_chunk(NULL)))
|
|
app_fatal("Unable to initialize memory");
|
|
ZeroMemory(plr,PLR_BYTES);
|
|
}
|
|
// pjw.patch1.end
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// pjw.patch1.start
|
|
#pragma intrinsic(_rotl)
|
|
static DWORD calc_checksum(LPVOID lpMem,DWORD dwBytes,DWORD dwSum) {
|
|
LPDWORD lpDW = (LPDWORD) lpMem;
|
|
dwBytes /= sizeof(DWORD);
|
|
while (dwBytes--) {
|
|
dwSum ^= *lpDW++;
|
|
dwSum = _rotl(dwSum,3);
|
|
}
|
|
return dwSum;
|
|
}
|
|
// pjw.patch1.end
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// pjw.patch1.start
|
|
static void CRASH() {
|
|
#if 0 // !!! @@@ !!! fix in final
|
|
static BYTE sgbCheating = FALSE;
|
|
if (! sgbCheating) {
|
|
sgbCheating = TRUE;
|
|
app_warning("Cheating detected");
|
|
void myDebugBreak();
|
|
myDebugBreak();
|
|
}
|
|
#else
|
|
LPDWORD pFrame = (LPDWORD) plr[myplr]._pAnimData;
|
|
pFrame[plr[myplr]._pAnimFrame + 1] ^= 0x3fffffff;
|
|
#endif
|
|
FullBlit(TRUE);
|
|
}
|
|
// pjw.patch1.end
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// pjw.patch1.start
|
|
typedef void (* TCrypt)(LPDWORD,DWORD,DWORD);
|
|
static void encrypt_aux(TCrypt fnCrypt) {
|
|
for (int i = 0; i < MAX_PLRS; i++) {
|
|
// SLOW encrypt the important part of the character
|
|
fnCrypt((LPDWORD)&plr[i],offsetof(PlayerStruct,_pGFXLoad),HASH_ENCRYPTKEY);
|
|
|
|
// FAST encrypt the inventory -- takes too long otherwise
|
|
LPDWORD lpInv = (LPDWORD) &plr[i].InvBody;
|
|
for (int j = sizeof(ItemStruct) * NUM_INVLOC / sizeof(DWORD); j--; )
|
|
*lpInv++ ^= 0xf0638142;
|
|
|
|
// pjw.patch2.start -- commented out -- still taking too long
|
|
#if 0
|
|
lpInv = (LPDWORD) &plr[i].InvList;
|
|
for (j = sizeof(ItemStruct) * MAXINV / sizeof(DWORD); j--; )
|
|
*lpInv++ ^= 0x23484862;
|
|
#endif
|
|
// pjw.patch2.end
|
|
}
|
|
}
|
|
// pjw.patch1.end
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
// pjw.patch1.start
|
|
static void plr_encrypt(BOOL bEncrypt) {
|
|
static BOOL sbEncrypt = FALSE;
|
|
static BOOL sbCrash = FALSE;
|
|
static DWORD sdwCheckSum = 0;
|
|
static DWORD sdwCheckStart = 0;
|
|
if (sbEncrypt == bEncrypt) return;
|
|
sbEncrypt = bEncrypt;
|
|
|
|
// pjw.patch2.start -- added for debugging only!
|
|
#if 0
|
|
static DWORD sgdwEncryptCount = 0;
|
|
sgdwEncryptCount++;
|
|
static DWORD sgdwLastTime = 0;
|
|
if (GetTickCount() - sgdwLastTime >= 1000) {
|
|
sgdwLastTime = GetTickCount();
|
|
do {
|
|
char szBuf[32];
|
|
HDC hDC;
|
|
HRESULT ddr = lpDDSPrimary->GetDC(&hDC);
|
|
if (ddr != DD_OK) break;
|
|
COLORREF oldTextColor = SetTextColor(hDC,RGB(0xff,0xff,0));
|
|
COLORREF oldBkColor = SetBkColor(hDC,RGB(0,0,0));
|
|
int oldBkMode = SetBkMode(hDC,OPAQUE);
|
|
sprintf(szBuf,"%u ",sgdwEncryptCount);
|
|
sgdwEncryptCount = 0;
|
|
TextOut(hDC,5,385,szBuf,strlen(szBuf));
|
|
SetTextColor(hDC,oldTextColor);
|
|
SetBkColor(hDC,oldBkColor);
|
|
SetBkMode(hDC,oldBkMode);
|
|
lpDDSPrimary->ReleaseDC(hDC);
|
|
} while (0);
|
|
}
|
|
#endif
|
|
// pjw.patch2.end
|
|
|
|
if (sbCrash) {
|
|
CRASH();
|
|
}
|
|
else if (bEncrypt) {
|
|
sdwCheckStart = rand();
|
|
sdwCheckSum = calc_checksum(plr,PLR_BYTES,sdwCheckStart);
|
|
encrypt_aux(Encrypt);
|
|
}
|
|
else {
|
|
encrypt_aux(Decrypt);
|
|
if (sdwCheckSum != calc_checksum(plr,PLR_BYTES,sdwCheckStart)) {
|
|
CRASH();
|
|
sbCrash = 1;
|
|
}
|
|
}
|
|
|
|
if ((rand() & 0x0f) == 0x0f)
|
|
plr = alloc_plr_chunk(plr);
|
|
}
|
|
// pjw.patch1.end
|