diff options
Diffstat (limited to 'src/hexen/h2_main.c')
-rw-r--r-- | src/hexen/h2_main.c | 863 |
1 files changed, 863 insertions, 0 deletions
diff --git a/src/hexen/h2_main.c b/src/hexen/h2_main.c new file mode 100644 index 00000000..abc58f15 --- /dev/null +++ b/src/hexen/h2_main.c @@ -0,0 +1,863 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 1993-2008 Raven Software +// Copyright(C) 2008 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +//----------------------------------------------------------------------------- + + +// HEADER FILES ------------------------------------------------------------ + +// haleyjd: removed WATCOMC +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#include "config.h" + +#include "h2def.h" +#include "ct_chat.h" +#include "d_iwad.h" +#include "d_mode.h" +#include "m_misc.h" +#include "s_sound.h" +#include "i_joystick.h" +#include "i_system.h" +#include "i_timer.h" +#include "m_argv.h" +#include "m_config.h" +#include "m_controls.h" +#include "p_local.h" +#include "v_video.h" +#include "w_main.h" + +// MACROS ------------------------------------------------------------------ + +#define MAXWADFILES 20 + +// TYPES ------------------------------------------------------------------- + +typedef struct +{ + char *name; + void (*func) (char **args, int tag); + int requiredArgs; + int tag; +} execOpt_t; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +void R_ExecuteSetViewSize(void); +void D_CheckNetGame(void); +void G_BuildTiccmd(ticcmd_t * cmd); +void F_Drawer(void); +boolean F_Responder(event_t * ev); +void I_StartupKeyboard(void); +void I_StartupJoystick(void); +void I_ShutdownKeyboard(void); +void S_InitScript(void); + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void H2_ProcessEvents(void); +void H2_DoAdvanceDemo(void); +void H2_AdvanceDemo(void); +void H2_StartTitle(void); +void H2_PageTicker(void); + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void DrawMessage(void); +static void PageDrawer(void); +static void HandleArgs(void); +static void CheckRecordFrom(void); +static void DrawAndBlit(void); +static void ExecOptionSCRIPTS(char **args, int tag); +static void ExecOptionSKILL(char **args, int tag); +static void ExecOptionPLAYDEMO(char **args, int tag); +static void CreateSavePath(void); +static void WarpCheck(void); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern boolean automapactive; +extern boolean MenuActive; +extern boolean askforquit; +extern char *SavePath; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +GameMode_t gamemode; +GameMission_t gamemission; +char *iwadfile; +boolean nomonsters; // checkparm of -nomonsters +boolean respawnparm; // checkparm of -respawn +boolean randomclass; // checkparm of -randclass +boolean debugmode; // checkparm of -debug +boolean ravpic; // checkparm of -ravpic +boolean cdrom = false; // true if cd-rom mode active +boolean cmdfrag; // true if a CMD_FRAG packet should be sent out +boolean singletics; // debug flag to cancel adaptiveness +boolean artiskip; // whether shift-enter skips an artifact +int maxzone = 0x800000; // Maximum allocated for zone heap (8meg default) +skill_t startskill; +int startepisode; +int startmap; +boolean autostart; +boolean advancedemo; +FILE *debugfile; +int UpdateState; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static int WarpMap; +static int demosequence; +static int pagetic; +static char *pagename; + +static execOpt_t ExecOptions[] = { + {"-scripts", ExecOptionSCRIPTS, 1, 0}, + {"-skill", ExecOptionSKILL, 1, 0}, + {"-playdemo", ExecOptionPLAYDEMO, 1, 0}, + {"-timedemo", ExecOptionPLAYDEMO, 1, 0}, + {NULL, NULL, 0, 0} // Terminator +}; + +// CODE -------------------------------------------------------------------- + +void D_BindVariables(void) +{ + int i; + + M_ApplyPlatformDefaults(); + + I_BindVideoVariables(); + I_BindJoystickVariables(); + I_BindSoundVariables(); + + M_BindBaseControls(); + M_BindMapControls(); + M_BindMenuControls(); + M_BindWeaponControls(); + M_BindChatControls(MAXPLAYERS); + M_BindHereticControls(); + M_BindHexenControls(); + + M_BindVariable("graphical_startup", &graphical_startup); + M_BindVariable("mouse_sensitivity", &mouseSensitivity); + M_BindVariable("sfx_volume", &snd_MaxVolume); + M_BindVariable("music_volume", &snd_MusicVolume); + M_BindVariable("messageson", &messageson); + M_BindVariable("screenblocks", &screenblocks); + M_BindVariable("snd_channels", &snd_Channels); + M_BindVariable("savedir", &SavePath); + + // Multiplayer chat macros + + for (i=0; i<10; ++i) + { + char buf[12]; + + sprintf(buf, "chatmacro%i", i); + M_BindVariable(buf, &chat_macros[i]); + } +} + +// Set the default directory where hub savegames are saved. + +static void D_SetDefaultSavePath(void) +{ + SavePath = malloc(strlen(configdir) + 10); + sprintf(SavePath, "%shexndata%c", configdir, DIR_SEPARATOR); +} + +// +// D_GrabMouseCallback +// +// Called to determine whether to grab the mouse pointer +// + +static boolean D_GrabMouseCallback(void) +{ + // when menu is active or game is paused, release the mouse + + if (MenuActive || paused) + return false; + + // only grab mouse when playing levels (but not demos) + + return (gamestate == GS_LEVEL) && !demoplayback; +} + +// Message displayed when quitting Hexen + +static void D_HexenQuitMessage(void) +{ + printf("\nHexen: Beyond Heretic\n"); +} + +static void D_AddFile(char *filename) +{ + printf(" adding %s\n", filename); + + W_AddFile(filename); +} + +//========================================================================== +// +// H2_Main +// +//========================================================================== +void InitMapMusicInfo(void); + +void D_DoomMain(void) +{ + int p; + + I_AtExit(D_HexenQuitMessage, false); + M_FindResponseFile(); + startepisode = 1; + autostart = false; + startskill = sk_medium; + startmap = 1; + gamemode = commercial; + + // Initialize subsystems + + ST_Message("V_Init: allocate screens.\n"); + V_Init(); + + // Load defaults before initing other systems + ST_Message("M_LoadDefaults: Load system defaults.\n"); + D_BindVariables(); + +#ifdef _WIN32 + + //! + // @platform windows + // @vanilla + // + // Save configuration data and savegames in c:\hexndata, + // allowing play from CD. + // + + cdrom = M_ParmExists("-cdrom"); +#endif + + if (cdrom) + { + M_SetConfigDir("c:\\hexndata\\"); + } + else + { + M_SetConfigDir(NULL); + } + + D_SetDefaultSavePath(); + M_SetConfigFilenames("hexen.cfg", PROGRAM_PREFIX "hexen.cfg"); + M_LoadDefaults(); + + I_AtExit(M_SaveDefaults, false); + + + // Now that the savedir is loaded from .CFG, make sure it exists + CreateSavePath(); + + ST_Message("Z_Init: Init zone memory allocation daemon.\n"); + Z_Init(); + + // haleyjd: removed WATCOMC + + ST_Message("W_Init: Init WADfiles.\n"); + + iwadfile = D_FindIWAD(IWAD_MASK_HEXEN, &gamemission); + + if (iwadfile == NULL) + { + I_Error("Game mode indeterminate. No IWAD was found. Try specifying\n" + "one with the '-iwad' command line parameter."); + } + + D_AddFile(iwadfile); + + HandleArgs(); + + I_PrintStartupBanner("Hexen"); + + ST_Message("MN_Init: Init menu system.\n"); + MN_Init(); + + ST_Message("CT_Init: Init chat mode data.\n"); + CT_Init(); + + InitMapMusicInfo(); // Init music fields in mapinfo + + ST_Message("S_InitScript\n"); + S_InitScript(); + + ST_Message("SN_InitSequenceScript: Registering sound sequences.\n"); + SN_InitSequenceScript(); + ST_Message("I_Init: Setting up machine state.\n"); + I_CheckIsScreensaver(); + I_InitTimer(); + I_InitJoystick(); + + S_Init(); + S_Start(); + + ST_Message("ST_Init: Init startup screen.\n"); + ST_Init(); + + // Show version message now, so it's visible during R_Init() + ST_Message("R_Init: Init Hexen refresh daemon"); + R_Init(); + ST_Message("\n"); + + if (M_CheckParm("-net")) + ST_NetProgress(); // Console player found + + ST_Message("P_Init: Init Playloop state.\n"); + P_Init(); + + // Check for command line warping. Follows P_Init() because the + // MAPINFO.TXT script must be already processed. + WarpCheck(); + + if (autostart) + { + ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n", + WarpMap, P_GetMapName(startmap), startmap, startskill + 1); + } + + ST_Message("D_CheckNetGame: Checking network game status.\n"); + D_CheckNetGame(); + + ST_Message("SB_Init: Loading patches.\n"); + SB_Init(); + + ST_Done(); + + CheckRecordFrom(); + + p = M_CheckParm("-record"); + if (p && p < myargc - 1) + { + G_RecordDemo(startskill, 1, startepisode, startmap, myargv[p + 1]); + H2_GameLoop(); // Never returns + } + + p = M_CheckParm("-playdemo"); + if (p && p < myargc - 1) + { + singledemo = true; // Quit after one demo + G_DeferedPlayDemo(myargv[p + 1]); + H2_GameLoop(); // Never returns + } + + p = M_CheckParm("-timedemo"); + if (p && p < myargc - 1) + { + G_TimeDemo(myargv[p + 1]); + H2_GameLoop(); // Never returns + } + + p = M_CheckParm("-loadgame"); + if (p && p < myargc - 1) + { + G_LoadGame(atoi(myargv[p + 1])); + } + + if (gameaction != ga_loadgame) + { + UpdateState |= I_FULLSCRN; + BorderNeedRefresh = true; + if (autostart || netgame) + { + G_StartNewInit(); + G_InitNew(startskill, startepisode, startmap); + } + else + { + H2_StartTitle(); + } + } + H2_GameLoop(); // Never returns +} + +//========================================================================== +// +// HandleArgs +// +//========================================================================== + +static void HandleArgs(void) +{ + int p; + execOpt_t *opt; + + nomonsters = M_ParmExists("-nomonsters"); + respawnparm = M_ParmExists("-respawn"); + randomclass = M_ParmExists("-randclass"); + ravpic = M_ParmExists("-ravpic"); + artiskip = M_ParmExists("-artiskip"); + debugmode = M_ParmExists("-debug"); + deathmatch = M_ParmExists("-deathmatch"); + + cmdfrag = M_ParmExists("-cmdfrag"); + + // Check WAD file command line options + W_ParseCommandLine(); + + // Process command line options + for (opt = ExecOptions; opt->name != NULL; opt++) + { + p = M_CheckParm(opt->name); + if (p && p < myargc - opt->requiredArgs) + { + opt->func(&myargv[p], opt->tag); + } + } +} + +//========================================================================== +// +// WarpCheck +// +//========================================================================== + +static void WarpCheck(void) +{ + int p; + int map; + + p = M_CheckParm("-warp"); + if (p && p < myargc - 1) + { + WarpMap = atoi(myargv[p + 1]); + map = P_TranslateMap(WarpMap); + if (map == -1) + { // Couldn't find real map number + startmap = 1; + ST_Message("-WARP: Invalid map number.\n"); + } + else + { // Found a valid startmap + startmap = map; + autostart = true; + } + } + else + { + WarpMap = 1; + startmap = P_TranslateMap(1); + if (startmap == -1) + { + startmap = 1; + } + } +} + +//========================================================================== +// +// ExecOptionSKILL +// +//========================================================================== + +static void ExecOptionSKILL(char **args, int tag) +{ + startskill = args[1][0] - '1'; + autostart = true; +} + +//========================================================================== +// +// ExecOptionPLAYDEMO +// +//========================================================================== + +static void ExecOptionPLAYDEMO(char **args, int tag) +{ + char file[256]; + + strcpy(file, args[1]); + + if (strcasecmp(file + strlen(file) - 4, ".lmp") != 0) + { + strcat(file, ".lmp"); + } + + W_AddFile(file); + ST_Message("Playing demo %s.\n", file); +} + +//========================================================================== +// +// ExecOptionSCRIPTS +// +//========================================================================== + +static void ExecOptionSCRIPTS(char **args, int tag) +{ + sc_FileScripts = true; + sc_ScriptsDir = args[1]; +} + + +//========================================================================== +// +// H2_GameLoop +// +//========================================================================== + +void H2_GameLoop(void) +{ + if (M_CheckParm("-debugfile")) + { + char filename[20]; + sprintf(filename, "debug%i.txt", consoleplayer); + debugfile = fopen(filename, "w"); + } + I_SetWindowTitle("Hexen"); + I_InitGraphics(); + I_SetGrabMouseCallback(D_GrabMouseCallback); + + while (1) + { + // Frame syncronous IO operations + I_StartFrame(); + + // Process one or more tics + if (singletics) + { + I_StartTic(); + H2_ProcessEvents(); + G_BuildTiccmd(&netcmds[consoleplayer][maketic % BACKUPTICS]); + if (advancedemo) + { + H2_DoAdvanceDemo(); + } + G_Ticker(); + gametic++; + maketic++; + } + else + { + // Will run at least one tic + TryRunTics(); + } + + // Move positional sounds + S_UpdateSounds(players[displayplayer].mo); + + DrawAndBlit(); + } +} + +//========================================================================== +// +// H2_ProcessEvents +// +// Send all the events of the given timestamp down the responder chain. +// +//========================================================================== + +void H2_ProcessEvents(void) +{ + event_t *ev; + + for (;;) + { + ev = D_PopEvent(); + + if (ev == NULL) + { + break; + } + + if (F_Responder(ev)) + { + continue; + } + if (MN_Responder(ev)) + { + continue; + } + G_Responder(ev); + } +} + +//========================================================================== +// +// DrawAndBlit +// +//========================================================================== + +static void DrawAndBlit(void) +{ + // Change the view size if needed + if (setsizeneeded) + { + R_ExecuteSetViewSize(); + } + + // Do buffered drawing + switch (gamestate) + { + case GS_LEVEL: + if (!gametic) + { + break; + } + if (automapactive) + { + AM_Drawer(); + } + else + { + R_RenderPlayerView(&players[displayplayer]); + } + CT_Drawer(); + UpdateState |= I_FULLVIEW; + SB_Drawer(); + break; + case GS_INTERMISSION: + IN_Drawer(); + break; + case GS_FINALE: + F_Drawer(); + break; + case GS_DEMOSCREEN: + PageDrawer(); + break; + } + + if (paused && !MenuActive && !askforquit) + { + if (!netgame) + { + V_DrawPatch(160, viewwindowy + 5, W_CacheLumpName("PAUSED", + PU_CACHE)); + } + else + { + V_DrawPatch(160, 70, W_CacheLumpName("PAUSED", PU_CACHE)); + } + } + + // Draw current message + DrawMessage(); + + // Draw Menu + MN_Drawer(); + + // Send out any new accumulation + NetUpdate(); + + // Flush buffered stuff to screen + I_FinishUpdate(); +} + +//========================================================================== +// +// DrawMessage +// +//========================================================================== + +static void DrawMessage(void) +{ + player_t *player; + + player = &players[consoleplayer]; + if (player->messageTics <= 0 || !player->message) + { // No message + return; + } + if (player->yellowMessage) + { + MN_DrTextAYellow(player->message, + 160 - MN_TextAWidth(player->message) / 2, 1); + } + else + { + MN_DrTextA(player->message, 160 - MN_TextAWidth(player->message) / 2, + 1); + } +} + +//========================================================================== +// +// H2_PageTicker +// +//========================================================================== + +void H2_PageTicker(void) +{ + if (--pagetic < 0) + { + H2_AdvanceDemo(); + } +} + +//========================================================================== +// +// PageDrawer +// +//========================================================================== + +static void PageDrawer(void) +{ + V_DrawRawScreen(W_CacheLumpName(pagename, PU_CACHE)); + if (demosequence == 1) + { + V_DrawPatch(4, 160, W_CacheLumpName("ADVISOR", PU_CACHE)); + } + UpdateState |= I_FULLSCRN; +} + +//========================================================================== +// +// H2_AdvanceDemo +// +// Called after each demo or intro demosequence finishes. +// +//========================================================================== + +void H2_AdvanceDemo(void) +{ + advancedemo = true; +} + +//========================================================================== +// +// H2_DoAdvanceDemo +// +//========================================================================== + +void H2_DoAdvanceDemo(void) +{ + players[consoleplayer].playerstate = PST_LIVE; // don't reborn + advancedemo = false; + usergame = false; // can't save/end game here + paused = false; + gameaction = ga_nothing; + demosequence = (demosequence + 1) % 7; + switch (demosequence) + { + case 0: + pagetic = 280; + gamestate = GS_DEMOSCREEN; + pagename = "TITLE"; + S_StartSongName("hexen", true); + break; + case 1: + pagetic = 210; + gamestate = GS_DEMOSCREEN; + pagename = "TITLE"; + break; + case 2: + BorderNeedRefresh = true; + UpdateState |= I_FULLSCRN; + G_DeferedPlayDemo("demo1"); + break; + case 3: + pagetic = 200; + gamestate = GS_DEMOSCREEN; + pagename = "CREDIT"; + break; + case 4: + BorderNeedRefresh = true; + UpdateState |= I_FULLSCRN; + G_DeferedPlayDemo("demo2"); + break; + case 5: + pagetic = 200; + gamestate = GS_DEMOSCREEN; + pagename = "CREDIT"; + break; + case 6: + BorderNeedRefresh = true; + UpdateState |= I_FULLSCRN; + G_DeferedPlayDemo("demo3"); + break; + } +} + +//========================================================================== +// +// H2_StartTitle +// +//========================================================================== + +void H2_StartTitle(void) +{ + gameaction = ga_nothing; + demosequence = -1; + H2_AdvanceDemo(); +} + +//========================================================================== +// +// CheckRecordFrom +// +// -recordfrom <savegame num> <demoname> +// +//========================================================================== + +static void CheckRecordFrom(void) +{ + int p; + + p = M_CheckParm("-recordfrom"); + if (!p || p > myargc - 2) + { // Bad args + return; + } + G_LoadGame(atoi(myargv[p + 1])); + G_DoLoadGame(); // Load the gameskill etc info from savegame + G_RecordDemo(gameskill, 1, gameepisode, gamemap, myargv[p + 2]); + + H2_GameLoop(); // Never returns +} + +// haleyjd: removed WATCOMC +/* +void CleanExit(void) +{ + union REGS regs; + + I_ShutdownKeyboard(); + regs.x.eax = 0x3; + int386(0x10, ®s, ®s); + printf("Exited from HEXEN: Beyond Heretic.\n"); + exit(1); +} +*/ + +//========================================================================== +// +// CreateSavePath +// +//========================================================================== + +static void CreateSavePath(void) +{ + M_MakeDirectory(SavePath); +} + |