diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 92bdaf8e..98f102e1 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,114 @@
+February 5, 2009 (Changes by Graf Zahl)
+- Made improvements so that the FOptionalMapinfoData class is easier to use.
+
+February 3, 2009
+- Moved the MF_INCHASE recursion check from A_Look() into A_Chase(). This
+ lets A_Look() always put the actor into its see state. This problem could
+ be heard by an Archvile's resurrectee playing its see sound but failing to
+ enter its see state because it was called from A_Chase().
+- Fixed: SBARINFO used different rounding modes for the background and
+ foreground of the DrawBar command.
+- Bumped MINSAVEVER to coincide with the new MAPINFO merge.
+- Added a fflush() call after the logfile write in I_FatalError so that the
+ error text is visible in the file while the error dialog is displayed.
+
+January 18, 2009 - February 3, 2009 (Changes by Graf Zahl)
+- moved all code related to global ACS variables to p_acs.cpp where it belongs.
+- fixed: The nextmap and nextsecret CCMDs need to call G_DeferedInitNew instead of G_InitNew.
+- rewrote the MAPINFO parser:
+ * split level_info_t::flags into 2 DWORDS so that I don't have to deal with 64 bit values later.
+ * split off skill code into its own file
+ * created a parser class for MAPINFO
+ * replaced all uses of ReplaceString in level_info_t with FStrings and made the specialaction
+ data a TArray so that levelinfos can be handled without error prone maintenance functions.
+ * split of parser code from g_level.cpp
+ * const-ified parameters to F_StartFinale.
+ * Changed how G_MaybeLookupLevelName works and made it return an FString.
+ * removed 64 character limit on level names.
+
+February 2, 2009
+- Changed DECORATE replacements so that they aren't overridden by Dehacked.
+
+February 2, 2009 (Changes by Graf Zahl)
+- Fixed: The damage factor for 'normal' damage is supposed to be applied to
+ all damage types that don't have a specific damage factor.
+
+January 31, 2009
+- Changed FMOD init() to allocate some virtual channels.
+- Fixed clipping in D3DFB::DrawTextureV() for good by using a scissor test.
+
+January 30, 2009
+- Fixed: D3DFB::DrawTextureV() did not properly adjust the texture coordinate
+ for lclip and rclip.
+- Added weapdrop ccmd.
+- Centered the compatibility mode option in the comptibility options menu.
+- Added button mappings for 8 mouse buttons on SDL. It works with my system,
+ but Linux being Linux, there are no guarantees that it's appropriate for
+ other systems.
+- Fixed: SDL input code did not generate GUI events for the mousewheel, so it
+ could not be used to scroll the console buffer.
+
+January 30, 2009 (Changes by Graf Zahl)
+- Added Blzut3's statusbar maintenance patch.
+
+January 29, 2009 (Changes by Graf Zahl)
+- fixed sound origin of the Mage Wand's missile.
+
+January 28, 2009 (Changes by Graf Zahl)
+- Added APROP_Dropped actor property.
+- Fixed: The compatmode CVAR needs CVAR_NOINITCALL so that the compatibility
+ flags don't get reset each start.
+- Fixed: compatmode Doom(strict) was missing COMPAT_CROSSDROPOFF
+
+January 27, 2009
+- More GCC warning removal, the most egregious of which was the security
+ vulnerability "format not a string literal and no format arguments".
+- Changed the CMake script to search for fmod libraries by full name instead
+ of assuming a symbolic link has been placed for the latest version. It can
+ also find a non-installed copy of FMOD if it is placed local to the ZDoom
+ source tree.
+
+January 26, 2009
+- Fixed: Some OPL state needs to be restored before calculating rhythm. Also,
+ since only the rhythm section uses the RNG, it doesn't need to be advanced
+ for the normal voice processing.
+
+January 25, 2009 (Changes by Graf Zahl)
+- fixed some issues with P_FindFloorCeiling's coordinate processing.
+- added a new compatmode CVAR which allows setting some generic compatibility
+ flag combinations:
+ Doom: sets the options needed to make most Doom.exe compatible map play without
+ errors.
+ Doom (strict): Same as above but sets a few more options. Please note that this
+ does not mean full Doom.exe behavior emulation.
+ Boom: Sets all options that consider differences between ZDoom and Boom.
+ ZDoom 2.0.63: Sets only the COMPATF_SOUNDTARGET option which is needed for
+ many older ZDoom maps.
+- added new COMPAT_CROSSDROPOFF option to block monsters from being pushed over
+ dropoffs by damage kickback.
+- fixed: AFastProjectile::Tick must call Effect only 8 times per tic, regardless
+ of the amount of steps taken.
+- fixed: momentum checks in AFastProjectile did not use absolute values.
+
+January 24, 2009
+- Restored the rhythm section to fmopl.cpp and made some slight updates from
+ version 0.72 of MAME's fmopl.c. Also refactored CalcVoice so that the
+ original MAME structure is more visible.
+- Removed the SoundChans bitfield from AActor, since it seems there are race
+ conditions I don't fully understand where it simply doesn't work.
+- Removed BaseTime initialization from sdl/i_system.cpp as per Chris's
+ recommendation.
+
+January 24, 2009 (Changes by Graf Zahl)
+- Fixed: The sight checking code didn't initialize the myseethrough variable.
+- Fixed: With COMPAT_TRACE switched on linedef actions on lines having
+ the same sector on both sides were not triggered.
+
+January 23, 2009
+- Set packet server as the default for four or more player games, and also the
+ default for three player games where the other players are not in the same
+ private IP range.
+
January 18, 2009 (Changes by Graf Zahl)
- Added a CopyInfo function to FTexture that contains all code required to
clone a texture. Used for creating warping textures.
diff --git a/gzdoom.vcproj b/gzdoom.vcproj
index f285653d..cd15b678 100644
--- a/gzdoom.vcproj
+++ b/gzdoom.vcproj
@@ -625,6 +625,14 @@
RelativePath=".\src\g_level.cpp"
>
+
+
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 270cd969..d9f34f9c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -455,6 +455,8 @@ add_executable( zdoom WIN32
g_game.cpp
g_hub.cpp
g_level.cpp
+ g_mapinfo.cpp
+ g_skill.cpp
gameconfigfile.cpp
gi.cpp
hu_scores.cpp
diff --git a/src/am_map.cpp b/src/am_map.cpp
index 36c10d63..541d3a5d 100644
--- a/src/am_map.cpp
+++ b/src/am_map.cpp
@@ -1784,7 +1784,7 @@ void AM_Drawer ()
if (!automapactive)
return;
- bool allmap = (level.flags & LEVEL_ALLMAP) != 0;
+ bool allmap = (level.flags2 & LEVEL2_ALLMAP) != 0;
bool allthings = allmap && players[consoleplayer].mo->FindInventory() != NULL;
AM_initColors (viewactive);
diff --git a/src/autosegs.h b/src/autosegs.h
index 01069c51..b873602e 100644
--- a/src/autosegs.h
+++ b/src/autosegs.h
@@ -41,11 +41,13 @@
#define CREG_SECTION "__DATA,creg"
#define GREG_SECTION "__DATA,greg"
#define MREG_SECTION "__DATA,mreg"
+#define MREG_SECTION "__DATA,yreg"
#else
#define AREG_SECTION "areg"
#define CREG_SECTION "creg"
#define GREG_SECTION "greg"
#define MREG_SECTION "mreg"
+#define GREG_SECTION "yreg"
#endif
#endif
@@ -68,6 +70,10 @@ extern REGINFO GRegTail;
extern REGINFO MRegHead;
extern REGINFO MRegTail;
+// List of MAPINFO map options
+extern REGINFO YRegHead;
+extern REGINFO YRegTail;
+
template
class TAutoSegIteratorNoArrow
{
diff --git a/src/autostart.cpp b/src/autostart.cpp
index 666f5b9d..5bdfa3c6 100644
--- a/src/autostart.cpp
+++ b/src/autostart.cpp
@@ -46,7 +46,7 @@
#if defined(_MSC_VER)
-#pragma comment(linker, "/merge:.areg=.data /merge:.creg=.data /merge:.greg=.data /merge:.mreg=.data")
+#pragma comment(linker, "/merge:.areg=.data /merge:.creg=.data /merge:.greg=.data /merge:.mreg=.data /merge:.yreg=.data")
#pragma data_seg(".areg$a")
void *ARegHead = 0;
@@ -60,6 +60,9 @@ void *GRegHead = 0;
#pragma data_seg(".mreg$a")
void *MRegHead = 0;
+#pragma data_seg(".yreg$a")
+void *YRegHead = 0;
+
#pragma data_seg()
// We want visual styles support under XP
@@ -87,6 +90,7 @@ void *ARegHead __attribute__((section(AREG_SECTION))) = 0;
void *CRegHead __attribute__((section(CREG_SECTION))) = 0;
void *GRegHead __attribute__((section(GREG_SECTION))) = 0;
void *MRegHead __attribute__((section(MREG_SECTION))) = 0;
+void *YRegHead __attribute__((section(YREG_SECTION))) = 0;
#elif
diff --git a/src/autozend.cpp b/src/autozend.cpp
index 0e7c2e5d..84903eee 100644
--- a/src/autozend.cpp
+++ b/src/autozend.cpp
@@ -49,6 +49,9 @@ void *GRegTail = 0;
#pragma data_seg(".mreg$z")
void *MRegTail = 0;
+#pragma data_seg(".yreg$z")
+void *YRegTail = 0;
+
#pragma data_seg()
@@ -59,6 +62,7 @@ void *ARegTail __attribute__((section(AREG_SECTION))) = 0;
void *CRegTail __attribute__((section(CREG_SECTION))) = 0;
void *GRegTail __attribute__((section(GREG_SECTION))) = 0;
void *MRegTail __attribute__((section(MREG_SECTION))) = 0;
+void *YRegTail __attribute__((section(YREG_SECTION))) = 0;
#elif
diff --git a/src/b_bot.cpp b/src/b_bot.cpp
index be43f2b1..b03c067f 100644
--- a/src/b_bot.cpp
+++ b/src/b_bot.cpp
@@ -55,7 +55,7 @@ void FCajunMaster::ClearPlayer (int i, bool keepTeam)
if (bot)
{
bot->inuse = false;
- bot->lastteam = keepTeam ? players[i].userinfo.team : TEAM_None;
+ bot->lastteam = keepTeam ? players[i].userinfo.team : TEAM_NONE;
}
players[i].~player_t();
::new(&players[i]) player_t;
diff --git a/src/b_game.cpp b/src/b_game.cpp
index 9a6b618f..f517f27e 100644
--- a/src/b_game.cpp
+++ b/src/b_game.cpp
@@ -332,7 +332,7 @@ bool FCajunMaster::SpawnBot (const char *name, int color)
{
strcat (concat, colors[bot_next_color]);
}
- if (TEAMINFO_IsValidTeam (thebot->lastteam))
+ if (TeamLibrary.IsValidTeam (thebot->lastteam))
{ // Keep the bot on the same team when switching levels
mysnprintf (concat + strlen(concat), countof(concat) - strlen(concat),
"\\team\\%d\n", thebot->lastteam);
@@ -374,7 +374,7 @@ void FCajunMaster::DoAddBot (int bnum, char *info)
botingame[bnum] = true;
if (teamplay)
- Printf ("%s joined the %s team\n", players[bnum].userinfo.netname, teams[players[bnum].userinfo.team].name.GetChars ());
+ Printf ("%s joined the %s team\n", players[bnum].userinfo.netname,Teams[players[bnum].userinfo.team].GetName ());
else
Printf ("%s joined the game\n", players[bnum].userinfo.netname);
@@ -592,17 +592,17 @@ bool FCajunMaster::LoadBots ()
if (IsNum (sc.String))
{
teamnum = atoi (sc.String);
- if (!TEAMINFO_IsValidTeam (teamnum))
+ if (!TeamLibrary.IsValidTeam (teamnum))
{
- teamnum = TEAM_None;
+ teamnum = TEAM_NONE;
}
}
else
{
- teamnum = TEAM_None;
- for (int i = 0; i < int(teams.Size()); ++i)
+ teamnum = TEAM_NONE;
+ for (unsigned int i = 0; i < Teams.Size(); ++i)
{
- if (stricmp (teams[i].name, sc.String) == 0)
+ if (stricmp (Teams[i].GetName (), sc.String) == 0)
{
teamnum = i;
break;
@@ -638,7 +638,7 @@ bool FCajunMaster::LoadBots ()
appendinfo (newinfo->info, "255");
}
newinfo->next = bglobal.botinfo;
- newinfo->lastteam = TEAM_None;
+ newinfo->lastteam = TEAM_NONE;
bglobal.botinfo = newinfo;
bglobal.loaded_bots++;
}
diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp
index e4197ce2..a65541de 100644
--- a/src/c_cmds.cpp
+++ b/src/c_cmds.cpp
@@ -482,7 +482,7 @@ CCMD (error)
if (argv.argc() > 1)
{
char *textcopy = copystring (argv[1]);
- I_Error (textcopy);
+ I_Error ("%s", textcopy);
}
else
{
@@ -495,7 +495,7 @@ CCMD (error_fatal)
if (argv.argc() > 1)
{
char *textcopy = copystring (argv[1]);
- I_FatalError (textcopy);
+ I_FatalError ("%s", textcopy);
}
else
{
@@ -858,7 +858,7 @@ CCMD(nextmap)
if (next != NULL && strncmp(next, "enDSeQ", 6))
{
- G_InitNew(next, false);
+ G_DeferedInitNew(next, false);
}
else
{
@@ -879,7 +879,7 @@ CCMD(nextsecret)
if (next != NULL && strncmp(next, "enDSeQ", 6))
{
- G_InitNew(next, false);
+ G_DeferedInitNew(next, false);
}
else
{
diff --git a/src/c_console.cpp b/src/c_console.cpp
index 76d13574..d6ec09c0 100644
--- a/src/c_console.cpp
+++ b/src/c_console.cpp
@@ -1317,7 +1317,7 @@ void C_FullConsole ()
if (gamestate != GS_STARTUP)
{
gamestate = GS_FULLCONSOLE;
- level.music = NULL;
+ level.Music = "";
S_Start ();
P_FreeLevelData ();
V_SetBlend (0,0,0,0);
diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp
index 6977179d..4194055a 100644
--- a/src/d_dehacked.cpp
+++ b/src/d_dehacked.cpp
@@ -2585,7 +2585,7 @@ void FinishDehPatch ()
AActor *defaults2 = GetDefaultByType (subclass);
memcpy (defaults2, defaults1, sizeof(AActor));
- // Make a copy the replaced class's state labels
+ // Make a copy of the replaced class's state labels
FStateDefinitions statedef;
statedef.MakeStateDefines(type);
@@ -2598,8 +2598,16 @@ void FinishDehPatch ()
// Use the DECORATE replacement feature to redirect all spawns
// of the original class to the new one.
+ FActorInfo *old_replacement = type->ActorInfo->Replacement;
+
type->ActorInfo->Replacement = subclass->ActorInfo;
subclass->ActorInfo->Replacee = type->ActorInfo;
+ // If this actor was already replaced by another actor, copy that
+ // replacement over to this item.
+ if (old_replacement != NULL)
+ {
+ subclass->ActorInfo->Replacement = old_replacement;
+ }
DPrintf ("%s replaces %s\n", subclass->TypeName.GetChars(), type->TypeName.GetChars());
}
diff --git a/src/d_main.cpp b/src/d_main.cpp
index cb9db695..8512252e 100644
--- a/src/d_main.cpp
+++ b/src/d_main.cpp
@@ -523,7 +523,7 @@ CUSTOM_CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
i_compatflags = GetCompatibility(self);
}
-CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
+CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_SERVERINFO|CVAR_NOINITCALL)
{
int v;
@@ -542,7 +542,7 @@ CUSTOM_CVAR(Int, compatmode, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
case 2: // same as 1 but stricter (NO_PASSMOBJ and INVISIBILITY are also set)
v = COMPATF_SHORTTEX|COMPATF_STAIRINDEX|COMPATF_USEBLOCKING|COMPATF_NODOORLIGHT|
COMPATF_TRACE|COMPATF_MISSILECLIP|COMPATF_SOUNDTARGET|COMPATF_NO_PASSMOBJ|COMPATF_LIMITPAIN|
- COMPATF_DEHHEALTH|COMPATF_INVISIBILITY;
+ COMPATF_DEHHEALTH|COMPATF_INVISIBILITY|COMPATF_CROSSDROPOFF;
break;
case 3:
@@ -2447,7 +2447,7 @@ void D_DoomMain (void)
}
if (devparm)
{
- Printf (GStrings("D_DEVSTR"));
+ Printf ("%s", GStrings("D_DEVSTR"));
}
#ifndef unix
@@ -2456,7 +2456,7 @@ void D_DoomMain (void)
// the user's home directory.
if (Args->CheckParm("-cdrom"))
{
- Printf (GStrings("D_CDROM"));
+ Printf ("%s", GStrings("D_CDROM"));
mkdir (CDROM_DIR, 0);
}
#endif
@@ -2521,9 +2521,9 @@ void D_DoomMain (void)
// Now that all textues have been loaded the crosshair can be initialized.
crosshair.Callback ();
- // [CW] Parse any TEAMINFO lumps
- Printf ("TEAMINFO_Init: Load team definitions.\n");
- TEAMINFO_Init ();
+ // [CW] Parse any TEAMINFO lumps.
+ Printf ("ParseTeamInfo: Load team definitions.\n");
+ TeamLibrary.ParseTeamInfo ();
FActorInfo::StaticInit ();
diff --git a/src/d_net.cpp b/src/d_net.cpp
index d480ab61..ed98a1a6 100644
--- a/src/d_net.cpp
+++ b/src/d_net.cpp
@@ -1963,7 +1963,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
BYTE who = ReadByte (stream);
s = ReadString (stream);
- if (((who & 1) == 0) || players[player].userinfo.team == TEAM_None)
+ if (((who & 1) == 0) || players[player].userinfo.team == TEAM_NONE)
{ // Said to everyone
if (who & 2)
{
@@ -1997,7 +1997,7 @@ void Net_DoCommand (int type, BYTE **stream, int player)
case DEM_PRINT:
s = ReadString (stream);
- Printf (s);
+ Printf ("%s", s);
break;
case DEM_CENTERPRINT:
diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp
index cb097d59..5ed0a9ac 100644
--- a/src/d_netinfo.cpp
+++ b/src/d_netinfo.cpp
@@ -65,7 +65,7 @@ CVAR (Float, autoaim, 5000.f, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (String, name, "Player", CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Color, color, 0x40cf00, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (String, skin, "base", CVAR_USERINFO | CVAR_ARCHIVE);
-CVAR (Int, team, TEAM_None, CVAR_USERINFO | CVAR_ARCHIVE);
+CVAR (Int, team, TEAM_NONE, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (String, gender, "male", CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Bool, neverswitchonpickup, false, CVAR_USERINFO | CVAR_ARCHIVE);
CVAR (Float, movebob, 0.25f, CVAR_USERINFO | CVAR_ARCHIVE);
@@ -191,13 +191,13 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v)
RGBtoHSV (RPART(color)/255.f, GPART(color)/255.f, BPART(color)/255.f,
h, s, v);
- if (teamplay && TEAMINFO_IsValidTeam(info->team))
+ if (teamplay && TeamLibrary.IsValidTeam(info->team) && !Teams[info->team].GetAllowCustomPlayerColor ())
{
// In team play, force the player to use the team's hue
// and adjust the saturation and value so that the team
// hue is visible in the final color.
float ts, tv;
- int tcolor = teams[info->team].playercolor;
+ int tcolor = Teams[info->team].GetPlayerColor ();
RGBtoHSV (RPART(tcolor)/255.f, GPART(tcolor)/255.f, BPART(tcolor)/255.f,
h, &ts, &tv);
@@ -225,10 +225,10 @@ void D_PickRandomTeam (int player)
int D_PickRandomTeam ()
{
- for (int i = 0; i < (signed)teams.Size (); i++)
+ for (unsigned int i = 0; i < Teams.Size (); i++)
{
- teams[i].present = 0;
- teams[i].ties = 0;
+ Teams[i].m_iPresent = 0;
+ Teams[i].m_iTies = 0;
}
int numTeams = 0;
@@ -238,9 +238,9 @@ int D_PickRandomTeam ()
{
if (playeringame[i])
{
- if (TEAMINFO_IsValidTeam (players[i].userinfo.team))
+ if (TeamLibrary.IsValidTeam (players[i].userinfo.team))
{
- if (teams[players[i].userinfo.team].present++ == 0)
+ if (Teams[players[i].userinfo.team].m_iPresent++ == 0)
{
numTeams++;
}
@@ -252,36 +252,37 @@ int D_PickRandomTeam ()
{
do
{
- team = pr_pickteam() % teams.Size ();
- } while (teams[team].present != 0);
+ team = pr_pickteam() % Teams.Size ();
+ } while (Teams[team].m_iPresent != 0);
}
else
{
- int lowest = INT_MAX, lowestTie = 0, i;
+ int lowest = INT_MAX, lowestTie = 0;
+ unsigned int i;
- for (i = 0; i < (signed)teams.Size (); ++i)
+ for (i = 0; i < Teams.Size (); ++i)
{
- if (teams[i].present > 0)
+ if (Teams[i].m_iPresent > 0)
{
- if (teams[i].present < lowest)
+ if (Teams[i].m_iPresent < lowest)
{
- lowest = teams[i].present;
+ lowest = Teams[i].m_iPresent;
lowestTie = 0;
- teams[0].ties = i;
+ Teams[0].m_iTies = i;
}
- else if (teams[i].present == lowest)
+ else if (Teams[i].m_iPresent == lowest)
{
- teams[++lowestTie].ties = i;
+ Teams[++lowestTie].m_iTies = i;
}
}
}
if (lowestTie == 0)
{
- team = teams[0].ties;
+ team = Teams[0].m_iTies;
}
else
{
- team = teams[pr_pickteam() % (lowestTie+1)].ties;
+ team = Teams[pr_pickteam() % (lowestTie+1)].m_iTies;
}
}
@@ -292,7 +293,7 @@ static void UpdateTeam (int pnum, int team, bool update)
{
userinfo_t *info = &players[pnum].userinfo;
- if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && TEAMINFO_IsValidTeam (info->team))
+ if ((dmflags2 & DF2_NO_TEAM_SWITCH) && (alwaysapplydmflags || deathmatch) && TeamLibrary.IsValidTeam (info->team))
{
Printf ("Team changing has been disabled!\n");
return;
@@ -300,21 +301,21 @@ static void UpdateTeam (int pnum, int team, bool update)
int oldteam;
- if (!TEAMINFO_IsValidTeam (team))
+ if (!TeamLibrary.IsValidTeam (team))
{
- team = TEAM_None;
+ team = TEAM_NONE;
}
oldteam = info->team;
info->team = team;
- if (teamplay && !TEAMINFO_IsValidTeam (info->team))
+ if (teamplay && !TeamLibrary.IsValidTeam (info->team))
{ // Force players onto teams in teamplay mode
info->team = D_PickRandomTeam ();
}
if (update && oldteam != info->team)
{
- if (TEAMINFO_IsValidTeam (info->team))
- Printf ("%s joined the %s team\n", info->netname, teams[info->team].name.GetChars());
+ if (TeamLibrary.IsValidTeam (info->team))
+ Printf ("%s joined the %s team\n", info->netname, Teams[info->team].GetName ());
else
Printf ("%s is now a loner\n", info->netname);
}
@@ -324,13 +325,13 @@ static void UpdateTeam (int pnum, int team, bool update)
{
StatusBar->AttachToPlayer (&players[pnum]);
}
- if (!TEAMINFO_IsValidTeam (info->team))
- info->team = TEAM_None;
+ if (!TeamLibrary.IsValidTeam (info->team))
+ info->team = TEAM_NONE;
}
int D_GetFragCount (player_t *player)
{
- if (!teamplay || !TEAMINFO_IsValidTeam (player->userinfo.team))
+ if (!teamplay || !TeamLibrary.IsValidTeam (player->userinfo.team))
{
return player->fragcount;
}
@@ -360,7 +361,7 @@ void D_SetupUserInfo ()
memset (&players[i].userinfo, 0, sizeof(userinfo_t));
strncpy (coninfo->netname, name, MAXPLAYERNAME);
- if (teamplay && !TEAMINFO_IsValidTeam (team))
+ if (teamplay && !TeamLibrary.IsValidTeam (team))
{
coninfo->team = D_PickRandomTeam ();
}
@@ -831,7 +832,7 @@ CCMD (playerinfo)
int i = atoi (argv[1]);
userinfo_t *ui = &players[i].userinfo;
Printf ("Name: %s\n", ui->netname);
- Printf ("Team: %s (%d)\n", ui->team == TEAM_None ? "None" : teams[ui->team].name.GetChars(), ui->team);
+ Printf ("Team: %s (%d)\n", ui->team == TEAM_NONE ? "None" : Teams[ui->team].GetName (), ui->team);
Printf ("Aimdist: %d\n", ui->aimdist);
Printf ("Color: %06x\n", ui->color);
Printf ("Skin: %s (%d)\n", skins[ui->skin].name, ui->skin);
diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp
index edb32fbb..481df513 100644
--- a/src/dobjtype.cpp
+++ b/src/dobjtype.cpp
@@ -253,7 +253,7 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
const PClass *existclass = FindClass(name);
// This is a placeholder so fill it in
- if (existclass != NULL && existclass->Size == -1)
+ if (existclass != NULL && existclass->Size == (unsigned)-1)
{
type = const_cast(existclass);
if (!IsDescendantOf(type->ParentClass))
diff --git a/src/doomstat.cpp b/src/doomstat.cpp
index 0fe988a9..6fe88955 100644
--- a/src/doomstat.cpp
+++ b/src/doomstat.cpp
@@ -60,7 +60,7 @@ CUSTOM_CVAR (String, language, "auto", CVAR_ARCHIVE)
{
SetLanguageIDs ();
GStrings.LoadStrings (false);
- G_MaybeLookupLevelName (NULL);
+ if (level.info != NULL) level.LevelName = level.info->LookupLevelName();
}
// [RH] Network arbitrator
diff --git a/src/f_finale.cpp b/src/f_finale.cpp
index bbdd7d43..11d06b55 100644
--- a/src/f_finale.cpp
+++ b/src/f_finale.cpp
@@ -86,8 +86,8 @@ void F_AdvanceSlideshow ();
//
// F_StartFinale
//
-void F_StartFinale (char *music, int musicorder, int cdtrack, unsigned int cdid, char *flat, char *text,
- INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText, bool ending)
+void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat,
+ const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText, bool ending)
{
bool loopmusic = ending ? !(gameinfo.flags & GI_NOLOOPFINALEMUSIC) : true;
gameaction = ga_nothing;
@@ -1026,7 +1026,7 @@ void F_StartSlideshow ()
V_SetBlend (0,0,0,0);
// The slideshow is determined solely by the map you're on.
- if (!multiplayer && level.flags & LEVEL_DEATHSLIDESHOW)
+ if (!multiplayer && level.flags2 & LEVEL2_DEATHSLIDESHOW)
{
FinalePart = 14;
}
@@ -1062,7 +1062,7 @@ void F_AdvanceSlideshow ()
{
case -99:
if (level.cdtrack == 0 || !S_ChangeCDMusic (level.cdtrack, level.cdid))
- S_ChangeMusic (level.music, level.musicorder);
+ S_ChangeMusic (level.Music, level.musicorder);
gamestate = GS_LEVEL;
wipegamestate = GS_LEVEL;
P_ResumeConversation ();
diff --git a/src/f_finale.h b/src/f_finale.h
index 701a756e..8673e3b2 100644
--- a/src/f_finale.h
+++ b/src/f_finale.h
@@ -42,8 +42,8 @@ void F_Ticker ();
void F_Drawer ();
-void F_StartFinale (char *music, int musicorder, int cdtrack, unsigned int cdid, char *flat, char *text,
- INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText, bool ending);
+void F_StartFinale (const char *music, int musicorder, int cdtrack, unsigned int cdid, const char *flat,
+ const char *text, INTBOOL textInLump, INTBOOL finalePic, INTBOOL lookupText, bool ending);
void F_StartSlideshow ();
diff --git a/src/fragglescript/t_load.cpp b/src/fragglescript/t_load.cpp
index f53ee762..4a326a1f 100644
--- a/src/fragglescript/t_load.cpp
+++ b/src/fragglescript/t_load.cpp
@@ -83,39 +83,22 @@ struct FFsOptions : public FOptionalMapinfoData
bool nocheckposition;
};
-static void ParseFunc(FScanner &sc, level_info_t *info)
+DEFINE_MAP_OPTION(fs_nocheckposition, false)
{
- FName id = "fragglescript";
- FOptionalMapinfoData *dat = info->opdata;
+ FFsOptions *opt = info->GetOptData("fragglescript");
- while (dat && dat->identifier != id) dat = dat->Next;
- if (!dat) dat = new FFsOptions;
- dat->Next = info->opdata;
- info->opdata = dat;
-
- FFsOptions *opt = static_cast(dat);
-
- while (!sc.CheckString("}"))
+ parse.ParseAssign();
+ if (parse.CheckAssign())
{
- sc.MustGetString();
- if (sc.Compare("nocheckposition"))
- {
- if (!sc.CheckNumber()) opt->nocheckposition = false;
- else opt->nocheckposition = !!sc.Number;
- }
- else
- {
- sc.ScriptError(NULL);
- }
+ parse.sc.MustGetNumber();
+ opt->nocheckposition = !!parse.sc.Number;
+ }
+ else
+ {
+ opt->nocheckposition = true;
}
}
-void AddFsMapinfoParser()
-{
- AddOptionalMapinfoParser("fragglescript", ParseFunc);
-}
-
-
//-----------------------------------------------------------------------------
//
// Process the lump to strip all unneeded information from it
@@ -176,8 +159,7 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
while (*beg<=' ') beg++;
char * comm = strstr(beg, "//");
if (comm) *comm=0;
- strncpy(level.level_name, beg, 63);
- level.level_name[63]=0;
+ level.LevelName = beg;
}
else if (sc.Compare("partime"))
{
@@ -193,7 +175,7 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
sc.MustGetString();
if (!FS_ChangeMusic(sc.String))
{
- S_ChangeMusic(level.music, level.musicorder);
+ S_ChangeMusic(level.Music, level.musicorder);
}
}
else if (sc.Compare("skyname"))
@@ -211,7 +193,7 @@ void FScriptLoader::ParseInfoCmd(char *line, FString &scriptsrc)
{
sc.MustGetStringName("=");
sc.MustGetString();
- ReplaceString(&level.info->exitpic, sc.String);
+ level.info->ExitPic = sc.String;
}
else if (sc.Compare("gravity"))
{
@@ -319,13 +301,9 @@ bool FScriptLoader::ParseInfo(MapData * map)
if (drownflag==-1) drownflag = ((level.flags&LEVEL_HEXENFORMAT) || fsglobal);
if (!drownflag) level.airsupply=0; // Legacy doesn't to water damage.
- FName id = "fragglescript";
- FOptionalMapinfoData *dat = level.info->opdata;
-
- while (dat && dat->identifier != id) dat = dat->Next;
- if (dat != NULL)
+ FFsOptions *opt = level.info->GetOptData("fragglescript", false);
+ if (opt != NULL)
{
- FFsOptions *opt = static_cast(dat);
DFraggleThinker::ActiveThinker->nocheckposition = opt->nocheckposition;
}
}
@@ -356,7 +334,7 @@ void T_LoadScripts(MapData *map)
// This code then then swaps 270 and 272 - but only if this is either Doom or Heretic and
// the default translator is being used.
// Custom translators will not be patched.
- if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && level.info->translator == NULL &&
+ if ((gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Heretic) && level.info->Translator.IsEmpty() &&
!((level.flags&LEVEL_HEXENFORMAT)) && SimpleLineTranslations[272 - 2*HasScripts].special == FS_Execute)
{
FLineTrans t = SimpleLineTranslations[270];
diff --git a/src/g_game.cpp b/src/g_game.cpp
index 7ca1b242..491852ff 100644
--- a/src/g_game.cpp
+++ b/src/g_game.cpp
@@ -73,6 +73,7 @@
#include "cmdlib.h"
#include "d_net.h"
#include "d_event.h"
+#include "p_acs.h"
#include
@@ -386,6 +387,11 @@ CCMD (invdrop)
if (players[consoleplayer].mo) SendItemDrop = players[consoleplayer].mo->InvSel;
}
+CCMD (weapdrop)
+{
+ SendItemDrop = players[consoleplayer].ReadyWeapon;
+}
+
CCMD (drop)
{
if (argv.argc() > 1 && who != NULL)
@@ -1124,7 +1130,7 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, bool resetinventory
}
}
- if (mode == FINISH_NoHub && !(level.flags & LEVEL_KEEPFULLINVENTORY))
+ if (mode == FINISH_NoHub && !(level.flags2 & LEVEL2_KEEPFULLINVENTORY))
{ // Reduce all owned (visible) inventory to 1 item each
for (item = p->mo->Inventory; item != NULL; item = item->Inventory)
{
@@ -1424,7 +1430,7 @@ static void G_QueueBody (AActor *body)
//
void G_DoReborn (int playernum, bool freshbot)
{
- if (!multiplayer && !(level.flags & LEVEL_ALLOWRESPAWN))
+ if (!multiplayer && !(level.flags2 & LEVEL2_ALLOWRESPAWN))
{
if (BackupSaveName.Len() > 0 && FileExists (BackupSaveName.GetChars()))
{ // Load game from the last point it was saved
@@ -1574,128 +1580,6 @@ bool G_CheckSaveGameWads (PNGHandle *png, bool printwarn)
return true;
}
-static void WriteVars (FILE *file, SDWORD *vars, size_t count, DWORD id)
-{
- size_t i, j;
-
- for (i = 0; i < count; ++i)
- {
- if (vars[i] != 0)
- break;
- }
- if (i < count)
- {
- // Find last non-zero var. Anything beyond the last stored variable
- // will be zeroed at load time.
- for (j = count-1; j > i; --j)
- {
- if (vars[j] != 0)
- break;
- }
- FPNGChunkArchive arc (file, id);
- for (i = 0; i <= j; ++i)
- {
- DWORD var = vars[i];
- arc << var;
- }
- }
-}
-
-static void ReadVars (PNGHandle *png, SDWORD *vars, size_t count, DWORD id)
-{
- size_t len = M_FindPNGChunk (png, id);
- size_t used = 0;
-
- if (len != 0)
- {
- DWORD var;
- size_t i;
- FPNGChunkArchive arc (png->File->GetFile(), id, len);
- used = len / 4;
-
- for (i = 0; i < used; ++i)
- {
- arc << var;
- vars[i] = var;
- }
- png->File->ResetFilePtr();
- }
- if (used < count)
- {
- memset (&vars[used], 0, (count-used)*4);
- }
-}
-
-static void WriteArrayVars (FILE *file, FWorldGlobalArray *vars, unsigned int count, DWORD id)
-{
- unsigned int i, j;
-
- // Find the first non-empty array.
- for (i = 0; i < count; ++i)
- {
- if (vars[i].CountUsed() != 0)
- break;
- }
- if (i < count)
- {
- // Find last non-empty array. Anything beyond the last stored array
- // will be emptied at load time.
- for (j = count-1; j > i; --j)
- {
- if (vars[j].CountUsed() != 0)
- break;
- }
- FPNGChunkArchive arc (file, id);
- arc.WriteCount (i);
- arc.WriteCount (j);
- for (; i <= j; ++i)
- {
- arc.WriteCount (vars[i].CountUsed());
-
- FWorldGlobalArray::ConstIterator it(vars[i]);
- const FWorldGlobalArray::Pair *pair;
-
- while (it.NextPair (pair))
- {
- arc.WriteCount (pair->Key);
- arc.WriteCount (pair->Value);
- }
- }
- }
-}
-
-static void ReadArrayVars (PNGHandle *png, FWorldGlobalArray *vars, size_t count, DWORD id)
-{
- size_t len = M_FindPNGChunk (png, id);
- unsigned int i, k;
-
- for (i = 0; i < count; ++i)
- {
- vars[i].Clear ();
- }
-
- if (len != 0)
- {
- DWORD max, size;
- FPNGChunkArchive arc (png->File->GetFile(), id, len);
-
- i = arc.ReadCount ();
- max = arc.ReadCount ();
-
- for (; i <= max; ++i)
- {
- size = arc.ReadCount ();
- for (k = 0; k < size; ++k)
- {
- SDWORD key, val;
- key = arc.ReadCount();
- val = arc.ReadCount();
- vars[i].Insert (key, val);
- }
- }
- png->File->ResetFilePtr();
- }
-}
void G_DoLoadGame ()
{
@@ -1815,10 +1699,7 @@ void G_DoLoadGame ()
delete[] map;
savegamerestore = false;
- ReadVars (png, ACS_WorldVars, NUM_WORLDVARS, MAKE_ID('w','v','A','r'));
- ReadVars (png, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r'));
- ReadArrayVars (png, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r'));
- ReadArrayVars (png, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r'));
+ P_ReadACSVars(png);
NextSkill = -1;
if (M_FindPNGChunk (png, MAKE_ID('s','n','X','t')) == 1)
@@ -1980,7 +1861,7 @@ static void PutSaveComment (FILE *file)
// Get level name
//strcpy (comment, level.level_name);
- mysnprintf(comment, countof(comment), "%s - %s", level.mapname, level.level_name);
+ mysnprintf(comment, countof(comment), "%s - %s", level.mapname, level.LevelName.GetChars());
len = (WORD)strlen (comment);
comment[len] = '\n';
@@ -2064,10 +1945,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
FRandom::StaticWriteRNGState (stdfile);
P_WriteACSDefereds (stdfile);
- WriteVars (stdfile, ACS_WorldVars, NUM_WORLDVARS, MAKE_ID('w','v','A','r'));
- WriteVars (stdfile, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r'));
- WriteArrayVars (stdfile, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r'));
- WriteArrayVars (stdfile, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r'));
+ P_WriteACSVars(stdfile);
if (NextSkill != -1)
{
@@ -2506,11 +2384,11 @@ void G_DoPlayDemo (void)
demo_p = demobuffer = NULL;
if (singledemo)
{
- I_Error (eek);
+ I_Error ("%s", eek);
}
else
{
- Printf (PRINT_BOLD, eek);
+ Printf (PRINT_BOLD, "%s", eek);
gameaction = ga_nothing;
}
}
diff --git a/src/g_hexen/a_hexenspecialdecs.cpp b/src/g_hexen/a_hexenspecialdecs.cpp
index c8c64b20..d9a704a0 100644
--- a/src/g_hexen/a_hexenspecialdecs.cpp
+++ b/src/g_hexen/a_hexenspecialdecs.cpp
@@ -72,7 +72,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode)
S_Sound (mo, CHAN_BODY, "PotteryExplode", 1, ATTN_NORM);
if (self->args[0]>=0 && self->args[0]<=255 && SpawnableThings[self->args[0]])
{ // Spawn an item
- if (!((level.flags & LEVEL_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
+ if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
|| !(GetDefaultByType (SpawnableThings[self->args[0]])->flags3 & MF3_ISMONSTER))
{ // Only spawn monsters if not -nomonsters
Spawn (SpawnableThings[self->args[0]],
@@ -290,7 +290,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode)
}
if (self->args[0]>=0 && self->args[0]<=255 && SpawnableThings[self->args[0]])
{ // Spawn an item
- if (!((level.flags & LEVEL_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
+ if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
|| !(GetDefaultByType (SpawnableThings[self->args[0]])->flags3 & MF3_ISMONSTER))
{ // Only spawn monsters if not -nomonsters
Spawn (SpawnableThings[self->args[0]],
diff --git a/src/g_hub.cpp b/src/g_hub.cpp
index f5338250..162aacd1 100644
--- a/src/g_hub.cpp
+++ b/src/g_hub.cpp
@@ -127,17 +127,16 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
wbs->plyr[j].ssecret += hubdata[i].plyr[j].ssecret;
}
}
- if (cluster->clustername)
+ if (cluster->ClusterName.IsNotEmpty())
{
if (cluster->flags & CLUSTER_LOOKUPNAME)
{
- strncpy(level.level_name, GStrings(cluster->clustername), 64);
+ level.LevelName = GStrings(cluster->ClusterName);
}
else
{
- strncpy(level.level_name, cluster->clustername, 64);
+ level.LevelName = cluster->ClusterName;
}
- level.level_name[63]=0;
}
}
}
diff --git a/src/g_level.cpp b/src/g_level.cpp
index 4a5ede75..2ab13790 100644
--- a/src/g_level.cpp
+++ b/src/g_level.cpp
@@ -1,6 +1,6 @@
/*
** g_level.cpp
-** Parses MAPINFO and controls movement between levels
+** controls movement between levels
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
@@ -101,10 +101,6 @@ EXTERN_CVAR (Float, sv_gravity)
EXTERN_CVAR (Float, sv_aircontrol)
EXTERN_CVAR (Int, disableautosave)
-// Hey, GCC, these macros better be safe!
-#define lioffset(x) ((size_t)&((level_info_t*)1)->x - 1)
-#define cioffset(x) ((size_t)&((cluster_info_t*)1)->x - 1)
-
#define SNAP_ID MAKE_ID('s','n','A','p')
#define DSNP_ID MAKE_ID('d','s','N','p')
#define VIST_ID MAKE_ID('v','i','S','t')
@@ -112,58 +108,8 @@ EXTERN_CVAR (Int, disableautosave)
#define RCLS_ID MAKE_ID('r','c','L','s')
#define PCLS_ID MAKE_ID('p','c','L','s')
-static int FindEndSequence (int type, const char *picname);
static void SetEndSequence (char *nextmap, int type);
-static void InitPlayerClasses ();
-static void ParseEpisodeInfo (FScanner &sc);
-static void G_DoParseMapInfo (int lump);
-static void SetLevelNum (level_info_t *info, int num);
-static void ClearEpisodes ();
-static void ClearLevelInfoStrings (level_info_t *linfo);
-static void ClearClusterInfoStrings (cluster_info_t *cinfo);
-static void ParseSkill (FScanner &sc);
-static void G_VerifySkill();
-
-struct FOptionalMapinfoParser
-{
- const char *keyword;
- MIParseFunc parsefunc;
-};
-
-static TArray optmapinf(TArray::NoInit);
-
-
-void AddOptionalMapinfoParser(const char *keyword, MIParseFunc parsefunc)
-{
- FOptionalMapinfoParser mi;
-
- mi.keyword = keyword;
- mi.parsefunc = parsefunc;
- optmapinf.Push(mi);
-}
-
-static void ParseOptionalBlock(const char *keyword, FScanner &sc, level_info_t *info)
-{
- for(unsigned i=0;i wadclusterinfos;
-TArray wadlevelinfos;
-TArray AllSkills;
-
-// MAPINFO is parsed slightly differently when the map name is just a number.
-static bool HexenHack;
-
-static char unnamed[] = "Unnamed";
-static level_info_t TheDefaultLevelInfo =
-{
- "", // mapname
- 0, // levelnum
- "", // pname,
- "", // nextmap
- "", // secretmap
- "SKY1", // skypic1
- 0, // cluster
- 0, // partime
- 0, // sucktime
- 0, // flags
- NULL, // music
- unnamed, // level_name
- "COLORMAP", // fadetable
- +8, // WallVertLight
- -8, // WallHorizLight
- "", // [RC] F1
-};
-
-static cluster_info_t TheDefaultClusterInfo = { 0 };
-
-
-
-static const char *MapInfoTopLevel[] =
-{
- "map",
- "defaultmap",
- "clusterdef",
- "episode",
- "clearepisodes",
- "skill",
- "clearskills",
- "adddefaultmap",
- "gamedefaults",
- NULL
-};
-
-enum
-{
- MITL_MAP,
- MITL_DEFAULTMAP,
- MITL_CLUSTERDEF,
- MITL_EPISODE,
- MITL_CLEAREPISODES,
- MITL_SKILL,
- MITL_CLEARSKILLS,
- MITL_ADDDEFAULTMAP,
- MITL_GAMEDEFAULTS,
-};
-
-static const char *MapInfoMapLevel[] =
-{
- "levelnum",
- "next",
- "secretnext",
- "cluster",
- "sky1",
- "sky2",
- "fade",
- "outsidefog",
- "titlepatch",
- "par",
- "sucktime",
- "music",
- "nointermission",
- "intermission",
- "doublesky",
- "nosoundclipping",
- "allowmonstertelefrags",
- "map07special",
- "baronspecial",
- "cyberdemonspecial",
- "spidermastermindspecial",
- "minotaurspecial",
- "dsparilspecial",
- "ironlichspecial",
- "specialaction_exitlevel",
- "specialaction_opendoor",
- "specialaction_lowerfloor",
- "specialaction_killmonsters",
- "lightning",
- "fadetable",
- "evenlighting",
- "smoothlighting",
- "noautosequences",
- "autosequences",
- "forcenoskystretch",
- "skystretch",
- "allowfreelook",
- "nofreelook",
- "allowjump",
- "nojump",
- "fallingdamage", // Hexen falling damage
- "oldfallingdamage", // Lesser ZDoom falling damage
- "forcefallingdamage", // Skull Tag compatibility name for oldfallingdamage
- "strifefallingdamage", // Strife's falling damage is really unforgiving
- "nofallingdamage",
- "noallies",
- "cdtrack",
- "cdid",
- "cd_start_track",
- "cd_end1_track",
- "cd_end2_track",
- "cd_end3_track",
- "cd_intermission_track",
- "cd_title_track",
- "warptrans",
- "vertwallshade",
- "horizwallshade",
- "gravity",
- "aircontrol",
- "filterstarts",
- "activateowndeathspecials",
- "killeractivatesdeathspecials",
- "missilesactivateimpactlines",
- "missileshootersactivetimpactlines",
- "noinventorybar",
- "deathslideshow",
- "redirect",
- "strictmonsteractivation",
- "laxmonsteractivation",
- "additive_scrollers",
- "interpic",
- "exitpic",
- "enterpic",
- "intermusic",
- "airsupply",
- "specialaction",
- "keepfullinventory",
- "monsterfallingdamage",
- "nomonsterfallingdamage",
- "sndseq",
- "sndinfo",
- "soundinfo",
- "clipmidtextures",
- "wrapmidtextures",
- "allowcrouch",
- "nocrouch",
- "pausemusicinmenus",
- "compat_shorttex",
- "compat_stairs",
- "compat_limitpain",
- "compat_nopassover",
- "compat_notossdrops",
- "compat_useblocking",
- "compat_nodoorlight",
- "compat_ravenscroll",
- "compat_soundtarget",
- "compat_dehhealth",
- "compat_trace",
- "compat_dropoff",
- "compat_boomscroll",
- "compat_invisibility",
- "compat_silent_instant_floors",
- "compat_sectorsounds",
- "compat_missileclip",
- "bordertexture",
- "f1", // [RC] F1 help
- "noinfighting",
- "normalinfighting",
- "totalinfighting",
- "infiniteflightpowerup",
- "noinfiniteflightpowerup",
- "allowrespawn",
- "teamdamage",
- "teamplayon",
- "teamplayoff",
- "checkswitchrange",
- "nocheckswitchrange",
- "translator",
- "unfreezesingleplayerconversations",
- "nobotnodes",
- NULL
-};
-
-enum EMIType
-{
- MITYPE_EATNEXT,
- MITYPE_IGNORE,
- MITYPE_INT,
- MITYPE_FLOAT,
- MITYPE_HEX,
- MITYPE_COLOR,
- MITYPE_MAPNAME,
- MITYPE_LUMPNAME,
- MITYPE_SKY,
- MITYPE_SETFLAG,
- MITYPE_CLRFLAG,
- MITYPE_SCFLAGS,
- MITYPE_CLUSTER,
- MITYPE_STRING,
- MITYPE_MUSIC,
- MITYPE_RELLIGHT,
- MITYPE_CLRBYTES,
- MITYPE_REDIRECT,
- MITYPE_SPECIALACTION,
- MITYPE_COMPATFLAG,
- MITYPE_STRINGT,
-};
-
-struct MapInfoHandler
-{
- EMIType type;
- QWORD data1, data2;
-}
-MapHandlers[] =
-{
- { MITYPE_INT, lioffset(levelnum), 0 },
- { MITYPE_MAPNAME, lioffset(nextmap), 0 },
- { MITYPE_MAPNAME, lioffset(secretmap), 0 },
- { MITYPE_CLUSTER, lioffset(cluster), 0 },
- { MITYPE_SKY, lioffset(skypic1), lioffset(skyspeed1) },
- { MITYPE_SKY, lioffset(skypic2), lioffset(skyspeed2) },
- { MITYPE_COLOR, lioffset(fadeto), 0 },
- { MITYPE_COLOR, lioffset(outsidefog), 0 },
- { MITYPE_LUMPNAME, lioffset(pname), 0 },
- { MITYPE_INT, lioffset(partime), 0 },
- { MITYPE_INT, lioffset(sucktime), 0 },
- { MITYPE_MUSIC, lioffset(music), lioffset(musicorder) },
- { MITYPE_SETFLAG, LEVEL_NOINTERMISSION, 0 },
- { MITYPE_CLRFLAG, LEVEL_NOINTERMISSION, 0 },
- { MITYPE_SETFLAG, LEVEL_DOUBLESKY, 0 },
- { MITYPE_IGNORE, 0, 0 }, // was nosoundclipping
- { MITYPE_SETFLAG, LEVEL_MONSTERSTELEFRAG, 0 },
- { MITYPE_SETFLAG, LEVEL_MAP07SPECIAL, 0 },
- { MITYPE_SETFLAG, LEVEL_BRUISERSPECIAL, 0 },
- { MITYPE_SETFLAG, LEVEL_CYBORGSPECIAL, 0 },
- { MITYPE_SETFLAG, LEVEL_SPIDERSPECIAL, 0 },
- { MITYPE_SETFLAG, LEVEL_MINOTAURSPECIAL, 0 },
- { MITYPE_SETFLAG, LEVEL_SORCERER2SPECIAL, 0 },
- { MITYPE_SETFLAG, LEVEL_HEADSPECIAL, 0 },
- { MITYPE_SCFLAGS, 0, ~LEVEL_SPECACTIONSMASK },
- { MITYPE_SCFLAGS, LEVEL_SPECOPENDOOR, ~LEVEL_SPECACTIONSMASK },
- { MITYPE_SCFLAGS, LEVEL_SPECLOWERFLOOR, ~LEVEL_SPECACTIONSMASK },
- { MITYPE_SETFLAG, LEVEL_SPECKILLMONSTERS, 0 },
- { MITYPE_SETFLAG, LEVEL_STARTLIGHTNING, 0 },
- { MITYPE_LUMPNAME, lioffset(fadetable), 0 },
- { MITYPE_CLRBYTES, lioffset(WallVertLight), lioffset(WallHorizLight) },
- { MITYPE_SETFLAG, LEVEL_SMOOTHLIGHTING, 0 },
- { MITYPE_SETFLAG, LEVEL_SNDSEQTOTALCTRL, 0 },
- { MITYPE_CLRFLAG, LEVEL_SNDSEQTOTALCTRL, 0 },
- { MITYPE_SETFLAG, LEVEL_FORCENOSKYSTRETCH, 0 },
- { MITYPE_CLRFLAG, LEVEL_FORCENOSKYSTRETCH, 0 },
- { MITYPE_SCFLAGS, LEVEL_FREELOOK_YES, ~LEVEL_FREELOOK_NO },
- { MITYPE_SCFLAGS, LEVEL_FREELOOK_NO, ~LEVEL_FREELOOK_YES },
- { MITYPE_CLRFLAG, LEVEL_JUMP_NO, 0 },
- { MITYPE_SETFLAG, LEVEL_JUMP_NO, 0 },
- { MITYPE_SCFLAGS, LEVEL_FALLDMG_HX, ~LEVEL_FALLDMG_ZD },
- { MITYPE_SCFLAGS, LEVEL_FALLDMG_ZD, ~LEVEL_FALLDMG_HX },
- { MITYPE_SCFLAGS, LEVEL_FALLDMG_ZD, ~LEVEL_FALLDMG_HX },
- { MITYPE_SETFLAG, LEVEL_FALLDMG_ZD|LEVEL_FALLDMG_HX, 0 },
- { MITYPE_SCFLAGS, 0, ~(LEVEL_FALLDMG_ZD|LEVEL_FALLDMG_HX) },
- { MITYPE_SETFLAG, LEVEL_NOALLIES, 0 },
- { MITYPE_INT, lioffset(cdtrack), 0 },
- { MITYPE_HEX, lioffset(cdid), 0 },
- { MITYPE_EATNEXT, 0, 0 },
- { MITYPE_EATNEXT, 0, 0 },
- { MITYPE_EATNEXT, 0, 0 },
- { MITYPE_EATNEXT, 0, 0 },
- { MITYPE_EATNEXT, 0, 0 },
- { MITYPE_EATNEXT, 0, 0 },
- { MITYPE_INT, lioffset(WarpTrans), 0 },
- { MITYPE_RELLIGHT, lioffset(WallVertLight), 0 },
- { MITYPE_RELLIGHT, lioffset(WallHorizLight), 0 },
- { MITYPE_FLOAT, lioffset(gravity), 0 },
- { MITYPE_FLOAT, lioffset(aircontrol), 0 },
- { MITYPE_SETFLAG, LEVEL_FILTERSTARTS, 0 },
- { MITYPE_SETFLAG, LEVEL_ACTOWNSPECIAL, 0 },
- { MITYPE_CLRFLAG, LEVEL_ACTOWNSPECIAL, 0 },
- { MITYPE_SETFLAG, LEVEL_MISSILESACTIVATEIMPACT, 0 },
- { MITYPE_CLRFLAG, LEVEL_MISSILESACTIVATEIMPACT, 0 },
- { MITYPE_SETFLAG, LEVEL_NOINVENTORYBAR, 0 },
- { MITYPE_SETFLAG, LEVEL_DEATHSLIDESHOW, 0 },
- { MITYPE_REDIRECT, lioffset(RedirectMap), 0 },
- { MITYPE_CLRFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
- { MITYPE_SETFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
- { MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
- { MITYPE_STRING, lioffset(exitpic), 0 },
- { MITYPE_STRING, lioffset(exitpic), 0 },
- { MITYPE_STRING, lioffset(enterpic), 0 },
- { MITYPE_MUSIC, lioffset(intermusic), lioffset(intermusicorder) },
- { MITYPE_INT, lioffset(airsupply), 0 },
- { MITYPE_SPECIALACTION, lioffset(specialactions), 0 },
- { MITYPE_SETFLAG, LEVEL_KEEPFULLINVENTORY, 0 },
- { MITYPE_SETFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 },
- { MITYPE_CLRFLAG, LEVEL_MONSTERFALLINGDAMAGE, 0 },
- { MITYPE_STRING, lioffset(sndseq), 0 },
- { MITYPE_STRING, lioffset(soundinfo), 0 },
- { MITYPE_STRING, lioffset(soundinfo), 0 },
- { MITYPE_SETFLAG, LEVEL_CLIPMIDTEX, 0 },
- { MITYPE_SETFLAG, LEVEL_WRAPMIDTEX, 0 },
- { MITYPE_CLRFLAG, LEVEL_CROUCH_NO, 0 },
- { MITYPE_SETFLAG, LEVEL_CROUCH_NO, 0 },
- { MITYPE_SCFLAGS, LEVEL_PAUSE_MUSIC_IN_MENUS, 0 },
- { MITYPE_COMPATFLAG, COMPATF_SHORTTEX},
- { MITYPE_COMPATFLAG, COMPATF_STAIRINDEX},
- { MITYPE_COMPATFLAG, COMPATF_LIMITPAIN},
- { MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ},
- { MITYPE_COMPATFLAG, COMPATF_NOTOSSDROPS},
- { MITYPE_COMPATFLAG, COMPATF_USEBLOCKING},
- { MITYPE_COMPATFLAG, COMPATF_NODOORLIGHT},
- { MITYPE_COMPATFLAG, COMPATF_RAVENSCROLL},
- { MITYPE_COMPATFLAG, COMPATF_SOUNDTARGET},
- { MITYPE_COMPATFLAG, COMPATF_DEHHEALTH},
- { MITYPE_COMPATFLAG, COMPATF_TRACE},
- { MITYPE_COMPATFLAG, COMPATF_DROPOFF},
- { MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
- { MITYPE_COMPATFLAG, COMPATF_INVISIBILITY},
- { MITYPE_COMPATFLAG, COMPATF_SILENT_INSTANT_FLOORS},
- { MITYPE_COMPATFLAG, COMPATF_SECTORSOUNDS},
- { MITYPE_COMPATFLAG, COMPATF_MISSILECLIP},
- { MITYPE_LUMPNAME, lioffset(bordertexture), 0 },
- { MITYPE_LUMPNAME, lioffset(f1), 0, },
- { MITYPE_SCFLAGS, LEVEL_NOINFIGHTING, ~LEVEL_TOTALINFIGHTING },
- { MITYPE_SCFLAGS, 0, ~(LEVEL_NOINFIGHTING|LEVEL_TOTALINFIGHTING)},
- { MITYPE_SCFLAGS, LEVEL_TOTALINFIGHTING, ~LEVEL_NOINFIGHTING },
- { MITYPE_SETFLAG, LEVEL_INFINITE_FLIGHT, 0 },
- { MITYPE_CLRFLAG, LEVEL_INFINITE_FLIGHT, 0 },
- { MITYPE_SETFLAG, LEVEL_ALLOWRESPAWN, 0 },
- { MITYPE_FLOAT, lioffset(teamdamage), 0 },
- { MITYPE_SCFLAGS, LEVEL_FORCETEAMPLAYON, ~LEVEL_FORCETEAMPLAYOFF },
- { MITYPE_SCFLAGS, LEVEL_FORCETEAMPLAYOFF, ~LEVEL_FORCETEAMPLAYON },
- { MITYPE_SETFLAG, LEVEL_CHECKSWITCHRANGE, 0 },
- { MITYPE_CLRFLAG, LEVEL_CHECKSWITCHRANGE, 0 },
- { MITYPE_STRING, lioffset(translator), 0 },
- { MITYPE_SETFLAG, LEVEL_CONV_SINGLE_UNFREEZE, 0 },
- { MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
-};
-
-static const char *MapInfoClusterLevel[] =
-{
- "entertext",
- "exittext",
- "music",
- "flat",
- "pic",
- "hub",
- "cdtrack",
- "cdid",
- "entertextislump",
- "exittextislump",
- "name",
- NULL
-};
-
-MapInfoHandler ClusterHandlers[] =
-{
- { MITYPE_STRINGT, cioffset(entertext), CLUSTER_LOOKUPENTERTEXT },
- { MITYPE_STRINGT, cioffset(exittext), CLUSTER_LOOKUPEXITTEXT },
- { MITYPE_MUSIC, cioffset(messagemusic), cioffset(musicorder) },
- { MITYPE_LUMPNAME, cioffset(finaleflat), 0 },
- { MITYPE_LUMPNAME, cioffset(finaleflat), CLUSTER_FINALEPIC },
- { MITYPE_SETFLAG, CLUSTER_HUB, 0 },
- { MITYPE_INT, cioffset(cdtrack), 0 },
- { MITYPE_HEX, cioffset(cdid), 0 },
- { MITYPE_SETFLAG, CLUSTER_ENTERTEXTINLUMP, 0 },
- { MITYPE_SETFLAG, CLUSTER_EXITTEXTINLUMP, 0 },
- { MITYPE_STRINGT, cioffset(clustername), CLUSTER_LOOKUPNAME },
-};
-
-static void ParseMapInfoLower (FScanner &sc,
- MapInfoHandler *handlers,
- const char *strings[],
- level_info_t *levelinfo,
- cluster_info_t *clusterinfo,
- QWORD levelflags);
-
-static int FindWadLevelInfo (const char *name)
-{
- for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
- if (!strnicmp (name, wadlevelinfos[i].mapname, 8))
- return i;
-
- return -1;
-}
-
-static int FindWadClusterInfo (int cluster)
-{
- for (unsigned int i = 0; i < wadclusterinfos.Size(); i++)
- if (wadclusterinfos[i].cluster == cluster)
- return i;
-
- return -1;
-}
-
-static void SetLevelDefaults (level_info_t *levelinfo)
-{
- memset (levelinfo, 0, sizeof(*levelinfo));
- levelinfo->snapshot = NULL;
- levelinfo->outsidefog = 0xff000000;
- levelinfo->WallHorizLight = -8;
- levelinfo->WallVertLight = +8;
- strncpy (levelinfo->fadetable, "COLORMAP", 8);
- strcpy (levelinfo->skypic1, "-NOFLAT-");
- strcpy (levelinfo->skypic2, "-NOFLAT-");
- strcpy (levelinfo->bordertexture, gameinfo.borderFlat);
- if (gameinfo.gametype != GAME_Hexen)
- {
- // For maps without a BEHAVIOR, this will be cleared.
- levelinfo->flags |= LEVEL_LAXMONSTERACTIVATION;
- }
- levelinfo->airsupply = 10;
-}
-
+//==========================================================================
//
-// G_ParseMapInfo
-// Parses the MAPINFO lumps of all loaded WADs and generates
-// data for wadlevelinfos and wadclusterinfos.
//
-void G_ParseMapInfo ()
-{
- int lump, lastlump = 0;
+//==========================================================================
- gl_AddMapinfoParser() ;
-
- atterm (G_UnloadMapInfo);
-
- SetLevelDefaults (&gamedefaults);
-
- // Parse the default MAPINFO for the current game.
- for(int i=0; i<2; i++)
- {
- if (gameinfo.mapinfo[i] != NULL)
- {
- G_DoParseMapInfo(Wads.GetNumForFullName(gameinfo.mapinfo[i]));
- }
- }
-
- // Parse any extra MAPINFOs.
- while ((lump = Wads.FindLump ("MAPINFO", &lastlump)) != -1)
- {
- G_DoParseMapInfo (lump);
- }
- EndSequences.ShrinkToFit ();
-
- if (EpiDef.numitems == 0)
- {
- I_FatalError ("You cannot use clearepisodes in a MAPINFO if you do not define any new episodes after it.");
- }
- if (AllSkills.Size()==0)
- {
- I_FatalError ("You cannot use clearskills in a MAPINFO if you do not define any new skills after it.");
- }
- ClearLevelInfoStrings (&gamedefaults);
-}
-
-static FSpecialAction *CopySpecialActions(FSpecialAction *spec)
-{
- FSpecialAction **pSpec = &spec;
-
- while (*pSpec)
- {
- FSpecialAction *newspec = new FSpecialAction;
- *newspec = **pSpec;
- *pSpec = newspec;
- pSpec = &newspec->Next;
- }
- return spec;
-}
-
-static FOptionalMapinfoData *CopyOptData(FOptionalMapinfoData *opdata)
-{
- FOptionalMapinfoData **opt = &opdata;
-
- while (*opt)
- {
- FOptionalMapinfoData *newop = (*opt)->Clone();
- *opt = newop;
- opt = &newop->Next;
- }
- return opdata;
-}
-
-static void CopyString (char *& string)
-{
- if (string != NULL)
- string = copystring(string);
-}
-
-static void SafeDelete(char *&string)
-{
- if (string != NULL)
- {
- delete[] string;
- string = NULL;
- }
-}
-
-static void ClearLevelInfoStrings(level_info_t *linfo)
-{
- SafeDelete(linfo->music);
- SafeDelete(linfo->intermusic);
- SafeDelete(linfo->level_name);
- SafeDelete(linfo->translator);
- SafeDelete(linfo->enterpic);
- SafeDelete(linfo->exitpic);
- SafeDelete(linfo->soundinfo);
- SafeDelete(linfo->sndseq);
- for (FSpecialAction *spac = linfo->specialactions; spac != NULL; )
- {
- FSpecialAction *next = spac->Next;
- delete spac;
- spac = next;
- }
- for (FOptionalMapinfoData *spac = linfo->opdata; spac != NULL; )
- {
- FOptionalMapinfoData *next = spac->Next;
- delete spac;
- spac = next;
- }
-}
-
-static void ClearClusterInfoStrings(cluster_info_t *cinfo)
-{
- SafeDelete(cinfo->exittext);
- SafeDelete(cinfo->entertext);
- SafeDelete(cinfo->messagemusic);
- SafeDelete(cinfo->clustername);
-}
-
-static void CopyLevelInfo(level_info_t *levelinfo, level_info_t *from)
-{
- memcpy (levelinfo, from, sizeof(*levelinfo));
- CopyString(levelinfo->music);
- CopyString(levelinfo->intermusic);
- CopyString(levelinfo->translator);
- CopyString(levelinfo->enterpic);
- CopyString(levelinfo->exitpic);
- CopyString(levelinfo->soundinfo);
- CopyString(levelinfo->sndseq);
- levelinfo->specialactions = CopySpecialActions(levelinfo->specialactions);
- levelinfo->opdata = CopyOptData(levelinfo->opdata);
-}
-
-
-static void G_DoParseMapInfo (int lump)
-{
- level_info_t defaultinfo;
- level_info_t *levelinfo;
- int levelindex;
- cluster_info_t *clusterinfo;
- int clusterindex;
- QWORD levelflags;
-
- FScanner sc(lump);
-
- CopyLevelInfo(&defaultinfo, &gamedefaults);
- HexenHack = false;
-
- while (sc.GetString ())
- {
- switch (sc.MustMatchString (MapInfoTopLevel))
- {
- case MITL_GAMEDEFAULTS:
- ClearLevelInfoStrings(&gamedefaults);
- SetLevelDefaults (&gamedefaults);
- ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, &gamedefaults, NULL, defaultinfo.flags);
- ClearLevelInfoStrings(&defaultinfo);
- CopyLevelInfo(&defaultinfo, &gamedefaults);
- break;
-
- case MITL_DEFAULTMAP:
- ClearLevelInfoStrings(&defaultinfo);
- SetLevelDefaults (&defaultinfo);
- ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, &defaultinfo, NULL, defaultinfo.flags);
- break;
-
- case MITL_ADDDEFAULTMAP:
- // Same as above but adds to the existing definitions instead of replacing them completely
- ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, &defaultinfo, NULL, defaultinfo.flags);
- break;
-
- case MITL_MAP: // map
- {
- char maptemp[8];
- const char *mapname;
-
- levelflags = defaultinfo.flags;
- sc.MustGetString ();
- mapname = sc.String;
- if (IsNum (mapname))
- { // MAPNAME is a number; assume a Hexen wad
- int mapnum = atoi (mapname);
- mysnprintf (maptemp, countof(maptemp), "MAP%02d", mapnum);
- mapname = maptemp;
- HexenHack = true;
- // Hexen levels are automatically nointermission,
- // no auto sound sequences, falling damage,
- // monsters activate their own specials, and missiles
- // are always the activators of impact lines.
- levelflags |= LEVEL_NOINTERMISSION
- | LEVEL_SNDSEQTOTALCTRL
- | LEVEL_FALLDMG_HX
- | LEVEL_ACTOWNSPECIAL
- | LEVEL_MISSILESACTIVATEIMPACT
- | LEVEL_INFINITE_FLIGHT
- | LEVEL_MONSTERFALLINGDAMAGE
- | LEVEL_HEXENHACK;
- }
- levelindex = FindWadLevelInfo (mapname);
- if (levelindex == -1)
- {
- levelindex = wadlevelinfos.Reserve(1);
- }
- else
- {
- ClearLevelInfoStrings (&wadlevelinfos[levelindex]);
- }
- levelinfo = &wadlevelinfos[levelindex];
- CopyLevelInfo(levelinfo, &defaultinfo);
- if (HexenHack)
- {
- levelinfo->WallHorizLight = levelinfo->WallVertLight = 0;
- }
- uppercopy (levelinfo->mapname, mapname);
- sc.MustGetString ();
- if (sc.String[0] == '$')
- {
- // For consistency with other definitions allow $Stringtablename here, too.
- levelflags |= LEVEL_LOOKUPLEVELNAME;
- ReplaceString (&levelinfo->level_name, sc.String + 1);
- }
- else
- {
- if (sc.Compare ("lookup"))
- {
- sc.MustGetString ();
- levelflags |= LEVEL_LOOKUPLEVELNAME;
- }
- ReplaceString (&levelinfo->level_name, sc.String);
- }
- // Set up levelnum now so that you can use Teleport_NewMap specials
- // to teleport to maps with standard names without needing a levelnum.
- if (!strnicmp (levelinfo->mapname, "MAP", 3) && levelinfo->mapname[5] == 0)
- {
- int mapnum = atoi (levelinfo->mapname + 3);
-
- if (mapnum >= 1 && mapnum <= 99)
- levelinfo->levelnum = mapnum;
- }
- else if (levelinfo->mapname[0] == 'E' &&
- levelinfo->mapname[1] >= '0' && levelinfo->mapname[1] <= '9' &&
- levelinfo->mapname[2] == 'M' &&
- levelinfo->mapname[3] >= '0' && levelinfo->mapname[3] <= '9')
- {
- int epinum = levelinfo->mapname[1] - '1';
- int mapnum = levelinfo->mapname[3] - '0';
- levelinfo->levelnum = epinum*10 + mapnum;
- }
- ParseMapInfoLower (sc, MapHandlers, MapInfoMapLevel, levelinfo, NULL, levelflags);
- // When the second sky is -NOFLAT-, make it a copy of the first sky
- if (strcmp (levelinfo->skypic2, "-NOFLAT-") == 0)
- {
- strcpy (levelinfo->skypic2, levelinfo->skypic1);
- }
- SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
- /* can't do this here.
- if (levelinfo->pname[0] != 0)
- {
- if (!TexMan.CheckForTexture(levelinfo->pname, FTexture::TEX_MiscPatch).Exists())
- {
- levelinfo->pname[0] = 0;
- }
- }
- */
- break;
- }
-
- case MITL_CLUSTERDEF: // clusterdef
- sc.MustGetNumber ();
- clusterindex = FindWadClusterInfo (sc.Number);
- if (clusterindex == -1)
- {
- clusterindex = wadclusterinfos.Reserve(1);
- clusterinfo = &wadclusterinfos[clusterindex];
- }
- else
- {
- clusterinfo = &wadclusterinfos[clusterindex];
- ClearClusterInfoStrings(clusterinfo);
- }
- memset (clusterinfo, 0, sizeof(cluster_info_t));
- clusterinfo->cluster = sc.Number;
- ParseMapInfoLower (sc, ClusterHandlers, MapInfoClusterLevel, NULL, clusterinfo, 0);
- break;
-
- case MITL_EPISODE:
- ParseEpisodeInfo(sc);
- break;
-
- case MITL_CLEAREPISODES:
- ClearEpisodes();
- break;
-
- case MITL_SKILL:
- ParseSkill(sc);
- break;
-
- case MITL_CLEARSKILLS:
- AllSkills.Clear();
- break;
-
- }
- }
- ClearLevelInfoStrings(&defaultinfo);
-}
-
-static void ClearEpisodes()
-{
- for (int i = 0; i < EpiDef.numitems; ++i)
- {
- delete[] const_cast(EpisodeMenu[i].name);
- EpisodeMenu[i].name = NULL;
- }
- EpiDef.numitems = 0;
-}
-
-static void ParseMapInfoLower (FScanner &sc,
- MapInfoHandler *handlers,
- const char *strings[],
- level_info_t *levelinfo,
- cluster_info_t *clusterinfo,
- QWORD flags)
-{
- int entry;
- MapInfoHandler *handler;
- BYTE *info;
-
- info = levelinfo ? (BYTE *)levelinfo : (BYTE *)clusterinfo;
-
- while (sc.GetString ())
- {
- if (sc.MatchString (MapInfoTopLevel) != -1)
- {
- sc.UnGet ();
- break;
- }
- entry = sc.MatchString (strings);
-
- if (entry == -1)
- {
- FString keyword = sc.String;
- sc.MustGetString();
- if (levelinfo != NULL)
- {
- if (sc.Compare("{"))
- {
- ParseOptionalBlock(keyword, sc, levelinfo);
- continue;
- }
- }
- sc.ScriptError("Unknown keyword '%s'", keyword.GetChars());
- }
-
- handler = handlers + entry;
- switch (handler->type)
- {
- case MITYPE_EATNEXT:
- sc.MustGetString ();
- break;
-
- case MITYPE_IGNORE:
- break;
-
- case MITYPE_INT:
- sc.MustGetNumber ();
- *((int *)(info + handler->data1)) = sc.Number;
- break;
-
- case MITYPE_FLOAT:
- sc.MustGetFloat ();
- *((float *)(info + handler->data1)) = sc.Float;
- break;
-
- case MITYPE_HEX:
- sc.MustGetString ();
- *((int *)(info + handler->data1)) = strtoul (sc.String, NULL, 16);
- break;
-
- case MITYPE_COLOR:
- sc.MustGetString ();
- *((DWORD *)(info + handler->data1)) = V_GetColor (NULL, sc.String);
- break;
-
- case MITYPE_REDIRECT:
- sc.MustGetString ();
- levelinfo->RedirectType = sc.String;
- // Intentional fall-through
-
- case MITYPE_MAPNAME: {
- EndSequence newSeq;
- bool useseq = false;
- char maptemp[8];
- const char *mapname;
-
- sc.MustGetString ();
- mapname = sc.String;
- if (IsNum (mapname))
- {
- int mapnum = atoi (mapname);
-
- if (HexenHack)
- {
- mysnprintf (maptemp, countof(maptemp), "&wt@%02d", mapnum);
- }
- else
- {
- mysnprintf (maptemp, countof(maptemp), "MAP%02d", mapnum);
- }
- mapname = maptemp;
- }
- if (stricmp (mapname, "endgame") == 0)
- {
- newSeq.Advanced = true;
- newSeq.EndType = END_Pic1;
- newSeq.PlayTheEnd = false;
- newSeq.MusicLooping = true;
- sc.MustGetStringName("{");
- while (!sc.CheckString("}"))
- {
- sc.MustGetString();
- if (sc.Compare("pic"))
- {
- sc.MustGetString();
- newSeq.EndType = END_Pic;
- newSeq.PicName = sc.String;
- }
- else if (sc.Compare("hscroll"))
- {
- newSeq.EndType = END_Bunny;
- sc.MustGetString();
- newSeq.PicName = sc.String;
- sc.MustGetString();
- newSeq.PicName2 = sc.String;
- if (sc.CheckNumber())
- newSeq.PlayTheEnd = !!sc.Number;
- }
- else if (sc.Compare("vscroll"))
- {
- newSeq.EndType = END_Demon;
- sc.MustGetString();
- newSeq.PicName = sc.String;
- sc.MustGetString();
- newSeq.PicName2 = sc.String;
- }
- else if (sc.Compare("cast"))
- {
- newSeq.EndType = END_Cast;
- }
- else if (sc.Compare("music"))
- {
- sc.MustGetString();
- newSeq.Music = sc.String;
- if (sc.CheckNumber())
- {
- newSeq.MusicLooping = !!sc.Number;
- }
- }
- }
- useseq = true;
- }
- else if (strnicmp (mapname, "EndGame", 7) == 0)
- {
- int type;
- switch (sc.String[7])
- {
- case '1': type = END_Pic1; break;
- case '2': type = END_Pic2; break;
- case '3': type = END_Bunny; break;
- case 'C': type = END_Cast; break;
- case 'W': type = END_Underwater; break;
- case 'S': type = END_Strife; break;
- default: type = END_Pic3; break;
- }
- newSeq.EndType = type;
- useseq = true;
- }
- else if (stricmp (mapname, "endpic") == 0)
- {
- sc.MustGetString ();
- newSeq.EndType = END_Pic;
- newSeq.PicName = sc.String;
- useseq = true;
- }
- else if (stricmp (mapname, "endbunny") == 0)
- {
- newSeq.EndType = END_Bunny;
- useseq = true;
- }
- else if (stricmp (mapname, "endcast") == 0)
- {
- newSeq.EndType = END_Cast;
- useseq = true;
- }
- else if (stricmp (mapname, "enddemon") == 0)
- {
- newSeq.EndType = END_Demon;
- useseq = true;
- }
- else if (stricmp (mapname, "endchess") == 0)
- {
- newSeq.EndType = END_Chess;
- useseq = true;
- }
- else if (stricmp (mapname, "endunderwater") == 0)
- {
- newSeq.EndType = END_Underwater;
- useseq = true;
- }
- else if (stricmp (mapname, "endbuystrife") == 0)
- {
- newSeq.EndType = END_BuyStrife;
- useseq = true;
- }
- else
- {
- strncpy ((char *)(info + handler->data1), mapname, 8);
- }
- if (useseq)
- {
- int seqnum = -1;
-
- if (!newSeq.Advanced)
- {
- seqnum = FindEndSequence (newSeq.EndType, newSeq.PicName);
- }
-
- if (seqnum == -1)
- {
- seqnum = (int)EndSequences.Push (newSeq);
- }
- strcpy ((char *)(info + handler->data1), "enDSeQ");
- *((WORD *)(info + handler->data1 + 6)) = (WORD)seqnum;
- }
- break;
- }
-
- case MITYPE_LUMPNAME:
- sc.MustGetString ();
- uppercopy ((char *)(info + handler->data1), sc.String);
- flags |= handler->data2;
- break;
-
- case MITYPE_SKY:
- sc.MustGetString (); // get texture name;
- uppercopy ((char *)(info + handler->data1), sc.String);
- sc.MustGetFloat (); // get scroll speed
- if (HexenHack)
- {
- sc.Float /= 256;
- }
- // Sky scroll speed is specified as pixels per tic, but we
- // want pixels per millisecond.
- *((float *)(info + handler->data2)) = sc.Float * 35 / 1000;
- break;
-
- case MITYPE_SETFLAG:
- flags |= handler->data1;
- flags |= handler->data2;
- break;
-
- case MITYPE_CLRFLAG:
- flags &= ~handler->data1;
- flags |= handler->data2;
- break;
-
- case MITYPE_SCFLAGS:
- flags = (flags & handler->data2) | handler->data1;
- break;
-
- case MITYPE_CLUSTER:
- sc.MustGetNumber ();
- *((int *)(info + handler->data1)) = sc.Number;
- // If this cluster hasn't been defined yet, add it. This is especially needed
- // for Hexen, because it doesn't have clusterdefs. If we don't do this, every
- // level on Hexen will sometimes be considered as being on the same hub,
- // depending on the check done.
- if (FindWadClusterInfo (sc.Number) == -1)
- {
- unsigned int clusterindex = wadclusterinfos.Reserve(1);
- clusterinfo = &wadclusterinfos[clusterindex];
- memset (clusterinfo, 0, sizeof(cluster_info_t));
- clusterinfo->cluster = sc.Number;
- if (HexenHack)
- {
- clusterinfo->flags |= CLUSTER_HUB;
- }
- }
- break;
-
- case MITYPE_STRINGT:
- sc.MustGetString ();
- if (sc.String[0] == '$')
- {
- // For consistency with other definitions allow $Stringtablename here, too.
- flags |= handler->data2;
- ReplaceString ((char **)(info + handler->data1), sc.String+1);
- }
- else
- {
- if (sc.Compare ("lookup"))
- {
- flags |= handler->data2;
- sc.MustGetString ();
- }
- ReplaceString ((char **)(info + handler->data1), sc.String);
- }
- break;
-
- case MITYPE_STRING:
- sc.MustGetString();
- ReplaceString ((char **)(info + handler->data1), sc.String);
- break;
-
- case MITYPE_MUSIC:
- sc.MustGetString ();
- {
- char *colon = strchr (sc.String, ':');
- if (colon)
- {
- *colon = 0;
- }
- ReplaceString ((char **)(info + handler->data1), sc.String);
- *((int *)(info + handler->data2)) = colon ? atoi (colon + 1) : 0;
- if (levelinfo != NULL)
- {
- // Flag the level so that the $MAP command doesn't override this.
- flags|=LEVEL_MUSICDEFINED;
- }
- }
- break;
-
- case MITYPE_RELLIGHT:
- sc.MustGetNumber ();
- *((SBYTE *)(info + handler->data1)) = (SBYTE)clamp (sc.Number / 2, -128, 127);
- break;
-
- case MITYPE_CLRBYTES:
- *((BYTE *)(info + handler->data1)) = 0;
- *((BYTE *)(info + handler->data2)) = 0;
- break;
-
- case MITYPE_SPECIALACTION:
- {
- FSpecialAction **so = (FSpecialAction**)(info + handler->data1);
- FSpecialAction *sa = new FSpecialAction;
- int min_arg, max_arg;
- sa->Next = *so;
- *so = sa;
- sc.SetCMode(true);
- sc.MustGetString();
- sa->Type = FName(sc.String);
- sc.CheckString(",");
- sc.MustGetString();
- sa->Action = P_FindLineSpecial(sc.String, &min_arg, &max_arg);
- if (sa->Action == 0 || min_arg < 0)
- {
- sc.ScriptError("Unknown specialaction '%s'");
- }
- int j = 0;
- while (j < 5 && sc.CheckString(","))
- {
- sc.MustGetNumber();
- sa->Args[j++] = sc.Number;
- }
- /*
- if (jmax)
- {
- // Should be an error but can't for compatibility.
- }
- */
- sc.SetCMode(false);
- }
- break;
-
- case MITYPE_COMPATFLAG:
- if (!sc.CheckNumber()) sc.Number = 1;
-
- if (levelinfo != NULL)
- {
- if (sc.Number) levelinfo->compatflags |= (DWORD)handler->data1;
- else levelinfo->compatflags &= ~ (DWORD)handler->data1;
- levelinfo->compatmask |= (DWORD)handler->data1;
- }
- break;
- }
- }
- if (levelinfo)
- {
- levelinfo->flags = flags;
- }
- else
- {
- clusterinfo->flags = flags;
- }
-}
-
-// Episode definitions start with the header "episode "
-// and then can be followed by any of the following:
-//
-// name "Episode name as text"
-// picname "Picture to display the episode name"
-// key "Shortcut key for the menu"
-// noskillmenu
-// remove
-
-static void ParseEpisodeInfo (FScanner &sc)
-{
- int i;
- char map[9];
- char *pic = NULL;
- bool picisgfx = false; // Shut up, GCC!!!!
- bool remove = false;
- char key = 0;
- bool noskill = false;
- bool optional = false;
- bool extended = false;
-
- // Get map name
- sc.MustGetString ();
- uppercopy (map, sc.String);
- map[8] = 0;
-
- sc.MustGetString ();
- if (sc.Compare ("teaser"))
- {
- sc.MustGetString ();
- if (gameinfo.flags & GI_SHAREWARE)
- {
- uppercopy (map, sc.String);
- }
- sc.MustGetString ();
- }
- do
- {
- if (sc.Compare ("optional"))
- {
- // For M4 in Doom
- optional = true;
- }
- else if (sc.Compare ("extended"))
- {
- // For M4 and M5 in Heretic
- extended = true;
- }
- else if (sc.Compare ("name"))
- {
- sc.MustGetString ();
- ReplaceString (&pic, sc.String);
- picisgfx = false;
- }
- else if (sc.Compare ("picname"))
- {
- sc.MustGetString ();
- ReplaceString (&pic, sc.String);
- picisgfx = true;
- }
- else if (sc.Compare ("remove"))
- {
- remove = true;
- }
- else if (sc.Compare ("key"))
- {
- sc.MustGetString ();
- key = sc.String[0];
- }
- else if (sc.Compare("noskillmenu"))
- {
- noskill = true;
- }
- else
- {
- sc.UnGet ();
- break;
- }
- }
- while (sc.GetString ());
-
- if (extended && !(gameinfo.flags & GI_MENUHACK_EXTENDED))
- { // If the episode is for the extended Heretic, but this is
- // not the extended Heretic, ignore it.
- return;
- }
-
- if (optional && !remove)
- {
- if (!P_CheckMapData(map))
- {
- // If the episode is optional and the map does not exist
- // just ignore this episode definition.
- return;
- }
- }
-
-
- for (i = 0; i < EpiDef.numitems; ++i)
- {
- if (strncmp (EpisodeMaps[i], map, 8) == 0)
- {
- break;
- }
- }
-
- if (remove)
- {
- // If the remove property is given for an episode, remove it.
- if (i < EpiDef.numitems)
- {
- if (i+1 < EpiDef.numitems)
- {
- memmove (&EpisodeMaps[i], &EpisodeMaps[i+1],
- sizeof(EpisodeMaps[0])*(EpiDef.numitems - i - 1));
- memmove (&EpisodeMenu[i], &EpisodeMenu[i+1],
- sizeof(EpisodeMenu[0])*(EpiDef.numitems - i - 1));
- memmove (&EpisodeNoSkill[i], &EpisodeNoSkill[i+1],
- sizeof(EpisodeNoSkill[0])*(EpiDef.numitems - i - 1));
- }
- EpiDef.numitems--;
- }
- }
- else
- {
- if (pic == NULL)
- {
- pic = copystring (map);
- picisgfx = false;
- }
-
- if (i == EpiDef.numitems)
- {
- if (EpiDef.numitems == MAX_EPISODES)
- {
- i = EpiDef.numitems - 1;
- }
- else
- {
- i = EpiDef.numitems++;
- }
- }
- else
- {
- delete[] const_cast(EpisodeMenu[i].name);
- }
-
- EpisodeMenu[i].name = pic;
- EpisodeMenu[i].alphaKey = tolower(key);
- EpisodeMenu[i].fulltext = !picisgfx;
- EpisodeNoSkill[i] = noskill;
- strncpy (EpisodeMaps[i], map, 8);
- }
-}
-
-static int FindEndSequence (int type, const char *picname)
+int FindEndSequence (int type, const char *picname)
{
unsigned int i, num;
@@ -1483,6 +165,11 @@ static int FindEndSequence (int type, const char *picname)
return -1;
}
+//==========================================================================
+//
+//
+//==========================================================================
+
static void SetEndSequence (char *nextmap, int type)
{
int seqnum;
@@ -1498,6 +185,11 @@ static void SetEndSequence (char *nextmap, int type)
*((WORD *)(nextmap + 6)) = (WORD)seqnum;
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_SetForEndGame (char *nextmap)
{
if (!strncmp(nextmap, "enDSeQ",6)) return; // If there is already an end sequence please leave it alone!!!
@@ -1521,85 +213,14 @@ void G_SetForEndGame (char *nextmap)
}
}
-void G_UnloadMapInfo ()
-{
- unsigned int i;
-
- G_ClearSnapshots ();
-
- for (i = 0; i < wadlevelinfos.Size(); ++i)
- {
- ClearLevelInfoStrings (&wadlevelinfos[i]);
- }
- wadlevelinfos.Clear();
-
- for (i = 0; i < wadclusterinfos.Size(); ++i)
- {
- ClearClusterInfoStrings (&wadclusterinfos[i]);
- }
- wadclusterinfos.Clear();
-
- ClearEpisodes();
-}
-
-level_info_t *FindLevelByWarpTrans (int num)
-{
- for (unsigned i = wadlevelinfos.Size(); i-- != 0; )
- if (wadlevelinfos[i].WarpTrans == num)
- return &wadlevelinfos[i];
-
- return NULL;
-}
-
-static void zapDefereds (acsdefered_t *def)
-{
- while (def)
- {
- acsdefered_t *next = def->next;
- delete def;
- def = next;
- }
-}
-
-void P_RemoveDefereds (void)
-{
- // Remove any existing defereds
- for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
- {
- if (wadlevelinfos[i].defered)
- {
- zapDefereds (wadlevelinfos[i].defered);
- wadlevelinfos[i].defered = NULL;
- }
- }
-}
-
-bool CheckWarpTransMap (FString &mapname, bool substitute)
-{
- if (mapname[0] == '&' && (mapname[1] & 0xDF) == 'W' &&
- (mapname[2] & 0xDF) == 'T' && mapname[3] == '@')
- {
- level_info_t *lev = FindLevelByWarpTrans (atoi (&mapname[4]));
- if (lev != NULL)
- {
- mapname = lev->mapname;
- return true;
- }
- else if (substitute)
- {
- char a = mapname[4], b = mapname[5];
- mapname = "MAP";
- mapname << a << b;
- }
- }
- return false;
-}
-
+//==========================================================================
//
// G_InitNew
// Can be called by the startup code or the menu task,
// consoleplayer, playeringame[] should be set.
//
+//==========================================================================
+
static FString d_mapname;
static int d_skill=-1;
@@ -1611,6 +232,11 @@ void G_DeferedInitNew (const char *mapname, int newskill)
gameaction = ga_newgame2;
}
+//==========================================================================
+//
+//
+//==========================================================================
+
CCMD (map)
{
if (netgame)
@@ -1636,6 +262,11 @@ CCMD (map)
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
CCMD (open)
{
if (netgame)
@@ -1664,6 +295,11 @@ CCMD (open)
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_NewInit ()
{
int i;
@@ -1696,6 +332,11 @@ void G_NewInit ()
NextSkill = -1;
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_DoNewGame (void)
{
G_NewInit ();
@@ -1708,6 +349,38 @@ void G_DoNewGame (void)
gameaction = ga_nothing;
}
+//==========================================================================
+//
+// Initializes player classes in case they are random.
+// This gets called at the start of a new game, and the classes
+// chosen here are used for the remainder of a single-player
+// or coop game. These are ignored for deathmatch.
+//
+//==========================================================================
+
+
+static void InitPlayerClasses ()
+{
+ if (!savegamerestore)
+ {
+ for (int i = 0; i < MAXPLAYERS; ++i)
+ {
+ SinglePlayerClass[i] = players[i].userinfo.PlayerClass;
+ if (SinglePlayerClass[i] < 0 || !playeringame[i])
+ {
+ SinglePlayerClass[i] = (pr_classchoice()) % PlayerClasses.Size ();
+ }
+ players[i].cls = NULL;
+ players[i].CurrentPlayerClass = SinglePlayerClass[i];
+ }
+ }
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_InitNew (const char *mapname, bool bTitleLevel)
{
EGameSpeed oldSpeed;
@@ -1766,14 +439,14 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
}
else
{
- StatusBar = CreateCustomStatusBar(GETSBARINFOSCRIPT(gameinfo.gametype));
+ StatusBar = CreateCustomStatusBar(SCRIPT_DEFAULT);
}
}
if (StatusBar == NULL)
{
if (gameinfo.gametype & GAME_DoomChex)
{
- StatusBar = CreateCustomStatusBar (GETSBARINFOSCRIPT(gameinfo.gametype));
+ StatusBar = CreateCustomStatusBar (SCRIPT_DEFAULT);
}
else if (gameinfo.gametype == GAME_Heretic)
{
@@ -1823,16 +496,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
rngseed = rngseed*3/2;
}
FRandom::StaticClearRandom ();
- memset (ACS_WorldVars, 0, sizeof(ACS_WorldVars));
- memset (ACS_GlobalVars, 0, sizeof(ACS_GlobalVars));
- for (i = 0; i < NUM_WORLDVARS; ++i)
- {
- ACS_WorldArrays[i].Clear ();
- }
- for (i = 0; i < NUM_GLOBALVARS; ++i)
- {
- ACS_GlobalArrays[i].Clear ();
- }
+ P_ClearACSVars(true);
level.time = 0;
level.maptime = 0;
level.totaltime = 0;
@@ -1888,9 +552,14 @@ static bool resetinventory; // Reset the inventory to the player's default for
static bool unloading;
static bool g_nomonsters;
+//==========================================================================
+//
// [RH] The position parameter to these next three functions should
// match the first parameter of the single player start spots
// that should appear in the next map.
+//
+//==========================================================================
+
void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nextSkill,
bool nointermission, bool resetinv, bool nomonsters)
@@ -1905,7 +574,7 @@ void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nex
if (strncmp(levelname, "enDSeQ", 6))
{
- level_info_t *nextinfo = CheckLevelRedirect (FindLevelInfo (nextlevel));
+ level_info_t *nextinfo = FindLevelInfo (nextlevel)->CheckLevelRedirect ();
if (nextinfo)
{
nextlevel = nextinfo->mapname;
@@ -1969,6 +638,11 @@ void G_ChangeLevel(const char *levelname, int position, bool keepFacing, int nex
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
const char *G_GetExitMap()
{
return level.nextmap;
@@ -1988,6 +662,11 @@ const char *G_GetSecretExitMap()
return nextmap;
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_ExitLevel (int position, bool keepFacing)
{
G_ChangeLevel(G_GetExitMap(), position, keepFacing);
@@ -1998,6 +677,11 @@ void G_SecretExitLevel (int position)
G_ChangeLevel(G_GetSecretExitMap(), position, false);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_DoCompleted (void)
{
int i;
@@ -2120,11 +804,7 @@ void G_DoCompleted (void)
if (mode == FINISH_NextHub)
{ // Reset world variables for the new hub.
- memset (ACS_WorldVars, 0, sizeof(ACS_WorldVars));
- for (i = 0; i < NUM_WORLDVARS; ++i)
- {
- ACS_WorldArrays[i].Clear ();
- }
+ P_ClearACSVars(false);
}
// With hub statistics the time should be per hub.
// Additionally there is a global time counter now so nothing is missed by changing it
@@ -2154,6 +834,11 @@ void G_DoCompleted (void)
WI_Start (&wminfo);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
class DAutosaver : public DThinker
{
DECLARE_CLASS (DAutosaver, DThinker)
@@ -2169,9 +854,12 @@ void DAutosaver::Tick ()
Destroy ();
}
+//==========================================================================
//
// G_DoLoadLevel
//
+//==========================================================================
+
extern gamestate_t wipegamestate;
void G_DoLoadLevel (int position, bool autosave)
@@ -2197,18 +885,18 @@ void G_DoLoadLevel (int position, bool autosave)
StatusBar->DetachAllMessages ();
// Force 'teamplay' to 'true' if need be.
- if (level.flags & LEVEL_FORCETEAMPLAYON)
+ if (level.flags2 & LEVEL2_FORCETEAMPLAYON)
teamplay = true;
// Force 'teamplay' to 'false' if need be.
- if (level.flags & LEVEL_FORCETEAMPLAYOFF)
+ if (level.flags2 & LEVEL2_FORCETEAMPLAYOFF)
teamplay = false;
Printf (
"\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36"
"\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"
TEXTCOLOR_BOLD "%s - %s\n\n",
- level.mapname, level.level_name);
+ level.mapname, level.LevelName.GetChars());
if (wipegamestate == GS_LEVEL)
wipegamestate = GS_FORCEWIPE;
@@ -2245,11 +933,11 @@ void G_DoLoadLevel (int position, bool autosave)
if (g_nomonsters)
{
- level.flags |= LEVEL_NOMONSTERS;
+ level.flags2 |= LEVEL2_NOMONSTERS;
}
else
{
- level.flags &= ~LEVEL_NOMONSTERS;
+ level.flags2 &= ~LEVEL2_NOMONSTERS;
}
P_SetupLevel (level.mapname, position);
@@ -2316,9 +1004,12 @@ void G_DoLoadLevel (int position, bool autosave)
}
+//==========================================================================
//
// G_WorldDone
//
+//==========================================================================
+
void G_WorldDone (void)
{
cluster_info_t *nextcluster;
@@ -2333,9 +1024,9 @@ void G_WorldDone (void)
if (strncmp (nextlevel, "enDSeQ", 6) == 0)
{
- F_StartFinale (thiscluster->messagemusic, thiscluster->musicorder,
+ F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder,
thiscluster->cdtrack, thiscluster->cdid,
- thiscluster->finaleflat, thiscluster->exittext,
+ thiscluster->finaleflat, thiscluster->ExitText,
thiscluster->flags & CLUSTER_EXITTEXTINLUMP,
thiscluster->flags & CLUSTER_FINALEPIC,
thiscluster->flags & CLUSTER_LOOKUPEXITTEXT,
@@ -2349,21 +1040,21 @@ void G_WorldDone (void)
{
// Only start the finale if the next level's cluster is different
// than the current one and we're not in deathmatch.
- if (nextcluster->entertext)
+ if (nextcluster->EnterText.IsNotEmpty())
{
- F_StartFinale (nextcluster->messagemusic, nextcluster->musicorder,
+ F_StartFinale (nextcluster->MessageMusic, nextcluster->musicorder,
nextcluster->cdtrack, nextcluster->cdid,
- nextcluster->finaleflat, nextcluster->entertext,
+ nextcluster->finaleflat, nextcluster->EnterText,
nextcluster->flags & CLUSTER_ENTERTEXTINLUMP,
nextcluster->flags & CLUSTER_FINALEPIC,
nextcluster->flags & CLUSTER_LOOKUPENTERTEXT,
false);
}
- else if (thiscluster->exittext)
+ else if (thiscluster->ExitText.IsNotEmpty())
{
- F_StartFinale (thiscluster->messagemusic, thiscluster->musicorder,
+ F_StartFinale (thiscluster->MessageMusic, thiscluster->musicorder,
thiscluster->cdtrack, nextcluster->cdid,
- thiscluster->finaleflat, thiscluster->exittext,
+ thiscluster->finaleflat, thiscluster->ExitText,
thiscluster->flags & CLUSTER_EXITTEXTINLUMP,
thiscluster->flags & CLUSTER_FINALEPIC,
thiscluster->flags & CLUSTER_LOOKUPEXITTEXT,
@@ -2373,6 +1064,11 @@ void G_WorldDone (void)
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_DoWorldDone (void)
{
gamestate = GS_LEVEL;
@@ -2518,6 +1214,11 @@ void G_FinishTravel ()
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_InitLevelLocals ()
{
level_info_t *info;
@@ -2538,7 +1239,6 @@ void G_InitLevelLocals ()
level.info = info;
level.skyspeed1 = info->skyspeed1;
level.skyspeed2 = info->skyspeed2;
- info = (level_info_t *)info;
strncpy (level.skypic2, info->skypic2, 8);
level.fadeto = info->fadeto;
level.cdtrack = info->cdtrack;
@@ -2577,7 +1277,7 @@ void G_InitLevelLocals ()
G_AirControlChanged ();
- if (info->level_name)
+ if (!info->LevelName.IsEmpty())
{
cluster_info_t *clus = FindClusterInfo (info->cluster);
@@ -2587,11 +1287,10 @@ void G_InitLevelLocals ()
level.clusterflags = clus ? clus->flags : 0;
level.flags |= info->flags;
level.levelnum = info->levelnum;
- level.music = info->music;
+ level.Music = info->Music;
level.musicorder = info->musicorder;
- strncpy (level.level_name, info->level_name, 63);
- G_MaybeLookupLevelName (NULL);
+ level.LevelName = level.info->LookupLevelName();
strncpy (level.nextmap, info->nextmap, 8);
level.nextmap[8] = 0;
strncpy (level.secretmap, info->secretmap, 8);
@@ -2606,10 +1305,10 @@ void G_InitLevelLocals ()
{
level.partime = level.cluster = 0;
level.sucktime = 0;
- strcpy (level.level_name, "Unnamed");
+ level.LevelName = "Unnamed";
level.nextmap[0] =
level.secretmap[0] = 0;
- level.music = NULL;
+ level.Music = "";
strcpy (level.skypic1, "SKY1");
strcpy (level.skypic2, "SKY1");
level.flags = 0;
@@ -2621,6 +1320,11 @@ void G_InitLevelLocals ()
NormalLight.ChangeFade (level.fadeto);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
bool FLevelLocals::IsJumpingAllowed() const
{
if (dmflags & DF_NO_JUMP)
@@ -2630,6 +1334,11 @@ bool FLevelLocals::IsJumpingAllowed() const
return !(level.flags & LEVEL_JUMP_NO);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
bool FLevelLocals::IsCrouchingAllowed() const
{
if (dmflags & DF_NO_CROUCH)
@@ -2639,6 +1348,11 @@ bool FLevelLocals::IsCrouchingAllowed() const
return !(level.flags & LEVEL_CROUCH_NO);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
bool FLevelLocals::IsFreelookAllowed() const
{
if (level.flags & LEVEL_FREELOOK_NO)
@@ -2648,6 +1362,11 @@ bool FLevelLocals::IsFreelookAllowed() const
return !(dmflags & DF_NO_FREELOOK);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
FString CalcMapName (int episode, int level)
{
FString lumpname;
@@ -2664,124 +1383,10 @@ FString CalcMapName (int episode, int level)
return lumpname;
}
-level_info_t *FindLevelInfo (const char *mapname)
-{
- int i;
-
- if ((i = FindWadLevelInfo (mapname)) > -1)
- return &wadlevelinfos[i];
- else
- return &TheDefaultLevelInfo;
-}
-
-level_info_t *FindLevelByNum (int num)
-{
- for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
- if (wadlevelinfos[i].levelnum == num)
- return &wadlevelinfos[i];
-
- return NULL;
-}
-
-level_info_t *CheckLevelRedirect (level_info_t *info)
-{
- if (info->RedirectType != NAME_None)
- {
- const PClass *type = PClass::FindClass(info->RedirectType);
- if (type != NULL)
- {
- for (int i = 0; i < MAXPLAYERS; ++i)
- {
- if (playeringame[i] && players[i].mo->FindInventory (type))
- {
- // check for actual presence of the map.
- if (P_CheckMapData(info->RedirectMap))
- {
- return FindLevelInfo(info->RedirectMap);
- }
- break;
- }
- }
- }
- }
- return NULL;
-}
-
-static void SetLevelNum (level_info_t *info, int num)
-{
- // Avoid duplicate levelnums. The level being set always has precedence.
- for (unsigned int i = 0; i < wadlevelinfos.Size(); ++i)
- {
- if (wadlevelinfos[i].levelnum == num)
- wadlevelinfos[i].levelnum = 0;
- }
- info->levelnum = num;
-}
-
-cluster_info_t *FindClusterInfo (int cluster)
-{
- int i;
-
- if ((i = FindWadClusterInfo (cluster)) > -1)
- return &wadclusterinfos[i];
- else
- return &TheDefaultClusterInfo;
-}
-
-const char *G_MaybeLookupLevelName (level_info_t *ininfo)
-{
- level_info_t *info;
-
- if (ininfo == NULL)
- {
- info = level.info;
- }
- else
- {
- info = ininfo;
- }
-
- if (info != NULL && info->flags & LEVEL_LOOKUPLEVELNAME)
- {
- const char *thename;
- const char *lookedup;
-
- lookedup = GStrings[info->level_name];
- if (lookedup == NULL)
- {
- thename = info->level_name;
- }
- else
- {
- char checkstring[32];
-
- // Strip out the header from the localized string
- if (info->mapname[0] == 'E' && info->mapname[2] == 'M')
- {
- mysnprintf (checkstring, countof(checkstring), "%s: ", info->mapname);
- }
- else if (info->mapname[0] == 'M' && info->mapname[1] == 'A' && info->mapname[2] == 'P')
- {
- mysnprintf (checkstring, countof(checkstring), "%d: ", atoi(info->mapname + 3));
- }
- thename = strstr (lookedup, checkstring);
- if (thename == NULL)
- {
- thename = lookedup;
- }
- else
- {
- thename += strlen (checkstring);
- }
- }
- if (ininfo == NULL)
- {
- strncpy (level.level_name, thename, 63);
- }
- return thename;
- }
- return info != NULL ? info->level_name : NULL;
-}
+//==========================================================================
+//
+//
+//==========================================================================
void G_AirControlChanged ()
{
@@ -2797,6 +1402,11 @@ void G_AirControlChanged ()
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_SerializeLevel (FArchive &arc, bool hubLoad)
{
int i = level.totaltime;
@@ -2914,13 +1524,18 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
gl_RecreateAllAttachedLights();
}
+//==========================================================================
+//
// Archives the current level
+//
+//==========================================================================
+
void G_SnapshotLevel ()
{
if (level.info->snapshot)
delete level.info->snapshot;
- if (level.info->mapname[0] != 0 || level.info == &TheDefaultLevelInfo)
+ if (level.info->isValid())
{
level.info->snapshotVer = SAVEVER;
level.info->snapshot = new FCompressedMemFile;
@@ -2933,14 +1548,19 @@ void G_SnapshotLevel ()
}
}
+//==========================================================================
+//
// Unarchives the current level based on its snapshot
// The level should have already been loaded and setup.
+//
+//==========================================================================
+
void G_UnSnapshotLevel (bool hubLoad)
{
if (level.info->snapshot == NULL)
return;
- if (level.info->mapname[0] != 0 || level.info == &TheDefaultLevelInfo)
+ if (level.info->isValid())
{
SaveVersion = level.info->snapshotVer;
level.info->snapshot->Reopen ();
@@ -2978,21 +1598,13 @@ void G_UnSnapshotLevel (bool hubLoad)
}
}
// No reason to keep the snapshot around once the level's been entered.
- delete level.info->snapshot;
- level.info->snapshot = NULL;
+ level.info->ClearSnapshot();
}
-void G_ClearSnapshots (void)
-{
- for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
- {
- if (wadlevelinfos[i].snapshot)
- {
- delete wadlevelinfos[i].snapshot;
- wadlevelinfos[i].snapshot = NULL;
- }
- }
-}
+//==========================================================================
+//
+//
+//==========================================================================
static void writeMapName (FArchive &arc, const char *name)
{
@@ -3009,6 +1621,11 @@ static void writeMapName (FArchive &arc, const char *name)
arc.Write (name, size);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
static void writeSnapShot (FArchive &arc, level_info_t *i)
{
arc << i->snapshotVer;
@@ -3016,6 +1633,11 @@ static void writeSnapShot (FArchive &arc, level_info_t *i)
i->snapshot->Serialize (arc);
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_WriteSnapshots (FILE *file)
{
unsigned int i;
@@ -3083,6 +1705,11 @@ void G_WriteSnapshots (FILE *file)
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void G_ReadSnapshots (PNGHandle *png)
{
DWORD chunkLen;
@@ -3169,12 +1796,22 @@ void G_ReadSnapshots (PNGHandle *png)
}
+//==========================================================================
+//
+//
+//==========================================================================
+
static void writeDefereds (FArchive &arc, level_info_t *i)
{
writeMapName (arc, i->mapname);
arc << i->defered;
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void P_WriteACSDefereds (FILE *file)
{
FPNGChunkArchive *arc = NULL;
@@ -3200,6 +1837,11 @@ void P_WriteACSDefereds (FILE *file)
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void P_ReadACSDefereds (PNGHandle *png)
{
BYTE namelen;
@@ -3230,6 +1872,11 @@ void P_ReadACSDefereds (PNGHandle *png)
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void FLevelLocals::Tick ()
{
// Reset carry sectors
@@ -3239,6 +1886,11 @@ void FLevelLocals::Tick ()
}
}
+//==========================================================================
+//
+//
+//==========================================================================
+
void FLevelLocals::AddScroller (DScroller *scroller, int secnum)
{
if (secnum < 0)
@@ -3252,285 +1904,11 @@ void FLevelLocals::AddScroller (DScroller *scroller, int secnum)
}
}
-// Initializes player classes in case they are random.
-// This gets called at the start of a new game, and the classes
-// chosen here are used for the remainder of a single-player
-// or coop game. These are ignored for deathmatch.
-
-static void InitPlayerClasses ()
-{
- if (!savegamerestore)
- {
- for (int i = 0; i < MAXPLAYERS; ++i)
- {
- SinglePlayerClass[i] = players[i].userinfo.PlayerClass;
- if (SinglePlayerClass[i] < 0 || !playeringame[i])
- {
- SinglePlayerClass[i] = (pr_classchoice()) % PlayerClasses.Size ();
- }
- players[i].cls = NULL;
- players[i].CurrentPlayerClass = SinglePlayerClass[i];
- }
- }
-}
-
-
-static void ParseSkill (FScanner &sc)
-{
- FSkillInfo skill;
-
- skill.AmmoFactor = FRACUNIT;
- skill.DoubleAmmoFactor = 2*FRACUNIT;
- skill.DropAmmoFactor = -1;
- skill.DamageFactor = FRACUNIT;
- skill.FastMonsters = false;
- skill.DisableCheats = false;
- skill.EasyBossBrain = false;
- skill.AutoUseHealth = false;
- skill.RespawnCounter = 0;
- skill.RespawnLimit = 0;
- skill.Aggressiveness = FRACUNIT;
- skill.SpawnFilter = 0;
- skill.ACSReturn = AllSkills.Size();
- skill.MenuNameIsLump = false;
- skill.MustConfirm = false;
- skill.Shortcut = 0;
- skill.TextColor = "";
-
- sc.MustGetString();
- skill.Name = sc.String;
-
- while (sc.GetString ())
- {
- if (sc.Compare ("ammofactor"))
- {
- sc.MustGetFloat ();
- skill.AmmoFactor = FLOAT2FIXED(sc.Float);
- }
- else if (sc.Compare ("doubleammofactor"))
- {
- sc.MustGetFloat ();
- skill.DoubleAmmoFactor = FLOAT2FIXED(sc.Float);
- }
- else if (sc.Compare ("dropammofactor"))
- {
- sc.MustGetFloat ();
- skill.DropAmmoFactor = FLOAT2FIXED(sc.Float);
- }
- else if (sc.Compare ("damagefactor"))
- {
- sc.MustGetFloat ();
- skill.DamageFactor = FLOAT2FIXED(sc.Float);
- }
- else if (sc.Compare ("fastmonsters"))
- {
- skill.FastMonsters = true;
- }
- else if (sc.Compare ("disablecheats"))
- {
- skill.DisableCheats = true;
- }
- else if (sc.Compare ("easybossbrain"))
- {
- skill.EasyBossBrain = true;
- }
- else if (sc.Compare("autousehealth"))
- {
- skill.AutoUseHealth = true;
- }
- else if (sc.Compare("respawntime"))
- {
- sc.MustGetFloat ();
- skill.RespawnCounter = int(sc.Float*TICRATE);
- }
- else if (sc.Compare("respawnlimit"))
- {
- sc.MustGetNumber ();
- skill.RespawnLimit = sc.Number;
- }
- else if (sc.Compare("Aggressiveness"))
- {
- sc.MustGetFloat ();
- skill.Aggressiveness = FRACUNIT - FLOAT2FIXED(clamp(sc.Float, 0,1));
- }
- else if (sc.Compare("SpawnFilter"))
- {
- if (sc.CheckNumber())
- {
- if (sc.Number > 0) skill.SpawnFilter |= (1<<(sc.Number-1));
- }
- else
- {
- sc.MustGetString ();
- if (sc.Compare("baby")) skill.SpawnFilter |= 1;
- else if (sc.Compare("easy")) skill.SpawnFilter |= 2;
- else if (sc.Compare("normal")) skill.SpawnFilter |= 4;
- else if (sc.Compare("hard")) skill.SpawnFilter |= 8;
- else if (sc.Compare("nightmare")) skill.SpawnFilter |= 16;
- }
- }
- else if (sc.Compare("ACSReturn"))
- {
- sc.MustGetNumber ();
- skill.ACSReturn = sc.Number;
- }
- else if (sc.Compare("Name"))
- {
- sc.MustGetString ();
- skill.MenuName = sc.String;
- skill.MenuNameIsLump = false;
- }
- else if (sc.Compare("PlayerClassName"))
- {
- sc.MustGetString ();
- FName pc = sc.String;
- sc.MustGetString ();
- skill.MenuNamesForPlayerClass[pc]=sc.String;
- }
- else if (sc.Compare("PicName"))
- {
- sc.MustGetString ();
- skill.MenuName = sc.String;
- skill.MenuNameIsLump = true;
- }
- else if (sc.Compare("MustConfirm"))
- {
- skill.MustConfirm = true;
- if (sc.CheckToken(TK_StringConst))
- {
- skill.MustConfirmText = sc.String;
- }
- }
- else if (sc.Compare("Key"))
- {
- sc.MustGetString();
- skill.Shortcut = tolower(sc.String[0]);
- }
- else if (sc.Compare("TextColor"))
- {
- sc.MustGetString();
- skill.TextColor = '[';
- skill.TextColor << sc.String << ']';
- }
- else
- {
- sc.UnGet ();
- break;
- }
- }
- for(unsigned int i = 0; i < AllSkills.Size(); i++)
- {
- if (AllSkills[i].Name == skill.Name)
- {
- AllSkills[i] = skill;
- return;
- }
- }
- AllSkills.Push(skill);
-}
-
-int G_SkillProperty(ESkillProperty prop)
-{
- if (AllSkills.Size() > 0)
- {
- switch(prop)
- {
- case SKILLP_AmmoFactor:
- if (dmflags2 & DF2_YES_DOUBLEAMMO)
- {
- return AllSkills[gameskill].DoubleAmmoFactor;
- }
- return AllSkills[gameskill].AmmoFactor;
-
- case SKILLP_DropAmmoFactor:
- return AllSkills[gameskill].DropAmmoFactor;
-
- case SKILLP_DamageFactor:
- return AllSkills[gameskill].DamageFactor;
-
- case SKILLP_FastMonsters:
- return AllSkills[gameskill].FastMonsters || (dmflags & DF_FAST_MONSTERS);
-
- case SKILLP_Respawn:
- if (dmflags & DF_MONSTERS_RESPAWN && AllSkills[gameskill].RespawnCounter==0)
- return TICRATE * (gameinfo.gametype != GAME_Strife ? 12 : 16);
- return AllSkills[gameskill].RespawnCounter;
-
- case SKILLP_RespawnLimit:
- return AllSkills[gameskill].RespawnLimit;
-
- case SKILLP_Aggressiveness:
- return AllSkills[gameskill].Aggressiveness;
-
- case SKILLP_DisableCheats:
- return AllSkills[gameskill].DisableCheats;
-
- case SKILLP_AutoUseHealth:
- return AllSkills[gameskill].AutoUseHealth;
-
- case SKILLP_EasyBossBrain:
- return AllSkills[gameskill].EasyBossBrain;
-
- case SKILLP_SpawnFilter:
- return AllSkills[gameskill].SpawnFilter;
-
- case SKILLP_ACSReturn:
- return AllSkills[gameskill].ACSReturn;
- }
- }
- return 0;
-}
-
-
-void G_VerifySkill()
-{
- if (gameskill >= (int)AllSkills.Size())
- gameskill = AllSkills.Size()-1;
- else if (gameskill < 0)
- gameskill = 0;
-}
-
-FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other)
-{
- Name = other.Name;
- AmmoFactor = other.AmmoFactor;
- DoubleAmmoFactor = other.DoubleAmmoFactor;
- DropAmmoFactor = other.DropAmmoFactor;
- DamageFactor = other.DamageFactor;
- FastMonsters = other.FastMonsters;
- DisableCheats = other.DisableCheats;
- AutoUseHealth = other.AutoUseHealth;
- EasyBossBrain = other.EasyBossBrain;
- RespawnCounter= other.RespawnCounter;
- RespawnLimit= other.RespawnLimit;
- Aggressiveness= other.Aggressiveness;
- SpawnFilter = other.SpawnFilter;
- ACSReturn = other.ACSReturn;
- MenuName = other.MenuName;
- MenuNamesForPlayerClass = other.MenuNamesForPlayerClass;
- MenuNameIsLump = other.MenuNameIsLump;
- MustConfirm = other.MustConfirm;
- MustConfirmText = other.MustConfirmText;
- Shortcut = other.Shortcut;
- TextColor = other.TextColor;
- return *this;
-}
-
-int FSkillInfo::GetTextColor() const
-{
- if (TextColor.IsEmpty())
- {
- return CR_UNTRANSLATED;
- }
- const BYTE *cp = (const BYTE *)TextColor.GetChars();
- int color = V_ParseFontColor(cp, 0, 0);
- if (color == CR_UNDEFINED)
- {
- Printf("Undefined color '%s' in definition of skill %s\n", TextColor.GetChars(), Name.GetChars());
- color = CR_UNTRANSLATED;
- }
- return color;
-}
+//==========================================================================
+//
+// Lists all currently defined maps
+//
+//==========================================================================
CCMD(listmaps)
{
@@ -3540,7 +1918,11 @@ CCMD(listmaps)
if (P_CheckMapData(info->mapname))
{
- Printf("%s: '%s'\n", info->mapname, G_MaybeLookupLevelName(info));
+ Printf("%s: '%s'\n", info->mapname, info->LookupLevelName().GetChars());
}
}
}
+
+
+
+
diff --git a/src/g_level.h b/src/g_level.h
index b288cc06..48db7b19 100644
--- a/src/g_level.h
+++ b/src/g_level.h
@@ -36,90 +36,166 @@
#include "doomtype.h"
#include "doomdef.h"
+#include "autosegs.h"
+#include "sc_man.h"
-#define NUM_WORLDVARS 256
-#define NUM_GLOBALVARS 64
+struct level_info_t;
+struct cluster_info_t;
+class FScanner;
-#define LEVEL_NOINTERMISSION UCONST64(0x00000001)
-#define LEVEL_NOINVENTORYBAR UCONST64(0x00000002) // This effects Doom only, since it's the only one without a standard inventory bar.
-#define LEVEL_DOUBLESKY UCONST64(0x00000004)
-#define LEVEL_HASFADETABLE UCONST64(0x00000008) // Level uses Hexen's fadetable mapinfo to get fog
+#if defined(_MSC_VER)
+#pragma data_seg(".yreg$u")
+#pragma data_seg()
-#define LEVEL_MAP07SPECIAL UCONST64(0x00000010)
-#define LEVEL_BRUISERSPECIAL UCONST64(0x00000020)
-#define LEVEL_CYBORGSPECIAL UCONST64(0x00000040)
-#define LEVEL_SPIDERSPECIAL UCONST64(0x00000080)
+#define MSVC_YSEG __declspec(allocate(".yreg$u"))
+#define GCC_YSEG
+#else
+#define MSVC_YSEG
+#define GCC_YSEG __attribute__((section(YREG_SECTION)))
+#endif
-#define LEVEL_SPECLOWERFLOOR UCONST64(0x00000100)
-#define LEVEL_SPECOPENDOOR UCONST64(0x00000200)
-#define LEVEL_SPECACTIONSMASK UCONST64(0x00000300)
-#define LEVEL_MONSTERSTELEFRAG UCONST64(0x00000400)
-#define LEVEL_ACTOWNSPECIAL UCONST64(0x00000800)
-#define LEVEL_SNDSEQTOTALCTRL UCONST64(0x00001000)
-#define LEVEL_FORCENOSKYSTRETCH UCONST64(0x00002000)
+struct FMapInfoParser
+{
+ enum EFormatType
+ {
+ FMT_Unknown,
+ FMT_Old,
+ FMT_New
+ };
-#define LEVEL_CROUCH_NO UCONST64(0x00004000)
-#define LEVEL_JUMP_NO UCONST64(0x00008000)
-#define LEVEL_FREELOOK_NO UCONST64(0x00010000)
-#define LEVEL_FREELOOK_YES UCONST64(0x00020000)
+ FScanner sc;
+ int format_type;
+ bool HexenHack;
-// The absence of both of the following bits means that this level does not
-// use falling damage (though damage can be forced with dmflags).
-#define LEVEL_FALLDMG_ZD UCONST64(0x00040000) // Level uses ZDoom's falling damage
-#define LEVEL_FALLDMG_HX UCONST64(0x00080000) // Level uses Hexen's falling damage
+ FMapInfoParser()
+ {
+ format_type = FMT_Unknown;
+ HexenHack = false;
+ }
-#define LEVEL_HEADSPECIAL UCONST64(0x00100000) // Heretic episode 1/4
-#define LEVEL_MINOTAURSPECIAL UCONST64(0x00200000) // Heretic episode 2/5
-#define LEVEL_SORCERER2SPECIAL UCONST64(0x00400000) // Heretic episode 3
-#define LEVEL_SPECKILLMONSTERS UCONST64(0x00800000)
+ bool ParseLookupName(FString &dest);
+ void ParseMusic(FString &name, int &order);
+ void ParseLumpOrTextureName(char *name);
-#define LEVEL_STARTLIGHTNING UCONST64(0x01000000) // Automatically start lightning
-#define LEVEL_FILTERSTARTS UCONST64(0x02000000) // Apply mapthing filtering to player starts
-#define LEVEL_LOOKUPLEVELNAME UCONST64(0x04000000) // Level name is the name of a language string
-#define LEVEL_HEXENFORMAT UCONST64(0x08000000) // Level uses the Hexen map format
+ void ParseCluster();
+ void ParseNextMap(char *mapname);
+ level_info_t *ParseMapHeader(level_info_t &defaultinfo);
+ void ParseMapDefinition(level_info_t &leveldef);
+ void ParseEpisodeInfo ();
+ void ParseSkill ();
+ void ParseMapInfo (int lump, level_info_t &gamedefaults);
-#define LEVEL_SWAPSKIES UCONST64(0x10000000) // Used by lightning
-#define LEVEL_NOALLIES UCONST64(0x20000000) // i.e. Inside Strife's front base
-#define LEVEL_CHANGEMAPCHEAT UCONST64(0x40000000) // Don't display cluster messages
-#define LEVEL_VISITED UCONST64(0x80000000) // Used for intermission map
+ void ParseOpenBrace();
+ bool ParseCloseBrace();
+ bool CheckAssign();
+ void ParseAssign();
+ void MustParseAssign();
+ void ParseComma();
+ bool CheckNumber();
+ bool CheckFloat();
+ void SkipToNext();
+};
-#define LEVEL_DEATHSLIDESHOW UCONST64(0x100000000) // Slideshow on death
-#define LEVEL_ALLMAP UCONST64(0x200000000) // The player picked up a map on this level
+#define DEFINE_MAP_OPTION(name, old) \
+ static void MapOptHandler_##name(FMapInfoParser &parse, level_info_t *info); \
+ static FMapOptInfo MapOpt_##name = \
+ { #name, MapOptHandler_##name, old }; \
+ MSVC_YSEG FMapOptInfo *mapopt_##name GCC_YSEG = &MapOpt_##name; \
+ static void MapOptHandler_##name(FMapInfoParser &parse, level_info_t *info)
-#define LEVEL_LAXMONSTERACTIVATION UCONST64(0x400000000) // Monsters can open doors depending on the door speed
-#define LEVEL_LAXACTIVATIONMAPINFO UCONST64(0x800000000) // LEVEL_LAXMONSTERACTIVATION is not a default.
-#define LEVEL_MISSILESACTIVATEIMPACT UCONST64(0x1000000000) // Missiles are the activators of SPAC_IMPACT events, not their shooters
-#define LEVEL_FROZEN UCONST64(0x2000000000) // Game is frozen by a TimeFreezer
+struct FMapOptInfo
+{
+ const char *name;
+ void (*handler) (FMapInfoParser &parse, level_info_t *levelinfo);
+ bool old;
+};
-#define LEVEL_KEEPFULLINVENTORY UCONST64(0x4000000000) // doesn't reduce the amount of inventory items to 1
+enum ELevelFlags
+{
+ LEVEL_NOINTERMISSION = 0x00000001,
+ LEVEL_NOINVENTORYBAR = 0x00000002, // This effects Doom only, since it's the only one without a standard inventory bar.
+ LEVEL_DOUBLESKY = 0x00000004,
+ LEVEL_HASFADETABLE = 0x00000008, // Level uses Hexen's fadetable mapinfo to get fog
-#define LEVEL_MUSICDEFINED UCONST64(0x8000000000) // a marker to disable the $map command in SNDINFO for this map
-#define LEVEL_MONSTERFALLINGDAMAGE UCONST64(0x10000000000)
-#define LEVEL_CLIPMIDTEX UCONST64(0x20000000000)
-#define LEVEL_WRAPMIDTEX UCONST64(0x40000000000)
+ LEVEL_MAP07SPECIAL = 0x00000010,
+ LEVEL_BRUISERSPECIAL = 0x00000020,
+ LEVEL_CYBORGSPECIAL = 0x00000040,
+ LEVEL_SPIDERSPECIAL = 0x00000080,
-#define LEVEL_CHECKSWITCHRANGE UCONST64(0x80000000000)
+ LEVEL_SPECLOWERFLOOR = 0x00000100,
+ LEVEL_SPECOPENDOOR = 0x00000200,
+ LEVEL_SPECACTIONSMASK = 0x00000300,
-#define LEVEL_PAUSE_MUSIC_IN_MENUS UCONST64(0x100000000000)
-#define LEVEL_TOTALINFIGHTING UCONST64(0x200000000000)
-#define LEVEL_NOINFIGHTING UCONST64(0x400000000000)
+ LEVEL_MONSTERSTELEFRAG = 0x00000400,
+ LEVEL_ACTOWNSPECIAL = 0x00000800,
+ LEVEL_SNDSEQTOTALCTRL = 0x00001000,
+ LEVEL_FORCENOSKYSTRETCH = 0x00002000,
-#define LEVEL_NOMONSTERS UCONST64(0x800000000000)
-#define LEVEL_INFINITE_FLIGHT UCONST64(0x1000000000000)
+ LEVEL_CROUCH_NO = 0x00004000,
+ LEVEL_JUMP_NO = 0x00008000,
+ LEVEL_FREELOOK_NO = 0x00010000,
+ LEVEL_FREELOOK_YES = 0x00020000,
-#define LEVEL_ALLOWRESPAWN UCONST64(0x2000000000000)
+ // The absence of both of the following bits means that this level does not
+ // use falling damage (though damage can be forced with dmflags,.
+ LEVEL_FALLDMG_ZD = 0x00040000, // Level uses ZDoom's falling damage
+ LEVEL_FALLDMG_HX = 0x00080000, // Level uses Hexen's falling damage
-#define LEVEL_FORCETEAMPLAYON UCONST64(0x4000000000000)
-#define LEVEL_FORCETEAMPLAYOFF UCONST64(0x8000000000000)
+ LEVEL_HEADSPECIAL = 0x00100000, // Heretic episode 1/4
+ LEVEL_MINOTAURSPECIAL = 0x00200000, // Heretic episode 2/5
+ LEVEL_SORCERER2SPECIAL = 0x00400000, // Heretic episode 3
+ LEVEL_SPECKILLMONSTERS = 0x00800000,
-#define LEVEL_CONV_SINGLE_UNFREEZE UCONST64(0x10000000000000)
-#define LEVEL_RAILINGHACK UCONST64(0x20000000000000) // but UDMF requires them to be separate to have more control
-#define LEVEL_DUMMYSWITCHES UCONST64(0x40000000000000)
-#define LEVEL_HEXENHACK UCONST64(0x80000000000000) // Level was defined in a Hexen style MAPINFO
+ LEVEL_STARTLIGHTNING = 0x01000000, // Automatically start lightning
+ LEVEL_FILTERSTARTS = 0x02000000, // Apply mapthing filtering to player starts
+ LEVEL_LOOKUPLEVELNAME = 0x04000000, // Level name is the name of a language string
+ LEVEL_HEXENFORMAT = 0x08000000, // Level uses the Hexen map format
-#define LEVEL_SMOOTHLIGHTING UCONST64(0x100000000000000) // Level uses the smooth lighting feature.
+ LEVEL_SWAPSKIES = 0x10000000, // Used by lightning
+ LEVEL_NOALLIES = 0x20000000, // i.e. Inside Strife's front base
+ LEVEL_CHANGEMAPCHEAT = 0x40000000, // Don't display cluster messages
+ LEVEL_VISITED = 0x80000000, // Used for intermission map
+
+ // The flags QWORD is now split into 2 DWORDs
+ LEVEL2_DEATHSLIDESHOW = 0x00000001, // Slideshow on death
+ LEVEL2_ALLMAP = 0x00000002, // The player picked up a map on this level
+
+ LEVEL2_LAXMONSTERACTIVATION = 0x00000004, // Monsters can open doors depending on the door speed
+ LEVEL2_LAXACTIVATIONMAPINFO = 0x00000008, // LEVEL_LAXMONSTERACTIVATION is not a default.
+
+ LEVEL2_MISSILESACTIVATEIMPACT = 0x00000010, // Missiles are the activators of SPAC_IMPACT events, not their shooters
+ LEVEL2_FROZEN = 0x00000020, // Game is frozen by a TimeFreezer
+
+ LEVEL2_KEEPFULLINVENTORY = 0x00000040, // doesn't reduce the amount of inventory items to 1
+
+ LEVEL2_MUSICDEFINED = 0x00000080, // a marker to disable the $map command in SNDINFO for this map
+ LEVEL2_MONSTERFALLINGDAMAGE = 0x00000100,
+ LEVEL2_CLIPMIDTEX = 0x00000200,
+ LEVEL2_WRAPMIDTEX = 0x00000400,
+
+ LEVEL2_CHECKSWITCHRANGE = 0x00000800,
+
+ LEVEL2_PAUSE_MUSIC_IN_MENUS = 0x00001000,
+ LEVEL2_TOTALINFIGHTING = 0x00002000,
+ LEVEL2_NOINFIGHTING = 0x00004000,
+
+ LEVEL2_NOMONSTERS = 0x00008000,
+ LEVEL2_INFINITE_FLIGHT = 0x00010000,
+
+ LEVEL2_ALLOWRESPAWN = 0x00020000,
+
+ LEVEL2_FORCETEAMPLAYON = 0x00040000,
+ LEVEL2_FORCETEAMPLAYOFF = 0x00080000,
+
+ LEVEL2_CONV_SINGLE_UNFREEZE = 0x00100000,
+ LEVEL2_RAILINGHACK = 0x00200000, // but UDMF requires them to be separate to have more control
+ LEVEL2_DUMMYSWITCHES = 0x00400000,
+ LEVEL2_HEXENHACK = 0x00800000, // Level was defined in a Hexen style MAPINFO
+
+ LEVEL2_SMOOTHLIGHTING = 0x01000000, // Level uses the smooth lighting feature.
+};
struct acsdefered_t;
@@ -129,7 +205,6 @@ struct FSpecialAction
FName Type; // this is initialized before the actors...
BYTE Action;
int Args[5]; // must allow 16 bit tags for 666 & 667!
- FSpecialAction *Next;
};
class FCompressedMemFile;
@@ -137,9 +212,6 @@ class DScroller;
class FScanner;
struct level_info_t;
-typedef void (*MIParseFunc)(FScanner &sc, level_info_t *info);
-
-void AddOptionalMapinfoParser(const char *keyword, MIParseFunc parsefunc);
struct FOptionalMapinfoData
{
@@ -150,6 +222,18 @@ struct FOptionalMapinfoData
virtual FOptionalMapinfoData *Clone() const = 0;
};
+struct FOptionalMapinfoDataPtr
+{
+ FOptionalMapinfoData *Ptr;
+
+ FOptionalMapinfoDataPtr() throw() : Ptr(NULL) {}
+ ~FOptionalMapinfoDataPtr() { if (Ptr!=NULL) delete Ptr; }
+ FOptionalMapinfoDataPtr(const FOptionalMapinfoDataPtr &p) throw() : Ptr(p.Ptr->Clone()) {}
+ FOptionalMapinfoDataPtr &operator= (FOptionalMapinfoDataPtr &p) throw() { Ptr = p.Ptr->Clone(); return *this; }
+};
+
+typedef TMap FOptData;
+
struct level_info_t
{
char mapname[9];
@@ -161,13 +245,13 @@ struct level_info_t
int cluster;
int partime;
int sucktime;
- QWORD flags;
- char *music;
- char *level_name;
+ DWORD flags;
+ DWORD flags2;
+ FString Music;
+ FString LevelName;
char fadetable[9];
SBYTE WallVertLight, WallHorizLight;
char f1[9];
- // TheDefaultLevelInfo initializes everything above this line.
int musicorder;
FCompressedMemFile *snapshot;
DWORD snapshotVer;
@@ -185,27 +269,61 @@ struct level_info_t
int airsupply;
DWORD compatflags;
DWORD compatmask;
- char *translator; // for converting Doom-format linedef and sector types.
+ FString Translator; // for converting Doom-format linedef and sector types.
// Redirection: If any player is carrying the specified item, then
// you go to the RedirectMap instead of this one.
FName RedirectType;
char RedirectMap[9];
- char *enterpic;
- char *exitpic;
- char *intermusic;
+ FString EnterPic;
+ FString ExitPic;
+ FString InterMusic;
int intermusicorder;
- char *soundinfo;
- char *sndseq;
+ FString SoundInfo;
+ FString SndSeq;
char bordertexture[9];
float teamdamage;
- FSpecialAction * specialactions;
- FOptionalMapinfoData *opdata;
+ FOptData optdata;
+ TArray specialactions;
+
+ level_info_t()
+ {
+ Reset();
+ }
+ ~level_info_t()
+ {
+ ClearSnapshot();
+ ClearDefered();
+ }
+ void Reset();
+ bool isValid();
+ FString LookupLevelName ();
+ void ClearSnapshot();
+ void ClearDefered();
+ level_info_t *CheckLevelRedirect ();
+
+ template
+ T *GetOptData(FName id, bool create = true)
+ {
+ FOptionalMapinfoDataPtr *pdat = optdata.CheckKey(id);
+
+ if (pdat != NULL)
+ {
+ return static_cast(pdat->Ptr);
+ }
+ else if (create)
+ {
+ T *newobj = new T;
+ optdata[id].Ptr = newobj;
+ return newobj;
+ }
+ else return NULL;
+ }
};
// [RH] These get zeroed every tic and are updated by thinkers.
@@ -231,17 +349,18 @@ struct FLevelLocals
int clusterflags;
int levelnum;
int lumpnum;
- char level_name[64]; // the descriptive name (Outer Base, etc)
+ FString LevelName;
char mapname[256]; // the server name (base1, etc)
char nextmap[9]; // go here when fraglimit is hit
char secretmap[9]; // map to go to when used secret exit
- QWORD flags;
+ DWORD flags;
+ DWORD flags2;
DWORD fadeto; // The color the palette fades to (usually black)
DWORD outsidefog; // The fog for sectors with sky ceilings
- char *music;
+ FString Music;
int musicorder;
int cdtrack;
unsigned int cdid;
@@ -313,14 +432,17 @@ struct cluster_info_t
{
int cluster;
char finaleflat[9];
- char *exittext;
- char *entertext;
- char *messagemusic;
+ FString ExitText;
+ FString EnterText;
+ FString MessageMusic;
int musicorder;
int flags;
int cdtrack;
- char *clustername;
+ FString ClusterName;
unsigned int cdid;
+
+ void Reset();
+
};
// Cluster flags
@@ -331,25 +453,12 @@ struct cluster_info_t
#define CLUSTER_LOOKUPEXITTEXT 0x00000010 // Exit text is the name of a language string
#define CLUSTER_LOOKUPENTERTEXT 0x00000020 // Enter text is the name of a language string
#define CLUSTER_LOOKUPNAME 0x00000040 // Name is the name of a language string
+#define CLUSTER_LOOKUPCLUSTERNAME 0x00000080 // Cluster name is the name of a language string
extern FLevelLocals level;
extern TArray wadlevelinfos;
-
-extern SDWORD ACS_WorldVars[NUM_WORLDVARS];
-extern SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
-
-struct InitIntToZero
-{
- void Init(int &v)
- {
- v = 0;
- }
-};
-typedef TMap, InitIntToZero> FWorldGlobalArray;
-
-extern FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
-extern FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
+extern TArray wadclusterinfos;
extern bool savegamerestore;
@@ -382,8 +491,6 @@ void G_InitLevelLocals (void);
void G_AirControlChanged ();
-const char *G_MaybeLookupLevelName (level_info_t *level);
-
cluster_info_t *FindClusterInfo (int cluster);
level_info_t *FindLevelInfo (const char *mapname);
level_info_t *FindLevelByNum (int num);
@@ -392,9 +499,9 @@ level_info_t *CheckLevelRedirect (level_info_t *info);
FString CalcMapName (int episode, int level);
void G_ParseMapInfo (void);
-void G_UnloadMapInfo ();
void G_ClearSnapshots (void);
+void P_RemoveDefereds ();
void G_SnapshotLevel (void);
void G_UnSnapshotLevel (bool keepPlayers);
struct PNGHandle;
diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp
new file mode 100644
index 00000000..170a9e4b
--- /dev/null
+++ b/src/g_mapinfo.cpp
@@ -0,0 +1,1850 @@
+/*
+** g_level.cpp
+** Parses MAPINFO
+**
+**---------------------------------------------------------------------------
+** Copyright 1998-2006 Randy Heit
+** Copyright 2009 Christoph Oelckers
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**---------------------------------------------------------------------------
+**
+*/
+
+#include
+#include "templates.h"
+#include "g_level.h"
+#include "sc_man.h"
+#include "w_wad.h"
+#include "m_menu.h"
+#include "cmdlib.h"
+#include "v_video.h"
+#include "p_lnspec.h"
+#include "p_setup.h"
+#include "i_system.h"
+#include "gi.h"
+#include "gstrings.h"
+#include "farchive.h"
+#include "p_acs.h"
+#include "doomstat.h"
+#include "d_player.h"
+
+int FindEndSequence (int type, const char *picname);
+
+
+TArray wadclusterinfos;
+TArray wadlevelinfos;
+
+level_info_t TheDefaultLevelInfo;
+static cluster_info_t TheDefaultClusterInfo;
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+static int FindWadLevelInfo (const char *name)
+{
+ for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
+ if (!strnicmp (name, wadlevelinfos[i].mapname, 8))
+ return i;
+
+ return -1;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+level_info_t *FindLevelInfo (const char *mapname)
+{
+ int i;
+
+ if ((i = FindWadLevelInfo (mapname)) > -1)
+ return &wadlevelinfos[i];
+ else
+ {
+ if (TheDefaultLevelInfo.LevelName.IsEmpty())
+ {
+ uppercopy(TheDefaultLevelInfo.skypic1, "SKY1");
+ uppercopy(TheDefaultLevelInfo.skypic2, "SKY1");
+ TheDefaultLevelInfo.LevelName = "Unnamed";
+ }
+ return &TheDefaultLevelInfo;
+ }
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+level_info_t *FindLevelByNum (int num)
+{
+ for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
+ if (wadlevelinfos[i].levelnum == num)
+ return &wadlevelinfos[i];
+
+ return NULL;
+}
+
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+static level_info_t *FindLevelByWarpTrans (int num)
+{
+ for (unsigned i = wadlevelinfos.Size(); i-- != 0; )
+ if (wadlevelinfos[i].WarpTrans == num)
+ return &wadlevelinfos[i];
+
+ return NULL;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+bool CheckWarpTransMap (FString &mapname, bool substitute)
+{
+ if (mapname[0] == '&' && (mapname[1] & 0xDF) == 'W' &&
+ (mapname[2] & 0xDF) == 'T' && mapname[3] == '@')
+ {
+ level_info_t *lev = FindLevelByWarpTrans (atoi (&mapname[4]));
+ if (lev != NULL)
+ {
+ mapname = lev->mapname;
+ return true;
+ }
+ else if (substitute)
+ {
+ char a = mapname[4], b = mapname[5];
+ mapname = "MAP";
+ mapname << a << b;
+ }
+ }
+ return false;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+static int FindWadClusterInfo (int cluster)
+{
+ for (unsigned int i = 0; i < wadclusterinfos.Size(); i++)
+ if (wadclusterinfos[i].cluster == cluster)
+ return i;
+
+ return -1;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+cluster_info_t *FindClusterInfo (int cluster)
+{
+ int i;
+
+ if ((i = FindWadClusterInfo (cluster)) > -1)
+ return &wadclusterinfos[i];
+ else
+ return &TheDefaultClusterInfo;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void G_ClearSnapshots (void)
+{
+ for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
+ {
+ wadlevelinfos[i].ClearSnapshot();
+ }
+}
+
+//==========================================================================
+//
+// Remove any existing defereds
+//
+//==========================================================================
+
+void P_RemoveDefereds (void)
+{
+ for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
+ {
+ wadlevelinfos[i].ClearDefered();
+ }
+}
+
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void level_info_t::Reset()
+{
+ mapname[0] = 0;
+ levelnum = 0;
+ pname[0] = 0;
+ nextmap[0] = 0;
+ secretmap[0] = 0;
+ strcpy (skypic1, "-NOFLAT-");
+ strcpy (skypic2, "-NOFLAT-");
+ cluster = 0;
+ partime = 0;
+ sucktime = 0;
+ flags = 0;
+ flags2 = gameinfo.gametype == GAME_Hexen? 0 : LEVEL2_LAXMONSTERACTIVATION;
+ Music = "";
+ LevelName = "";
+ strcpy (fadetable, "COLORMAP");
+ WallHorizLight = -8;
+ WallVertLight = +8;
+ f1[0] = 0;
+ musicorder = 0;
+ snapshot = NULL;
+ snapshotVer = 0;
+ defered = 0;
+ skyspeed1 = skyspeed2 = 0.f;
+ fadeto = 0;
+ outsidefog = 0xff000000;
+ cdtrack = 0;
+ cdid = 0;
+ gravity = 0.f;
+ aircontrol = 0.f;
+ WarpTrans = 0;
+ airsupply = 20;
+ compatflags = 0;
+ compatmask = 0;
+ Translator = "";
+ RedirectType = 0;
+ RedirectMap[0] = 0;
+ EnterPic = "";
+ ExitPic = "";
+ InterMusic = "";
+ intermusicorder = 0;
+ SoundInfo = "";
+ SndSeq = "";
+ strcpy (bordertexture, gameinfo.borderFlat);
+ teamdamage = 0.f;
+ specialactions.Clear();
+}
+
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+FString level_info_t::LookupLevelName()
+{
+ if (flags & LEVEL_LOOKUPLEVELNAME)
+ {
+ const char *thename;
+ const char *lookedup;
+
+ lookedup = GStrings[LevelName];
+ if (lookedup == NULL)
+ {
+ thename = LevelName;
+ }
+ else
+ {
+ char checkstring[32];
+
+ // Strip out the header from the localized string
+ if (mapname[0] == 'E' && mapname[2] == 'M')
+ {
+ mysnprintf (checkstring, countof(checkstring), "%s: ", mapname);
+ }
+ else if (mapname[0] == 'M' && mapname[1] == 'A' && mapname[2] == 'P')
+ {
+ mysnprintf (checkstring, countof(checkstring), "%d: ", atoi(mapname + 3));
+ }
+ thename = strstr (lookedup, checkstring);
+ if (thename == NULL)
+ {
+ thename = lookedup;
+ }
+ else
+ {
+ thename += strlen (checkstring);
+ }
+ }
+ return thename;
+ }
+ else return LevelName;
+}
+
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void level_info_t::ClearSnapshot()
+{
+ if (snapshot != NULL) delete snapshot;
+ snapshot = NULL;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void level_info_t::ClearDefered()
+{
+ acsdefered_t *def = defered;
+ while (def)
+ {
+ acsdefered_t *next = def->next;
+ delete def;
+ def = next;
+ }
+ defered = NULL;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+level_info_t *level_info_t::CheckLevelRedirect ()
+{
+ if (RedirectType != NAME_None)
+ {
+ const PClass *type = PClass::FindClass(RedirectType);
+ if (type != NULL)
+ {
+ for (int i = 0; i < MAXPLAYERS; ++i)
+ {
+ if (playeringame[i] && players[i].mo->FindInventory (type))
+ {
+ // check for actual presence of the map.
+ if (P_CheckMapData(RedirectMap))
+ {
+ return FindLevelInfo(RedirectMap);
+ }
+ break;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+bool level_info_t::isValid()
+{
+ return mapname[0] != 0 || this == &TheDefaultLevelInfo;
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void cluster_info_t::Reset()
+{
+ cluster = 0;
+ finaleflat[0] = 0;
+ ExitText = "";
+ EnterText = "";
+ MessageMusic = "";
+ musicorder = 0;
+ flags = 0;
+ cdtrack = 0;
+ ClusterName = "";
+ cdid = 0;
+}
+
+
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void FMapInfoParser::ParseOpenBrace()
+{
+ switch(format_type)
+ {
+ default:
+ format_type = sc.CheckString("{")? FMT_New : FMT_Old;
+ if (format_type == FMT_New)
+ sc.SetCMode(true);
+ break;
+
+ case FMT_Old:
+ break;
+
+ case FMT_New:
+ sc.MustGetStringName("{");
+ sc.SetCMode(true);
+ break;
+ }
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+bool FMapInfoParser::ParseCloseBrace()
+{
+ if (format_type == FMT_New)
+ {
+ return sc.Compare("}");
+ }
+ else
+ {
+ // We have to assume that the next keyword
+ // starts a new top level block
+ sc.UnGet();
+ return true;
+ }
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+bool FMapInfoParser::CheckAssign()
+{
+ if (format_type == FMT_New) return sc.CheckString("=");
+ else return false; // force explicit handling
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void FMapInfoParser::ParseAssign()
+{
+ if (format_type == FMT_New) sc.MustGetStringName("=");
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void FMapInfoParser::MustParseAssign()
+{
+ if (format_type == FMT_New) sc.MustGetStringName("=");
+ else sc.ScriptError(NULL);
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void FMapInfoParser::ParseComma()
+{
+ if (format_type == FMT_New) sc.MustGetStringName(",");
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+bool FMapInfoParser::CheckNumber()
+{
+ if (format_type == FMT_New)
+ {
+ if (sc.CheckString(","))
+ {
+ sc.MustGetNumber();
+ return true;
+ }
+ return false;
+ }
+ else return sc.CheckNumber();
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+bool FMapInfoParser::CheckFloat()
+{
+ if (format_type == FMT_New)
+ {
+ if (sc.CheckString(","))
+ {
+ sc.MustGetFloat();
+ return true;
+ }
+ return false;
+ }
+ else return sc.CheckFloat();
+}
+
+//==========================================================================
+//
+// skips an entire parameter list that's separated by commas
+//
+//==========================================================================
+
+void FMapInfoParser::SkipToNext()
+{
+ if (sc.CheckString("="))
+ {
+ do
+ {
+ sc.MustGetString();
+ }
+ while (sc.CheckString(","));
+ }
+}
+
+//==========================================================================
+//
+// ParseLookupname
+// Parses a string that may reference the string table
+//
+//==========================================================================
+
+bool FMapInfoParser::ParseLookupName(FString &dest)
+{
+ sc.MustGetString();
+ if (sc.Compare("lookup"))
+ {
+ ParseComma();
+ sc.MustGetString();
+ dest = sc.String;
+ return true;
+ }
+ else if (sc.String[0] == '$')
+ {
+ dest = sc.String+1;
+ return true;
+ }
+ else if (format_type == FMT_Old)
+ {
+ dest = sc.String;
+ return false;
+ }
+ else
+ {
+ sc.UnGet();
+ dest = "";
+ do
+ {
+ sc.MustGetString();
+ dest << sc.String << '\n';
+ }
+ while (sc.CheckString(","));
+ // strip off the last newline
+ dest.Truncate(long(dest.Len()-1));
+ return false;
+ }
+}
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void FMapInfoParser::ParseLumpOrTextureName(char *name)
+{
+ sc.MustGetString();
+ uppercopy(name, sc.String);
+ name[8]=0;
+}
+
+
+//==========================================================================
+//
+//
+//==========================================================================
+
+void FMapInfoParser::ParseMusic(FString &name, int &order)
+{
+ sc.MustGetString();
+
+ order = 0;
+ char *colon = strchr (sc.String, ':');
+ if (colon)
+ {
+ order = atoi(colon+1);
+ *colon = 0;
+ }
+ name = sc.String;
+ if (!colon && CheckNumber())
+ {
+ order = sc.Number;
+ }
+}
+
+//==========================================================================
+//
+// ParseCluster
+// Parses a cluster definition
+//
+//==========================================================================
+
+void FMapInfoParser::ParseCluster()
+{
+ sc.MustGetNumber ();
+ int clusterindex = FindWadClusterInfo (sc.Number);
+ if (clusterindex == -1)
+ {
+ clusterindex = wadclusterinfos.Reserve(1);
+ }
+
+ cluster_info_t *clusterinfo = &wadclusterinfos[clusterindex];
+ clusterinfo->Reset();
+ clusterinfo->cluster = sc.Number;
+
+ ParseOpenBrace();
+
+ while (sc.GetString())
+ {
+ if (sc.Compare("name"))
+ {
+ ParseAssign();
+ if (ParseLookupName(clusterinfo->ClusterName))
+ clusterinfo->flags |= CLUSTER_LOOKUPCLUSTERNAME;
+ }
+ else if (sc.Compare("entertext"))
+ {
+ ParseAssign();
+ if (ParseLookupName(clusterinfo->EnterText))
+ clusterinfo->flags |= CLUSTER_LOOKUPENTERTEXT;
+ }
+ else if (sc.Compare("exittext"))
+ {
+ ParseAssign();
+ if (ParseLookupName(clusterinfo->ExitText))
+ clusterinfo->flags |= CLUSTER_LOOKUPEXITTEXT;
+ }
+ else if (sc.Compare("music"))
+ {
+ int order = 0;
+
+ ParseAssign();
+ ParseMusic(clusterinfo->MessageMusic, clusterinfo->musicorder);
+ }
+ else if (sc.Compare("flat"))
+ {
+ ParseAssign();
+ ParseLumpOrTextureName(clusterinfo->finaleflat);
+ }
+ else if (sc.Compare("pic"))
+ {
+ ParseAssign();
+ ParseLumpOrTextureName(clusterinfo->finaleflat);
+ clusterinfo->flags |= CLUSTER_FINALEPIC;
+ }
+ else if (sc.Compare("hub"))
+ {
+ clusterinfo->flags |= CLUSTER_HUB;
+ }
+ else if (sc.Compare("cdtrack"))
+ {
+ ParseAssign();
+ sc.MustGetNumber();
+ clusterinfo->cdtrack = sc.Number;
+ }
+ else if (sc.Compare("cdid"))
+ {
+ ParseAssign();
+ sc.MustGetString();
+ clusterinfo->cdid = strtoul (sc.String, NULL, 16);
+ }
+ else if (sc.Compare("entertextislump"))
+ {
+ clusterinfo->flags |= CLUSTER_ENTERTEXTINLUMP;
+ }
+ else if (sc.Compare("exittextislump"))
+ {
+ clusterinfo->flags |= CLUSTER_EXITTEXTINLUMP;
+ }
+ else if (!ParseCloseBrace())
+ {
+ // Unknown
+ sc.ScriptMessage("Unknown property '%s' found in map definition\n", sc.String);
+ SkipToNext();
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+
+//==========================================================================
+//
+// ParseNextMap
+// Parses a next map field
+//
+//==========================================================================
+
+void FMapInfoParser::ParseNextMap(char *mapname)
+{
+ EndSequence newSeq;
+ bool useseq = false;
+
+ if (sc.CheckNumber())
+ {
+ if (HexenHack)
+ {
+ mysnprintf (mapname, 9, "&wt@%02d", sc.Number);
+ }
+ else
+ {
+ mysnprintf (mapname, 9, "MAP%02d", sc.Number);
+ }
+ }
+ else
+ {
+ sc.MustGetString();
+
+ if (sc.Compare("endgame"))
+ {
+ newSeq.Advanced = true;
+ newSeq.EndType = END_Pic1;
+ newSeq.PlayTheEnd = false;
+ newSeq.MusicLooping = true;
+ sc.MustGetStringName("{");
+ while (!sc.CheckString("}"))
+ {
+ sc.MustGetString();
+ if (sc.Compare("pic"))
+ {
+ ParseAssign();
+ sc.MustGetString();
+ newSeq.EndType = END_Pic;
+ newSeq.PicName = sc.String;
+ }
+ else if (sc.Compare("hscroll"))
+ {
+ ParseAssign();
+ newSeq.EndType = END_Bunny;
+ sc.MustGetString();
+ newSeq.PicName = sc.String;
+ ParseComma();
+ sc.MustGetString();
+ newSeq.PicName2 = sc.String;
+ if (CheckNumber())
+ newSeq.PlayTheEnd = !!sc.Number;
+ }
+ else if (sc.Compare("vscroll"))
+ {
+ ParseAssign();
+ newSeq.EndType = END_Demon;
+ sc.MustGetString();
+ newSeq.PicName = sc.String;
+ ParseComma();
+ sc.MustGetString();
+ newSeq.PicName2 = sc.String;
+ }
+ else if (sc.Compare("cast"))
+ {
+ newSeq.EndType = END_Cast;
+ }
+ else if (sc.Compare("music"))
+ {
+ ParseAssign();
+ sc.MustGetString();
+ newSeq.Music = sc.String;
+ if (CheckNumber())
+ {
+ newSeq.MusicLooping = !!sc.Number;
+ }
+ }
+ else
+ {
+ if (format_type == FMT_New)
+ {
+ // Unknown
+ sc.ScriptMessage("Unknown property '%s' found in endgame definition\n", sc.String);
+ SkipToNext();
+ }
+ else
+ {
+ sc.ScriptError("Unknown property '%s' found in endgame definition\n", sc.String);
+ }
+
+ }
+ }
+ useseq = true;
+ }
+ else if (strnicmp (sc.String, "EndGame", 7) == 0)
+ {
+ int type;
+ switch (sc.String[7])
+ {
+ case '1': type = END_Pic1; break;
+ case '2': type = END_Pic2; break;
+ case '3': type = END_Bunny; break;
+ case 'C': type = END_Cast; break;
+ case 'W': type = END_Underwater; break;
+ case 'S': type = END_Strife; break;
+ default: type = END_Pic3; break;
+ }
+ newSeq.EndType = type;
+ useseq = true;
+ }
+ else if (sc.Compare("endpic"))
+ {
+ ParseComma();
+ sc.MustGetString ();
+ newSeq.EndType = END_Pic;
+ newSeq.PicName = sc.String;
+ useseq = true;
+ }
+ else if (sc.Compare("endbunny"))
+ {
+ newSeq.EndType = END_Bunny;
+ useseq = true;
+ }
+ else if (sc.Compare("endcast"))
+ {
+ newSeq.EndType = END_Cast;
+ useseq = true;
+ }
+ else if (sc.Compare("enddemon"))
+ {
+ newSeq.EndType = END_Demon;
+ useseq = true;
+ }
+ else if (sc.Compare("endchess"))
+ {
+ newSeq.EndType = END_Chess;
+ useseq = true;
+ }
+ else if (sc.Compare("endunderwater"))
+ {
+ newSeq.EndType = END_Underwater;
+ useseq = true;
+ }
+ else if (sc.Compare("endbuystrife"))
+ {
+ newSeq.EndType = END_BuyStrife;
+ useseq = true;
+ }
+ else
+ {
+ strncpy (mapname, sc.String, 8);
+ }
+ if (useseq)
+ {
+ int seqnum = -1;
+
+ if (!newSeq.Advanced)
+ {
+ seqnum = FindEndSequence (newSeq.EndType, newSeq.PicName);
+ }
+
+ if (seqnum == -1)
+ {
+ seqnum = (int)EndSequences.Push (newSeq);
+ }
+ strcpy (mapname, "enDSeQ");
+ *((WORD *)(mapname + 6)) = (WORD)seqnum;
+ }
+ }
+}
+
+//==========================================================================
+//
+// Map options
+//
+//==========================================================================
+
+DEFINE_MAP_OPTION(levelnum, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->levelnum = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(next, true)
+{
+ parse.ParseAssign();
+ parse.ParseNextMap(info->nextmap);
+}
+
+DEFINE_MAP_OPTION(secretnext, true)
+{
+ parse.ParseAssign();
+ parse.ParseNextMap(info->secretmap);
+}
+
+DEFINE_MAP_OPTION(cluster, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->cluster = parse.sc.Number;
+
+ // If this cluster hasn't been defined yet, add it. This is especially needed
+ // for Hexen, because it doesn't have clusterdefs. If we don't do this, every
+ // level on Hexen will sometimes be considered as being on the same hub,
+ // depending on the check done.
+ if (FindWadClusterInfo (parse.sc.Number) == -1)
+ {
+ unsigned int clusterindex = wadclusterinfos.Reserve(1);
+ cluster_info_t *clusterinfo = &wadclusterinfos[clusterindex];
+ clusterinfo->cluster = parse.sc.Number;
+ if (parse.HexenHack)
+ {
+ clusterinfo->flags |= CLUSTER_HUB;
+ }
+ }
+}
+
+DEFINE_MAP_OPTION(sky1, true)
+{
+ parse.ParseAssign();
+ parse.ParseLumpOrTextureName(info->skypic1);
+ if (parse.CheckFloat())
+ {
+ if (parse.HexenHack)
+ {
+ parse.sc.Float /= 256;
+ }
+ info->skyspeed1 = parse.sc.Float * (35.f / 1000.f);
+ }
+}
+
+DEFINE_MAP_OPTION(sky2, true)
+{
+ parse.ParseAssign();
+ parse.ParseLumpOrTextureName(info->skypic2);
+ if (parse.CheckFloat())
+ {
+ if (parse.HexenHack)
+ {
+ parse.sc.Float /= 256;
+ }
+ info->skyspeed2 = parse.sc.Float * (35.f / 1000.f);
+ }
+}
+
+DEFINE_MAP_OPTION(fade, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->fadeto = V_GetColor(NULL, parse.sc.String);
+}
+
+DEFINE_MAP_OPTION(outsidefog, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->outsidefog = V_GetColor(NULL, parse.sc.String);
+}
+
+DEFINE_MAP_OPTION(titlepatch, true)
+{
+ parse.ParseAssign();
+ parse.ParseLumpOrTextureName(info->pname);
+}
+
+DEFINE_MAP_OPTION(partime, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->partime = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(par, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->partime = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(sucktime, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->sucktime = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(music, true)
+{
+ parse.ParseAssign();
+ parse.ParseMusic(info->Music, info->musicorder);
+ // Flag the level so that the $MAP command doesn't override this.
+ info->flags2 |= LEVEL2_MUSICDEFINED;
+}
+
+DEFINE_MAP_OPTION(intermusic, true)
+{
+ parse.ParseAssign();
+ parse.ParseMusic(info->InterMusic, info->intermusicorder);
+}
+
+DEFINE_MAP_OPTION(fadetable, true)
+{
+ parse.ParseAssign();
+ parse.ParseLumpOrTextureName(info->fadetable);
+}
+
+DEFINE_MAP_OPTION(evenlighting, true)
+{
+ info->WallVertLight = info->WallHorizLight = 0;
+}
+
+DEFINE_MAP_OPTION(cdtrack, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->cdtrack = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(cdid, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->cdid = strtoul (parse.sc.String, NULL, 16);
+}
+
+DEFINE_MAP_OPTION(warptrans, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->WarpTrans = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(vertwallshade, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->WallVertLight = (SBYTE)clamp (parse.sc.Number / 2, -128, 127);
+}
+
+DEFINE_MAP_OPTION(horizwallshade, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->WallHorizLight = (SBYTE)clamp (parse.sc.Number / 2, -128, 127);
+}
+
+DEFINE_MAP_OPTION(gravity, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetFloat();
+ info->gravity = parse.sc.Float;
+}
+
+DEFINE_MAP_OPTION(aircontrol, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetFloat();
+ info->aircontrol = parse.sc.Float;
+}
+
+DEFINE_MAP_OPTION(airsupply, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ info->airsupply = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(interpic, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->ExitPic = parse.sc.String;
+}
+
+DEFINE_MAP_OPTION(exitpic, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->ExitPic = parse.sc.String;
+}
+
+DEFINE_MAP_OPTION(enterpic, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->EnterPic = parse.sc.String;
+}
+
+DEFINE_MAP_OPTION(specialaction, true)
+{
+ parse.ParseAssign();
+
+ FSpecialAction *sa = &info->specialactions[info->specialactions.Reserve(1)];
+ int min_arg, max_arg;
+ if (parse.format_type == parse.FMT_Old) parse.sc.SetCMode(true);
+ parse.sc.MustGetString();
+ sa->Type = FName(parse.sc.String);
+ parse.sc.CheckString(",");
+ parse.sc.MustGetString();
+ sa->Action = P_FindLineSpecial(parse.sc.String, &min_arg, &max_arg);
+ if (sa->Action == 0 || min_arg < 0)
+ {
+ parse.sc.ScriptError("Unknown specialaction '%s'");
+ }
+ int j = 0;
+ while (j < 5 && parse.sc.CheckString(","))
+ {
+ parse.sc.MustGetNumber();
+ sa->Args[j++] = parse.sc.Number;
+ }
+ if (parse.format_type == parse.FMT_Old) parse.sc.SetCMode(false);
+}
+
+DEFINE_MAP_OPTION(redirect, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->RedirectType = parse.sc.String;
+ parse.ParseComma();
+ parse.ParseLumpOrTextureName(info->RedirectMap);
+}
+
+DEFINE_MAP_OPTION(sndseq, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->SndSeq = parse.sc.String;
+}
+
+DEFINE_MAP_OPTION(sndinfo, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->SoundInfo = parse.sc.String;
+}
+
+DEFINE_MAP_OPTION(soundinfo, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->SoundInfo = parse.sc.String;
+}
+
+DEFINE_MAP_OPTION(translator, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetString();
+ info->Translator = parse.sc.String;
+}
+
+DEFINE_MAP_OPTION(bordertexture, true)
+{
+ parse.ParseAssign();
+ parse.ParseLumpOrTextureName(info->bordertexture);
+}
+
+DEFINE_MAP_OPTION(f1, true)
+{
+ parse.ParseAssign();
+ parse.ParseLumpOrTextureName(info->f1);
+}
+
+DEFINE_MAP_OPTION(teamdamage, true)
+{
+ parse.ParseAssign();
+ parse.sc.MustGetFloat();
+ info->teamdamage = parse.sc.Float;
+}
+
+//==========================================================================
+//
+// All flag based map options
+//
+//==========================================================================
+
+enum EMIType
+{
+ MITYPE_IGNORE,
+ MITYPE_EATNEXT,
+ MITYPE_SETFLAG,
+ MITYPE_CLRFLAG,
+ MITYPE_SCFLAGS,
+ MITYPE_SETFLAG2,
+ MITYPE_CLRFLAG2,
+ MITYPE_SCFLAGS2,
+ MITYPE_COMPATFLAG,
+};
+
+struct MapInfoFlagHandler
+{
+ const char *name;
+ EMIType type;
+ DWORD data1, data2;
+}
+MapFlagHandlers[] =
+{
+ { "nointermission", MITYPE_SETFLAG, LEVEL_NOINTERMISSION, 0 },
+ { "intermission", MITYPE_CLRFLAG, LEVEL_NOINTERMISSION, 0 },
+ { "doublesky", MITYPE_SETFLAG, LEVEL_DOUBLESKY, 0 },
+ { "nosoundclipping", MITYPE_IGNORE, 0, 0 }, // was nosoundclipping
+ { "allowmonstertelefrags", MITYPE_SETFLAG, LEVEL_MONSTERSTELEFRAG, 0 },
+ { "map07special", MITYPE_SETFLAG, LEVEL_MAP07SPECIAL, 0 },
+ { "baronspecial", MITYPE_SETFLAG, LEVEL_BRUISERSPECIAL, 0 },
+ { "cyberdemonspecial", MITYPE_SETFLAG, LEVEL_CYBORGSPECIAL, 0 },
+ { "spidermastermindspecial", MITYPE_SETFLAG, LEVEL_SPIDERSPECIAL, 0 },
+ { "minotaurspecial", MITYPE_SETFLAG, LEVEL_MINOTAURSPECIAL, 0 },
+ { "dsparilspecial", MITYPE_SETFLAG, LEVEL_SORCERER2SPECIAL, 0 },
+ { "ironlichspecial", MITYPE_SETFLAG, LEVEL_HEADSPECIAL, 0 },
+ { "specialaction_exitlevel", MITYPE_SCFLAGS, 0, ~LEVEL_SPECACTIONSMASK },
+ { "specialaction_opendoor", MITYPE_SCFLAGS, LEVEL_SPECOPENDOOR, ~LEVEL_SPECACTIONSMASK },
+ { "specialaction_lowerfloor", MITYPE_SCFLAGS, LEVEL_SPECLOWERFLOOR, ~LEVEL_SPECACTIONSMASK },
+ { "specialaction_killmonsters", MITYPE_SETFLAG, LEVEL_SPECKILLMONSTERS, 0 },
+ { "lightning", MITYPE_SETFLAG, LEVEL_STARTLIGHTNING, 0 },
+ { "smoothlighting", MITYPE_SETFLAG2, LEVEL2_SMOOTHLIGHTING, 0 },
+ { "noautosequences", MITYPE_SETFLAG, LEVEL_SNDSEQTOTALCTRL, 0 },
+ { "autosequences", MITYPE_CLRFLAG, LEVEL_SNDSEQTOTALCTRL, 0 },
+ { "forcenoskystretch", MITYPE_SETFLAG, LEVEL_FORCENOSKYSTRETCH, 0 },
+ { "skystretch", MITYPE_CLRFLAG, LEVEL_FORCENOSKYSTRETCH, 0 },
+ { "allowfreelook", MITYPE_SCFLAGS, LEVEL_FREELOOK_YES, ~LEVEL_FREELOOK_NO },
+ { "nofreelook", MITYPE_SCFLAGS, LEVEL_FREELOOK_NO, ~LEVEL_FREELOOK_YES },
+ { "allowjump", MITYPE_CLRFLAG, LEVEL_JUMP_NO, 0 },
+ { "nojump", MITYPE_SETFLAG, LEVEL_JUMP_NO, 0 },
+ { "fallingdamage", MITYPE_SCFLAGS, LEVEL_FALLDMG_HX, ~LEVEL_FALLDMG_ZD },
+ { "oldfallingdamage", MITYPE_SCFLAGS, LEVEL_FALLDMG_ZD, ~LEVEL_FALLDMG_HX },
+ { "forcefallingdamage", MITYPE_SCFLAGS, LEVEL_FALLDMG_ZD, ~LEVEL_FALLDMG_HX },
+ { "strifefallingdamage", MITYPE_SETFLAG, LEVEL_FALLDMG_ZD|LEVEL_FALLDMG_HX, 0 },
+ { "nofallingdamage", MITYPE_SCFLAGS, 0, ~(LEVEL_FALLDMG_ZD|LEVEL_FALLDMG_HX) },
+ { "noallies", MITYPE_SETFLAG, LEVEL_NOALLIES, 0 },
+ { "filterstarts", MITYPE_SETFLAG, LEVEL_FILTERSTARTS, 0 },
+ { "activateowndeathspecials", MITYPE_SETFLAG, LEVEL_ACTOWNSPECIAL, 0 },
+ { "killeractivatesdeathspecials", MITYPE_CLRFLAG, LEVEL_ACTOWNSPECIAL, 0 },
+ { "missilesactivateimpactlines", MITYPE_SETFLAG2, LEVEL2_MISSILESACTIVATEIMPACT, 0 },
+ { "missileshootersactivetimpactlines",MITYPE_CLRFLAG2, LEVEL2_MISSILESACTIVATEIMPACT, 0 },
+ { "noinventorybar", MITYPE_SETFLAG, LEVEL_NOINVENTORYBAR, 0 },
+ { "deathslideshow", MITYPE_SETFLAG2, LEVEL2_DEATHSLIDESHOW, 0 },
+ { "strictmonsteractivation", MITYPE_CLRFLAG2, LEVEL2_LAXMONSTERACTIVATION, LEVEL2_LAXACTIVATIONMAPINFO },
+ { "laxmonsteractivation", MITYPE_SETFLAG2, LEVEL2_LAXMONSTERACTIVATION, LEVEL2_LAXACTIVATIONMAPINFO },
+ { "additive_scrollers", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
+ { "keepfullinventory", MITYPE_SETFLAG2, LEVEL2_KEEPFULLINVENTORY, 0 },
+ { "monsterfallingdamage", MITYPE_SETFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 },
+ { "nomonsterfallingdamage", MITYPE_CLRFLAG2, LEVEL2_MONSTERFALLINGDAMAGE, 0 },
+ { "clipmidtextures", MITYPE_SETFLAG2, LEVEL2_CLIPMIDTEX, 0 },
+ { "wrapmidtextures", MITYPE_SETFLAG2, LEVEL2_WRAPMIDTEX, 0 },
+ { "allowcrouch", MITYPE_CLRFLAG, LEVEL_CROUCH_NO, 0 },
+ { "nocrouch", MITYPE_SETFLAG, LEVEL_CROUCH_NO, 0 },
+ { "pausemusicinmenus", MITYPE_SCFLAGS2, LEVEL2_PAUSE_MUSIC_IN_MENUS, 0 },
+ { "noinfighting", MITYPE_SCFLAGS2, LEVEL2_NOINFIGHTING, ~LEVEL2_TOTALINFIGHTING },
+ { "normalinfighting", MITYPE_SCFLAGS2, 0, ~(LEVEL2_NOINFIGHTING|LEVEL2_TOTALINFIGHTING)},
+ { "totalinfighting", MITYPE_SCFLAGS2, LEVEL2_TOTALINFIGHTING, ~LEVEL2_NOINFIGHTING },
+ { "infiniteflightpowerup", MITYPE_SETFLAG2, LEVEL2_INFINITE_FLIGHT, 0 },
+ { "noinfiniteflightpowerup", MITYPE_CLRFLAG2, LEVEL2_INFINITE_FLIGHT, 0 },
+ { "allowrespawn", MITYPE_SETFLAG2, LEVEL2_ALLOWRESPAWN, 0 },
+ { "teamplayon", MITYPE_SCFLAGS2, LEVEL2_FORCETEAMPLAYON, ~LEVEL2_FORCETEAMPLAYOFF },
+ { "teamplayoff", MITYPE_SCFLAGS2, LEVEL2_FORCETEAMPLAYOFF, ~LEVEL2_FORCETEAMPLAYON },
+ { "checkswitchrange", MITYPE_SETFLAG2, LEVEL2_CHECKSWITCHRANGE, 0 },
+ { "nocheckswitchrange", MITYPE_CLRFLAG2, LEVEL2_CHECKSWITCHRANGE, 0 },
+ { "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 },
+ { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes
+ { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX},
+ { "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX},
+ { "compat_limitpain", MITYPE_COMPATFLAG, COMPATF_LIMITPAIN},
+ { "compat_nopassover", MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ},
+ { "compat_notossdrops", MITYPE_COMPATFLAG, COMPATF_NOTOSSDROPS},
+ { "compat_useblocking", MITYPE_COMPATFLAG, COMPATF_USEBLOCKING},
+ { "compat_nodoorlight", MITYPE_COMPATFLAG, COMPATF_NODOORLIGHT},
+ { "compat_ravenscroll", MITYPE_COMPATFLAG, COMPATF_RAVENSCROLL},
+ { "compat_soundtarget", MITYPE_COMPATFLAG, COMPATF_SOUNDTARGET},
+ { "compat_dehhealth", MITYPE_COMPATFLAG, COMPATF_DEHHEALTH},
+ { "compat_trace", MITYPE_COMPATFLAG, COMPATF_TRACE},
+ { "compat_dropoff", MITYPE_COMPATFLAG, COMPATF_DROPOFF},
+ { "compat_boomscroll", MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
+ { "compat_invisibility", MITYPE_COMPATFLAG, COMPATF_INVISIBILITY},
+ { "compat_silent_instant_floors", MITYPE_COMPATFLAG, COMPATF_SILENT_INSTANT_FLOORS},
+ { "compat_sectorsounds", MITYPE_COMPATFLAG, COMPATF_SECTORSOUNDS},
+ { "compat_missileclip", MITYPE_COMPATFLAG, COMPATF_MISSILECLIP},
+ { "compat_crossdropoff", MITYPE_COMPATFLAG, COMPATF_CROSSDROPOFF},
+ { "cd_start_track", MITYPE_EATNEXT, 0, 0 },
+ { "cd_end1_track", MITYPE_EATNEXT, 0, 0 },
+ { "cd_end2_track", MITYPE_EATNEXT, 0, 0 },
+ { "cd_end3_track", MITYPE_EATNEXT, 0, 0 },
+ { "cd_intermission_track", MITYPE_EATNEXT, 0, 0 },
+ { "cd_title_track", MITYPE_EATNEXT, 0, 0 },
+ { NULL, MITYPE_IGNORE, 0}
+};
+
+//==========================================================================
+//
+// ParseMapDefinition
+// Parses the body of a map definition, including defaultmap etc.
+//
+//==========================================================================
+
+void FMapInfoParser::ParseMapDefinition(level_info_t &info)
+{
+ int index;
+
+ ParseOpenBrace();
+
+ while (sc.GetString())
+ {
+ if ((index = sc.MatchString(&MapFlagHandlers->name, sizeof(*MapFlagHandlers))) >= 0)
+ {
+ MapInfoFlagHandler *handler = &MapFlagHandlers[index];
+ switch (handler->type)
+ {
+ case MITYPE_EATNEXT:
+ ParseAssign();
+ sc.MustGetString();
+ break;
+
+ case MITYPE_IGNORE:
+ break;
+
+ case MITYPE_SETFLAG:
+ info.flags |= handler->data1;
+ info.flags |= handler->data2;
+ break;
+
+ case MITYPE_CLRFLAG:
+ info.flags &= ~handler->data1;
+ info.flags |= handler->data2;
+ break;
+
+ case MITYPE_SCFLAGS:
+ info.flags = (info.flags & handler->data2) | handler->data1;
+ break;
+
+ case MITYPE_SETFLAG2:
+ info.flags2 |= handler->data1;
+ info.flags2 |= handler->data2;
+ break;
+
+ case MITYPE_CLRFLAG2:
+ info.flags2 &= ~handler->data1;
+ info.flags2 |= handler->data2;
+ break;
+
+ case MITYPE_SCFLAGS2:
+ info.flags2 = (info.flags2 & handler->data2) | handler->data1;
+ break;
+
+ case MITYPE_COMPATFLAG:
+ {
+ int set = 1;
+ if (format_type == FMT_New)
+ {
+ if (CheckAssign())
+ {
+ sc.MustGetNumber();
+ set = sc.Number;
+ }
+ }
+ else
+ {
+ if (sc.CheckNumber()) set = sc.Number;
+ }
+
+ if (set) info.compatflags |= handler->data1;
+ else info.compatflags &= ~handler->data1;
+ info.compatmask |= handler->data1;
+ }
+ break;
+
+ default:
+ // should never happen
+ assert(false);
+ break;
+ }
+ }
+ else
+ {
+ TAutoSegIterator probe;
+ bool success = false;
+
+ while (++probe != NULL)
+ {
+ if (sc.Compare(probe->name))
+ {
+ probe->handler(*this, &info);
+ success = true;
+ break;
+ }
+ }
+
+ if (!success)
+ {
+ if (!ParseCloseBrace())
+ {
+ // Unknown
+ sc.ScriptMessage("Unknown property '%s' found in map definition\n", sc.String);
+ SkipToNext();
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+//==========================================================================
+//
+// GetDefaultLevelNum
+// Gets a default level num from a map name.
+//
+//==========================================================================
+
+static int GetDefaultLevelNum(const char *mapname)
+{
+ if (!strnicmp (mapname, "MAP", 3) && strlen(mapname) <= 5)
+ {
+ int mapnum = atoi (mapname + 3);
+
+ if (mapnum >= 1 && mapnum <= 99)
+ return mapnum;
+ }
+ else if (mapname[0] == 'E' &&
+ mapname[1] >= '0' && mapname[1] <= '9' &&
+ mapname[2] == 'M' &&
+ mapname[3] >= '0' && mapname[3] <= '9')
+ {
+ int epinum = mapname[1] - '1';
+ int mapnum = mapname[3] - '0';
+ return epinum*10 + mapnum;
+ }
+ return 0;
+}
+
+//==========================================================================
+//
+// ParseMapHeader
+// Parses the header of a map definition ('map mapxx mapname')
+//
+//==========================================================================
+
+level_info_t *FMapInfoParser::ParseMapHeader(level_info_t &defaultinfo)
+{
+ FName mapname;
+
+ if (sc.CheckNumber())
+ { // MAPNAME is a number; assume a Hexen wad
+ char maptemp[8];
+ mysnprintf (maptemp, countof(maptemp), "MAP%02d", sc.Number);
+ mapname = maptemp;
+ HexenHack = true;
+ }
+ else
+ {
+ sc.MustGetString();
+ mapname = sc.String;
+ }
+ int levelindex = FindWadLevelInfo (mapname);
+ if (levelindex == -1)
+ {
+ levelindex = wadlevelinfos.Reserve(1);
+ }
+ level_info_t *levelinfo = &wadlevelinfos[levelindex];
+ *levelinfo = defaultinfo;
+ if (HexenHack)
+ {
+ levelinfo->WallHorizLight = levelinfo->WallVertLight = 0;
+
+ // Hexen levels are automatically nointermission,
+ // no auto sound sequences, falling damage,
+ // monsters activate their own specials, and missiles
+ // are always the activators of impact lines.
+ levelinfo->flags |= LEVEL_NOINTERMISSION
+ | LEVEL_SNDSEQTOTALCTRL
+ | LEVEL_FALLDMG_HX
+ | LEVEL_ACTOWNSPECIAL;
+ levelinfo->flags2|= LEVEL2_HEXENHACK
+ | LEVEL2_INFINITE_FLIGHT
+ | LEVEL2_MISSILESACTIVATEIMPACT
+ | LEVEL2_MONSTERFALLINGDAMAGE;
+
+ }
+
+ uppercopy (levelinfo->mapname, mapname);
+ levelinfo->mapname[8] = 0;
+ sc.MustGetString ();
+ if (sc.String[0] == '$')
+ {
+ // For consistency with other definitions allow $Stringtablename here, too.
+ levelinfo->flags |= LEVEL_LOOKUPLEVELNAME;
+ levelinfo->LevelName = sc.String + 1;
+ }
+ else
+ {
+ if (sc.Compare ("lookup"))
+ {
+ sc.MustGetString ();
+ levelinfo->flags |= LEVEL_LOOKUPLEVELNAME;
+ }
+ levelinfo->LevelName = sc.String;
+ }
+
+ // Set up levelnum now so that you can use Teleport_NewMap specials
+ // to teleport to maps with standard names without needing a levelnum.
+ levelinfo->levelnum = GetDefaultLevelNum(levelinfo->mapname);
+
+ return levelinfo;
+}
+
+
+//==========================================================================
+//
+// Episode definitions start with the header "episode "
+// and then can be followed by any of the following:
+//
+// name "Episode name as text"
+// picname "Picture to display the episode name"
+// key "Shortcut key for the menu"
+// noskillmenu
+// remove
+//
+//==========================================================================
+
+void FMapInfoParser::ParseEpisodeInfo ()
+{
+ int i;
+ char map[9];
+ char *pic = NULL;
+ bool picisgfx = false; // Shut up, GCC!!!!
+ bool remove = false;
+ char key = 0;
+ bool noskill = false;
+ bool optional = false;
+ bool extended = false;
+
+ // Get map name
+ sc.MustGetString ();
+ uppercopy (map, sc.String);
+ map[8] = 0;
+
+ if (sc.CheckString ("teaser"))
+ {
+ sc.MustGetString ();
+ if (gameinfo.flags & GI_SHAREWARE)
+ {
+ uppercopy (map, sc.String);
+ }
+ }
+
+ ParseOpenBrace();
+
+ while (sc.GetString())
+ {
+ if (sc.Compare ("optional"))
+ {
+ // For M4 in Doom
+ optional = true;
+ }
+ else if (sc.Compare ("extended"))
+ {
+ // For M4 and M5 in Heretic
+ extended = true;
+ }
+ else if (sc.Compare ("name"))
+ {
+ ParseAssign();
+ sc.MustGetString ();
+ ReplaceString (&pic, sc.String);
+ picisgfx = false;
+ }
+ else if (sc.Compare ("picname"))
+ {
+ ParseAssign();
+ sc.MustGetString ();
+ ReplaceString (&pic, sc.String);
+ picisgfx = true;
+ }
+ else if (sc.Compare ("remove"))
+ {
+ remove = true;
+ }
+ else if (sc.Compare ("key"))
+ {
+ ParseAssign();
+ sc.MustGetString ();
+ key = sc.String[0];
+ }
+ else if (sc.Compare("noskillmenu"))
+ {
+ noskill = true;
+ }
+ else if (!ParseCloseBrace())
+ {
+ // Unknown
+ sc.ScriptMessage("Unknown property '%s' found in episode definition\n", sc.String);
+ SkipToNext();
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (extended && !(gameinfo.flags & GI_MENUHACK_EXTENDED))
+ { // If the episode is for the extended Heretic, but this is
+ // not the extended Heretic, ignore it.
+ return;
+ }
+
+ if (optional && !remove)
+ {
+ if (!P_CheckMapData(map))
+ {
+ // If the episode is optional and the map does not exist
+ // just ignore this episode definition.
+ return;
+ }
+ }
+
+
+ for (i = 0; i < EpiDef.numitems; ++i)
+ {
+ if (strncmp (EpisodeMaps[i], map, 8) == 0)
+ {
+ break;
+ }
+ }
+
+ if (remove)
+ {
+ // If the remove property is given for an episode, remove it.
+ if (i < EpiDef.numitems)
+ {
+ if (i+1 < EpiDef.numitems)
+ {
+ memmove (&EpisodeMaps[i], &EpisodeMaps[i+1],
+ sizeof(EpisodeMaps[0])*(EpiDef.numitems - i - 1));
+ memmove (&EpisodeMenu[i], &EpisodeMenu[i+1],
+ sizeof(EpisodeMenu[0])*(EpiDef.numitems - i - 1));
+ memmove (&EpisodeNoSkill[i], &EpisodeNoSkill[i+1],
+ sizeof(EpisodeNoSkill[0])*(EpiDef.numitems - i - 1));
+ }
+ EpiDef.numitems--;
+ }
+ }
+ else
+ {
+ if (pic == NULL)
+ {
+ pic = copystring (map);
+ picisgfx = false;
+ }
+
+ if (i == EpiDef.numitems)
+ {
+ if (EpiDef.numitems == MAX_EPISODES)
+ {
+ i = EpiDef.numitems - 1;
+ }
+ else
+ {
+ i = EpiDef.numitems++;
+ }
+ }
+ else
+ {
+ delete[] const_cast(EpisodeMenu[i].name);
+ }
+
+ EpisodeMenu[i].name = pic;
+ EpisodeMenu[i].alphaKey = tolower(key);
+ EpisodeMenu[i].fulltext = !picisgfx;
+ EpisodeNoSkill[i] = noskill;
+ strncpy (EpisodeMaps[i], map, 8);
+ }
+}
+
+
+//==========================================================================
+//
+// Clears episode definitions
+//
+//==========================================================================
+
+void ClearEpisodes()
+{
+ for (int i = 0; i < EpiDef.numitems; ++i)
+ {
+ delete[] const_cast(EpisodeMenu[i].name);
+ EpisodeMenu[i].name = NULL;
+ }
+ EpiDef.numitems = 0;
+}
+
+//==========================================================================
+//
+// SetLevelNum
+// Avoid duplicate levelnums. The level being set always has precedence.
+//
+//==========================================================================
+
+static void SetLevelNum (level_info_t *info, int num)
+{
+ for (unsigned int i = 0; i < wadlevelinfos.Size(); ++i)
+ {
+ if (wadlevelinfos[i].levelnum == num)
+ wadlevelinfos[i].levelnum = 0;
+ }
+ info->levelnum = num;
+}
+
+//==========================================================================
+//
+// G_DoParseMapInfo
+// Parses a single MAPINFO lump
+// data for wadlevelinfos and wadclusterinfos.
+//
+//==========================================================================
+
+void FMapInfoParser::ParseMapInfo (int lump, level_info_t &gamedefaults)
+{
+ level_info_t defaultinfo;
+
+ sc.OpenLumpNum(lump);
+
+ defaultinfo = gamedefaults;
+ HexenHack = false;
+
+ while (sc.GetString ())
+ {
+ if (sc.Compare("gamedefaults"))
+ {
+ gamedefaults.Reset();
+ ParseMapDefinition(gamedefaults);
+ defaultinfo = gamedefaults;
+ }
+ else if (sc.Compare("defaultmap"))
+ {
+ defaultinfo = gamedefaults;
+ ParseMapDefinition(defaultinfo);
+ }
+ else if (sc.Compare("adddefaultmap"))
+ {
+ // Same as above but adds to the existing definitions instead of replacing them completely
+ ParseMapDefinition(defaultinfo);
+ }
+ else if (sc.Compare("map"))
+ {
+ level_info_t *levelinfo = ParseMapHeader(defaultinfo);
+
+ ParseMapDefinition(*levelinfo);
+
+ // When the second sky is -NOFLAT-, make it a copy of the first sky
+ if (strcmp (levelinfo->skypic2, "-NOFLAT-") == 0)
+ {
+ strcpy (levelinfo->skypic2, levelinfo->skypic1);
+ }
+ SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
+ }
+ else if (sc.Compare("clusterdef"))
+ {
+ ParseCluster();
+ }
+ else if (sc.Compare("episode"))
+ {
+ ParseEpisodeInfo();
+ }
+ else if (sc.Compare("clearepisodes"))
+ {
+ ClearEpisodes();
+ }
+ else if (sc.Compare("skill"))
+ {
+ ParseSkill();
+ }
+ else if (sc.Compare("clearskills"))
+ {
+ AllSkills.Clear();
+ }
+ else
+ {
+ sc.ScriptError("%s: Unknown top level keyword", sc.String);
+ }
+ }
+}
+
+
+//==========================================================================
+//
+// G_ParseMapInfo
+// Parses the MAPINFO lumps of all loaded WADs and generates
+// data for wadlevelinfos and wadclusterinfos.
+//
+//==========================================================================
+
+void G_ParseMapInfo ()
+{
+ int lump, lastlump = 0;
+ level_info_t gamedefaults;
+
+ atterm(ClearEpisodes);
+
+ // Parse the default MAPINFO for the current game.
+ for(int i=0; i<2; i++)
+ {
+ if (gameinfo.mapinfo[i] != NULL)
+ {
+ FMapInfoParser parse;
+ parse.ParseMapInfo(Wads.GetNumForFullName(gameinfo.mapinfo[i]), gamedefaults);
+ }
+ }
+
+ // Parse any extra MAPINFOs.
+ while ((lump = Wads.FindLump ("MAPINFO", &lastlump)) != -1)
+ {
+ FMapInfoParser parse;
+ parse.ParseMapInfo(lump, gamedefaults);
+ }
+ EndSequences.ShrinkToFit ();
+
+ if (EpiDef.numitems == 0)
+ {
+ I_FatalError ("You cannot use clearepisodes in a MAPINFO if you do not define any new episodes after it.");
+ }
+ if (AllSkills.Size()==0)
+ {
+ I_FatalError ("You cannot use clearskills in a MAPINFO if you do not define any new skills after it.");
+ }
+}
+
diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp
index 6ee93f4f..37bf5312 100644
--- a/src/g_shared/a_artifacts.cpp
+++ b/src/g_shared/a_artifacts.cpp
@@ -951,7 +951,7 @@ void APowerFlight::InitEffect ()
void APowerFlight::Tick ()
{
// The Wings of Wrath only expire in multiplayer and non-hub games
- if (!multiplayer && (level.flags & LEVEL_INFINITE_FLIGHT))
+ if (!multiplayer && (level.flags2 & LEVEL2_INFINITE_FLIGHT))
{
assert(EffectTics < INT_MAX); // I can't see a game lasting nearly two years, but...
EffectTics++;
@@ -1364,7 +1364,7 @@ void APowerTimeFreezer::InitEffect( )
// Make sure the effect starts and ends on an even tic.
if ((level.time & 1) == 0)
{
- level.flags |= LEVEL_FROZEN;
+ level.flags2 |= LEVEL2_FROZEN;
}
else
{
@@ -1395,9 +1395,9 @@ void APowerTimeFreezer::DoEffect( )
|| (( EffectTics > 2*32 && EffectTics <= 3*32 ) && ((EffectTics + 1) & 7) != 0 )
|| (( EffectTics > 32 && EffectTics <= 2*32 ) && ((EffectTics + 1) & 3) != 0 )
|| (( EffectTics > 0 && EffectTics <= 1*32 ) && ((EffectTics + 1) & 1) != 0 ))
- level.flags |= LEVEL_FROZEN;
+ level.flags2 |= LEVEL2_FROZEN;
else
- level.flags &= ~LEVEL_FROZEN;
+ level.flags2 &= ~LEVEL2_FROZEN;
}
//===========================================================================
@@ -1411,7 +1411,7 @@ void APowerTimeFreezer::EndEffect( )
int ulIdx;
// Allow other actors to move about freely once again.
- level.flags &= ~LEVEL_FROZEN;
+ level.flags2 &= ~LEVEL2_FROZEN;
// Also, turn the music back on.
S_ResumeSound( );
diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp
index 67635acb..e466d1cd 100644
--- a/src/g_shared/a_pickups.cpp
+++ b/src/g_shared/a_pickups.cpp
@@ -1707,7 +1707,7 @@ IMPLEMENT_CLASS (AMapRevealer)
bool AMapRevealer::TryPickup (AActor *&toucher)
{
- level.flags |= LEVEL_ALLMAP;
+ level.flags2 |= LEVEL2_ALLMAP;
GoAwayAndDie ();
return true;
}
diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h
index e792b31e..daa13609 100644
--- a/src/g_shared/sbarinfo.h
+++ b/src/g_shared/sbarinfo.h
@@ -147,17 +147,9 @@ struct SBarInfo
static void Load();
};
-#define NUM_SCRIPTS 5
#define SCRIPT_CUSTOM 0
-#define SCRIPT_DOOM 1
-// The next ones shouldn't be used... yet
-#define SCRIPT_HERETIC 2
-#define SCRIPT_HEXEN 3
-#define SCRIPT_STRIFE 4
-// Converts GAME_x to it's script number
-#define GETSBARINFOSCRIPT(game) \
- (game & GAME_DoomChex) ? SCRIPT_DOOM : (game == GAME_Heretic ? SCRIPT_HERETIC : (game == GAME_Hexen ? SCRIPT_HEXEN : (game == GAME_Strife ? SCRIPT_STRIFE : SCRIPT_CUSTOM)))
-extern SBarInfo *SBarInfoScript[5];
+#define SCRIPT_DEFAULT 1
+extern SBarInfo *SBarInfoScript[2];
// Enums used between the parser and the display
diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp
index 790a9a49..205c8205 100644
--- a/src/g_shared/sbarinfo_display.cpp
+++ b/src/g_shared/sbarinfo_display.cpp
@@ -56,6 +56,7 @@
#include "a_strifeglobal.h"
#include "g_level.h"
#include "v_palette.h"
+#include "p_acs.h"
static FRandom pr_chainwiggle; //use the same method of chain wiggling as heretic.
diff --git a/src/g_shared/sbarinfo_parser.cpp b/src/g_shared/sbarinfo_parser.cpp
index 8530afe2..e9e1f218 100644
--- a/src/g_shared/sbarinfo_parser.cpp
+++ b/src/g_shared/sbarinfo_parser.cpp
@@ -46,16 +46,9 @@
#include "gi.h"
#include "i_system.h"
#include "g_level.h"
+#include "p_acs.h"
-SBarInfo *SBarInfoScript[NUM_SCRIPTS] = {NULL,NULL,NULL,NULL,NULL};
-static const char *DefaultScriptNames[NUM_SCRIPTS] =
-{
- "SBARINFO", //Custom
- "sbarinfo/doom.txt",
- NULL, //Heretic
- NULL, //Hexen
- NULL //Strife
-};
+SBarInfo *SBarInfoScript[2] = {NULL,NULL};
static const char *SBarInfoTopLevel[] =
{
@@ -114,7 +107,7 @@ static const char *SBarInfoRoutineLevel[] =
static void FreeSBarInfoScript()
{
- for(int i = 0;i < NUM_SCRIPTS;i++)
+ for(int i = 0;i < 2;i++)
{
if (SBarInfoScript[i] != NULL)
{
@@ -126,28 +119,25 @@ static void FreeSBarInfoScript()
void SBarInfo::Load()
{
- Printf ("ParseSBarInfo: Loading default status bar definitions.\n");
- for(int i = 1;i < NUM_SCRIPTS;i++) // Read in default bars if they exist
+ if(gameinfo.statusbar != NULL)
{
- if(DefaultScriptNames[i] != NULL)
+ int lump = Wads.CheckNumForFullName(gameinfo.statusbar, true);
+ if(lump != -1)
{
- int lump = Wads.CheckNumForFullName(DefaultScriptNames[i], true);
- if(lump != -1)
- {
- if(SBarInfoScript[i] == NULL)
- SBarInfoScript[i] = new SBarInfo(lump);
- else
- SBarInfoScript[i]->ParseSBarInfo(lump);
- }
+ Printf ("ParseSBarInfo: Loading default status bar definition.\n");
+ if(SBarInfoScript[SCRIPT_DEFAULT] == NULL)
+ SBarInfoScript[SCRIPT_DEFAULT] = new SBarInfo(lump);
+ else
+ SBarInfoScript[SCRIPT_DEFAULT]->ParseSBarInfo(lump);
}
}
- if(Wads.CheckNumForName(DefaultScriptNames[SCRIPT_CUSTOM]) != -1)
+ if(Wads.CheckNumForName("SBARINFO") != -1)
{
Printf ("ParseSBarInfo: Loading custom status bar definition.\n");
int lastlump, lump;
lastlump = 0;
- while((lump = Wads.FindLump(DefaultScriptNames[SCRIPT_CUSTOM], &lastlump)) != -1)
+ while((lump = Wads.FindLump("SBARINFO", &lastlump)) != -1)
{
if(SBarInfoScript[SCRIPT_CUSTOM] == NULL)
SBarInfoScript[SCRIPT_CUSTOM] = new SBarInfo(lump);
diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp
index cb77e40d..43b06002 100644
--- a/src/g_shared/shared_hud.cpp
+++ b/src/g_shared/shared_hud.cpp
@@ -875,7 +875,7 @@ void DrawHUD()
}
}
- mysnprintf(printstr, countof(printstr), "%s: %s", level.mapname, level.level_name);
+ mysnprintf(printstr, countof(printstr), "%s: %s", level.mapname, level.LevelName.GetChars());
screen->DrawText(SmallFont, hudcolor_titl, 1, hudheight-fonth-1, printstr,
DTA_KeepRatio, true,
DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, TAG_DONE);
diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp
index cc25a3b1..644e2508 100644
--- a/src/g_shared/shared_sbar.cpp
+++ b/src/g_shared/shared_sbar.cpp
@@ -1242,11 +1242,11 @@ void DBaseStatusBar::Draw (EHudState state)
{
i = mysnprintf (line, countof(line), "%s: ", level.mapname);
}
- line[i] = TEXTCOLOR_ESCAPE;
- line[i+1] = CR_GREY + 'A';
- strcpy (&line[i+2], level.level_name);
+ FString mapname;
+
+ mapname.Format("%c%c%s", TEXTCOLOR_ESCAPE, CR_GREY + 'A', level.LevelName.GetChars());
screen->DrawText (SmallFont, highlight,
- (SCREENWIDTH - SmallFont->StringWidth (line)*CleanXfac)/2, y, line,
+ (SCREENWIDTH - SmallFont->StringWidth (mapname)*CleanXfac)/2, y, mapname,
DTA_CleanNoMove, true, TAG_DONE);
if (!deathmatch)
diff --git a/src/g_skill.cpp b/src/g_skill.cpp
new file mode 100644
index 00000000..a664dc7a
--- /dev/null
+++ b/src/g_skill.cpp
@@ -0,0 +1,354 @@
+/*
+** g_skill.cpp
+** Skill level handling
+**
+**---------------------------------------------------------------------------
+** Copyright 2008-2009 Christoph Oelckers
+** Copyright 2008-2009 Randy Heit
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**---------------------------------------------------------------------------
+**
+*/
+
+#include
+#include "doomstat.h"
+#include "g_level.h"
+#include "g_game.h"
+#include "gi.h"
+#include "templates.h"
+#include "v_font.h"
+
+TArray AllSkills;
+
+//==========================================================================
+//
+// ParseSkill
+//
+//==========================================================================
+
+void FMapInfoParser::ParseSkill ()
+{
+ FSkillInfo skill;
+
+ skill.AmmoFactor = FRACUNIT;
+ skill.DoubleAmmoFactor = 2*FRACUNIT;
+ skill.DropAmmoFactor = -1;
+ skill.DamageFactor = FRACUNIT;
+ skill.FastMonsters = false;
+ skill.DisableCheats = false;
+ skill.EasyBossBrain = false;
+ skill.AutoUseHealth = false;
+ skill.RespawnCounter = 0;
+ skill.RespawnLimit = 0;
+ skill.Aggressiveness = FRACUNIT;
+ skill.SpawnFilter = 0;
+ skill.ACSReturn = AllSkills.Size();
+ skill.MenuNameIsLump = false;
+ skill.MustConfirm = false;
+ skill.Shortcut = 0;
+ skill.TextColor = "";
+
+ sc.MustGetString();
+ skill.Name = sc.String;
+
+ ParseOpenBrace();
+
+ while (sc.GetString ())
+ {
+ if (sc.Compare ("ammofactor"))
+ {
+ ParseAssign();
+ sc.MustGetFloat ();
+ skill.AmmoFactor = FLOAT2FIXED(sc.Float);
+ }
+ else if (sc.Compare ("doubleammofactor"))
+ {
+ ParseAssign();
+ sc.MustGetFloat ();
+ skill.DoubleAmmoFactor = FLOAT2FIXED(sc.Float);
+ }
+ else if (sc.Compare ("dropammofactor"))
+ {
+ ParseAssign();
+ sc.MustGetFloat ();
+ skill.DropAmmoFactor = FLOAT2FIXED(sc.Float);
+ }
+ else if (sc.Compare ("damagefactor"))
+ {
+ ParseAssign();
+ sc.MustGetFloat ();
+ skill.DamageFactor = FLOAT2FIXED(sc.Float);
+ }
+ else if (sc.Compare ("fastmonsters"))
+ {
+ skill.FastMonsters = true;
+ }
+ else if (sc.Compare ("disablecheats"))
+ {
+ skill.DisableCheats = true;
+ }
+ else if (sc.Compare ("easybossbrain"))
+ {
+ skill.EasyBossBrain = true;
+ }
+ else if (sc.Compare("autousehealth"))
+ {
+ skill.AutoUseHealth = true;
+ }
+ else if (sc.Compare("respawntime"))
+ {
+ ParseAssign();
+ sc.MustGetFloat ();
+ skill.RespawnCounter = int(sc.Float*TICRATE);
+ }
+ else if (sc.Compare("respawnlimit"))
+ {
+ ParseAssign();
+ sc.MustGetNumber ();
+ skill.RespawnLimit = sc.Number;
+ }
+ else if (sc.Compare("Aggressiveness"))
+ {
+ ParseAssign();
+ sc.MustGetFloat ();
+ skill.Aggressiveness = FRACUNIT - FLOAT2FIXED(clamp(sc.Float, 0.,1.));
+ }
+ else if (sc.Compare("SpawnFilter"))
+ {
+ ParseAssign();
+ if (sc.CheckNumber())
+ {
+ if (sc.Number > 0) skill.SpawnFilter |= (1<<(sc.Number-1));
+ }
+ else
+ {
+ sc.MustGetString ();
+ if (sc.Compare("baby")) skill.SpawnFilter |= 1;
+ else if (sc.Compare("easy")) skill.SpawnFilter |= 2;
+ else if (sc.Compare("normal")) skill.SpawnFilter |= 4;
+ else if (sc.Compare("hard")) skill.SpawnFilter |= 8;
+ else if (sc.Compare("nightmare")) skill.SpawnFilter |= 16;
+ }
+ }
+ else if (sc.Compare("ACSReturn"))
+ {
+ ParseAssign();
+ sc.MustGetNumber ();
+ skill.ACSReturn = sc.Number;
+ }
+ else if (sc.Compare("Name"))
+ {
+ ParseAssign();
+ sc.MustGetString ();
+ skill.MenuName = sc.String;
+ skill.MenuNameIsLump = false;
+ }
+ else if (sc.Compare("PlayerClassName"))
+ {
+ ParseAssign();
+ sc.MustGetString ();
+ FName pc = sc.String;
+ ParseComma();
+ sc.MustGetString ();
+ skill.MenuNamesForPlayerClass[pc]=sc.String;
+ }
+ else if (sc.Compare("PicName"))
+ {
+ ParseAssign();
+ sc.MustGetString ();
+ skill.MenuName = sc.String;
+ skill.MenuNameIsLump = true;
+ }
+ else if (sc.Compare("MustConfirm"))
+ {
+ ParseAssign();
+ skill.MustConfirm = true;
+ if (sc.CheckToken(TK_StringConst))
+ {
+ skill.MustConfirmText = sc.String;
+ }
+ }
+ else if (sc.Compare("Key"))
+ {
+ ParseAssign();
+ sc.MustGetString();
+ skill.Shortcut = tolower(sc.String[0]);
+ }
+ else if (sc.Compare("TextColor"))
+ {
+ ParseAssign();
+ sc.MustGetString();
+ skill.TextColor.Format("[%s]", sc.String);
+ }
+ else if (!ParseCloseBrace())
+ {
+ // Unknown
+ sc.ScriptMessage("Unknown property '%s' found in skill definition\n", sc.String);
+ SkipToNext();
+ }
+ else
+ {
+ break;
+ }
+ }
+ for(unsigned int i = 0; i < AllSkills.Size(); i++)
+ {
+ if (AllSkills[i].Name == skill.Name)
+ {
+ AllSkills[i] = skill;
+ return;
+ }
+ }
+ AllSkills.Push(skill);
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+int G_SkillProperty(ESkillProperty prop)
+{
+ if (AllSkills.Size() > 0)
+ {
+ switch(prop)
+ {
+ case SKILLP_AmmoFactor:
+ if (dmflags2 & DF2_YES_DOUBLEAMMO)
+ {
+ return AllSkills[gameskill].DoubleAmmoFactor;
+ }
+ return AllSkills[gameskill].AmmoFactor;
+
+ case SKILLP_DropAmmoFactor:
+ return AllSkills[gameskill].DropAmmoFactor;
+
+ case SKILLP_DamageFactor:
+ return AllSkills[gameskill].DamageFactor;
+
+ case SKILLP_FastMonsters:
+ return AllSkills[gameskill].FastMonsters || (dmflags & DF_FAST_MONSTERS);
+
+ case SKILLP_Respawn:
+ if (dmflags & DF_MONSTERS_RESPAWN && AllSkills[gameskill].RespawnCounter==0)
+ return TICRATE * (gameinfo.gametype != GAME_Strife ? 12 : 16);
+ return AllSkills[gameskill].RespawnCounter;
+
+ case SKILLP_RespawnLimit:
+ return AllSkills[gameskill].RespawnLimit;
+
+ case SKILLP_Aggressiveness:
+ return AllSkills[gameskill].Aggressiveness;
+
+ case SKILLP_DisableCheats:
+ return AllSkills[gameskill].DisableCheats;
+
+ case SKILLP_AutoUseHealth:
+ return AllSkills[gameskill].AutoUseHealth;
+
+ case SKILLP_EasyBossBrain:
+ return AllSkills[gameskill].EasyBossBrain;
+
+ case SKILLP_SpawnFilter:
+ return AllSkills[gameskill].SpawnFilter;
+
+ case SKILLP_ACSReturn:
+ return AllSkills[gameskill].ACSReturn;
+ }
+ }
+ return 0;
+}
+
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+void G_VerifySkill()
+{
+ if (gameskill >= (int)AllSkills.Size())
+ gameskill = AllSkills.Size()-1;
+ else if (gameskill < 0)
+ gameskill = 0;
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other)
+{
+ Name = other.Name;
+ AmmoFactor = other.AmmoFactor;
+ DoubleAmmoFactor = other.DoubleAmmoFactor;
+ DropAmmoFactor = other.DropAmmoFactor;
+ DamageFactor = other.DamageFactor;
+ FastMonsters = other.FastMonsters;
+ DisableCheats = other.DisableCheats;
+ AutoUseHealth = other.AutoUseHealth;
+ EasyBossBrain = other.EasyBossBrain;
+ RespawnCounter= other.RespawnCounter;
+ RespawnLimit= other.RespawnLimit;
+ Aggressiveness= other.Aggressiveness;
+ SpawnFilter = other.SpawnFilter;
+ ACSReturn = other.ACSReturn;
+ MenuName = other.MenuName;
+ MenuNamesForPlayerClass = other.MenuNamesForPlayerClass;
+ MenuNameIsLump = other.MenuNameIsLump;
+ MustConfirm = other.MustConfirm;
+ MustConfirmText = other.MustConfirmText;
+ Shortcut = other.Shortcut;
+ TextColor = other.TextColor;
+ return *this;
+}
+
+//==========================================================================
+//
+//
+//
+//==========================================================================
+
+int FSkillInfo::GetTextColor() const
+{
+ if (TextColor.IsEmpty())
+ {
+ return CR_UNTRANSLATED;
+ }
+ const BYTE *cp = (const BYTE *)TextColor.GetChars();
+ int color = V_ParseFontColor(cp, 0, 0);
+ if (color == CR_UNDEFINED)
+ {
+ Printf("Undefined color '%s' in definition of skill %s\n", TextColor.GetChars(), Name.GetChars());
+ color = CR_UNTRANSLATED;
+ }
+ return color;
+}
+
diff --git a/src/g_strife/a_strifeitems.cpp b/src/g_strife/a_strifeitems.cpp
index c1028ccf..15bb4fbd 100644
--- a/src/g_strife/a_strifeitems.cpp
+++ b/src/g_strife/a_strifeitems.cpp
@@ -106,7 +106,7 @@ IMPLEMENT_CLASS (AScanner)
bool AScanner::Use (bool pickup)
{
- if (!(level.flags & LEVEL_ALLMAP))
+ if (!(level.flags2 & LEVEL2_ALLMAP))
{
if (Owner->CheckLocalView (consoleplayer))
{
diff --git a/src/gi.cpp b/src/gi.cpp
index d26733e2..9715675f 100644
--- a/src/gi.cpp
+++ b/src/gi.cpp
@@ -101,6 +101,7 @@ gameinfo_t HexenGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding", // Hexen doesn't have a backpack so use Heretic's.
+ NULL,
};
gameinfo_t HexenDKGameInfo =
@@ -134,6 +135,7 @@ gameinfo_t HexenDKGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding",
+ NULL,
};
gameinfo_t HereticGameInfo =
@@ -167,6 +169,7 @@ gameinfo_t HereticGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding",
+ NULL,
};
gameinfo_t HereticSWGameInfo =
@@ -200,6 +203,7 @@ gameinfo_t HereticSWGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"BagOfHolding",
+ NULL,
};
gameinfo_t SharewareGameInfo =
@@ -233,6 +237,7 @@ gameinfo_t SharewareGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
+ "sbarinfo/doom.txt",
};
gameinfo_t RegisteredGameInfo =
@@ -266,6 +271,7 @@ gameinfo_t RegisteredGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
+ "sbarinfo/doom.txt",
};
gameinfo_t ChexGameInfo =
@@ -299,6 +305,7 @@ gameinfo_t ChexGameInfo =
MAKERGB(63,125,57),
MAKERGB(95,175,87),
"ZorchPack",
+ "sbarinfo/doom.txt",
};
gameinfo_t Chex3GameInfo =
@@ -332,6 +339,7 @@ gameinfo_t Chex3GameInfo =
MAKERGB(63,125,57),
MAKERGB(95,175,87),
"ZorchPack",
+ "sbarinfo/doom.txt",
};
gameinfo_t RetailGameInfo =
@@ -365,6 +373,7 @@ gameinfo_t RetailGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
+ "sbarinfo/doom.txt",
};
gameinfo_t CommercialGameInfo =
@@ -398,6 +407,7 @@ gameinfo_t CommercialGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
+ "sbarinfo/doom.txt",
};
gameinfo_t PlutoniaGameInfo =
@@ -431,6 +441,7 @@ gameinfo_t PlutoniaGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
+ "sbarinfo/doom.txt",
};
gameinfo_t TNTGameInfo =
@@ -464,6 +475,7 @@ gameinfo_t TNTGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"Backpack",
+ "sbarinfo/doom.txt",
};
gameinfo_t StrifeGameInfo =
@@ -497,6 +509,7 @@ gameinfo_t StrifeGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"AmmoSatchel",
+ NULL,
};
gameinfo_t StrifeTeaserGameInfo =
@@ -530,6 +543,7 @@ gameinfo_t StrifeTeaserGameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"AmmoSatchel",
+ NULL,
};
gameinfo_t StrifeTeaser2GameInfo =
@@ -563,4 +577,5 @@ gameinfo_t StrifeTeaser2GameInfo =
MAKERGB(104,0,0),
MAKERGB(255,0,0),
"AmmoSatchel",
+ NULL,
};
diff --git a/src/gi.h b/src/gi.h
index 9ef71f8a..a83f94a5 100644
--- a/src/gi.h
+++ b/src/gi.h
@@ -122,6 +122,7 @@ typedef struct
DWORD defaultbloodcolor;
DWORD defaultbloodparticlecolor;
const char *backpacktype;
+ const char *statusbar;
} gameinfo_t;
extern gameinfo_t gameinfo;
diff --git a/src/gl/gl_data.cpp b/src/gl/gl_data.cpp
index 98e8b078..2db1eaf8 100644
--- a/src/gl/gl_data.cpp
+++ b/src/gl/gl_data.cpp
@@ -93,7 +93,6 @@ void gl_InitSpecialTextures()
glpart = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/glpart.png"), FTexture::TEX_MiscPatch);
mirrortexture = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/mirror.png"), FTexture::TEX_MiscPatch);
gllight = FTexture::CreateTexture(Wads.GetNumForFullName("glstuff/gllight.png"), FTexture::TEX_MiscPatch);
- //atterm(DeleteGLTextures);
}
//-----------------------------------------------------------------------------
@@ -221,88 +220,73 @@ struct FGLROptions : public FOptionalMapinfoData
FVector3 skyrotatevector;
};
-static void ParseFunc(FScanner &sc, level_info_t *info)
+DEFINE_MAP_OPTION(fogdensity, false)
{
- FName id = "gl_renderer";
- FOptionalMapinfoData *dat = info->opdata;
+ FGLROptions *opt = info->GetOptData("gl_renderer");
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ opt->fogdensity = parse.sc.Number;
+}
- while (dat && dat->identifier != id) dat = dat->Next;
- if (!dat)
+DEFINE_MAP_OPTION(outsidefogdensity, false)
+{
+ FGLROptions *opt = info->GetOptData("gl_renderer");
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ opt->outsidefogdensity = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(skyfog, false)
+{
+ FGLROptions *opt = info->GetOptData("gl_renderer");
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ opt->skyfog = parse.sc.Number;
+}
+
+DEFINE_MAP_OPTION(lightmode, false)
+{
+ FGLROptions *opt = info->GetOptData("gl_renderer");
+ parse.ParseAssign();
+ parse.sc.MustGetNumber();
+ opt->lightmode = BYTE(parse.sc.Number);
+}
+
+DEFINE_MAP_OPTION(nocoloredspritelighting, false)
+{
+ FGLROptions *opt = info->GetOptData("gl_renderer");
+ if (parse.CheckAssign())
{
- dat = new FGLROptions;
- dat->Next = info->opdata;
- info->opdata = dat;
+ parse.sc.MustGetNumber();
+ opt->nocoloredspritelighting = !!parse.sc.Number;
}
-
- FGLROptions *opt = static_cast(dat);
-
- while (!sc.CheckString("}"))
+ else
{
- sc.MustGetString();
- if (sc.Compare("fogdensity"))
- {
- sc.MustGetNumber();
- opt->fogdensity = sc.Number;
- }
- else if (sc.Compare("outsidefogdensity"))
- {
- sc.MustGetNumber();
- opt->outsidefogdensity = sc.Number;
- }
- else if (sc.Compare("skyfog"))
- {
- sc.MustGetNumber();
- opt->skyfog = sc.Number;
- }
- else if (sc.Compare("lightmode"))
- {
- sc.MustGetNumber();
- opt->lightmode = BYTE(sc.Number);
- }
- else if (sc.Compare("nocoloredspritelighting"))
- {
- if (sc.CheckNumber())
- {
- opt->nocoloredspritelighting = !!sc.Number;
- }
- else
- {
- opt->nocoloredspritelighting = true;
- }
- }
- else if (sc.Compare("skyrotate"))
- {
- sc.MustGetFloat();
- opt->skyrotatevector.X = (float)sc.Float;
- sc.MustGetFloat();
- opt->skyrotatevector.Y = (float)sc.Float;
- sc.MustGetFloat();
- opt->skyrotatevector.Z = (float)sc.Float;
- opt->skyrotatevector.MakeUnit();
- }
- else
- {
- sc.ScriptError("Unknown keyword %s", sc.String);
- }
+ opt->nocoloredspritelighting = true;
}
}
-void gl_AddMapinfoParser()
-{
- AddOptionalMapinfoParser("gl_renderer", ParseFunc);
+DEFINE_MAP_OPTION(skyrotate, false)
+{
+ FGLROptions *opt = info->GetOptData("gl_renderer");
+
+ parse.ParseAssign();
+ parse.sc.MustGetFloat();
+ opt->skyrotatevector.X = (float)parse.sc.Float;
+ parse.sc.MustGetFloat();
+ opt->skyrotatevector.Y = (float)parse.sc.Float;
+ parse.sc.MustGetFloat();
+ opt->skyrotatevector.Z = (float)parse.sc.Float;
+ opt->skyrotatevector.MakeUnit();
}
static void InitGLRMapinfoData()
{
- FName id = "gl_renderer";
- FOptionalMapinfoData *dat = level.info->opdata;
+ FGLROptions *opt = level.info->GetOptData("gl_renderer", false);
- while (dat && dat->identifier != id) dat = dat->Next;
- if (dat != NULL)
+ if (opt != NULL)
{
- FGLROptions *opt = static_cast(dat);
gl_SetFogParams(opt->fogdensity, level.info->outsidefog, opt->outsidefogdensity, opt->skyfog);
-
glset.map_lightmode = opt->lightmode;
glset.map_nocoloredspritelighting = opt->nocoloredspritelighting;
glset.skyrotatevector = opt->skyrotatevector;
diff --git a/src/gl/gl_models.cpp b/src/gl/gl_models.cpp
index f965923c..310f5197 100644
--- a/src/gl/gl_models.cpp
+++ b/src/gl/gl_models.cpp
@@ -514,7 +514,7 @@ void gl_RenderFrameModels( const FSpriteModelFrame *smf,
// [BB] To interpolate at more than 35 fps we take tic fractions into account.
float ticFraction = 0.;
// [BB] In case the tic counter is frozen we have to leave ticFraction at zero.
- if ( ConsoleState == c_up && menuactive != MENU_On && !(level.flags & LEVEL_FROZEN) )
+ if ( ConsoleState == c_up && menuactive != MENU_On && !(level.flags2 & LEVEL2_FROZEN) )
{
float time = GetTimeFloat();
ticFraction = (time - static_cast(time));
diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp
index efaba169..456652bc 100644
--- a/src/hu_scores.cpp
+++ b/src/hu_scores.cpp
@@ -248,22 +248,22 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
y = MAX(BigFont->GetHeight() * 4, y);
}
- for (i = 0; i < teams.Size (); i++)
+ for (i = 0; i < Teams.Size (); i++)
{
- teams[i].players = 0;
- teams[i].score = 0;
+ Teams[i].m_iPlayerCount = 0;
+ Teams[i].m_iScore = 0;
}
for (i = 0; i < MAXPLAYERS; ++i)
{
- if (playeringame[sortedplayers[i]-players] && TEAMINFO_IsValidTeam (sortedplayers[i]->userinfo.team))
+ if (playeringame[sortedplayers[i]-players] && TeamLibrary.IsValidTeam (sortedplayers[i]->userinfo.team))
{
- if (teams[sortedplayers[i]->userinfo.team].players++ == 0)
+ if (Teams[sortedplayers[i]->userinfo.team].m_iPlayerCount++ == 0)
{
numTeams++;
}
- teams[sortedplayers[i]->userinfo.team].score += sortedplayers[i]->fragcount;
+ Teams[sortedplayers[i]->userinfo.team].m_iScore += sortedplayers[i]->fragcount;
}
}
@@ -271,9 +271,9 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
int numscores = 0;
int scorex;
- for (i = 0; i < teams.Size(); ++i)
+ for (i = 0; i < Teams.Size(); ++i)
{
- if (teams[i].players)
+ if (Teams[i].m_iPlayerCount)
{
numscores++;
}
@@ -281,14 +281,14 @@ static void HU_DoDrawScores (player_t *player, player_t *sortedplayers[MAXPLAYER
scorex = (SCREENWIDTH - scorexwidth * (numscores - 1)) / 2;
- for (i = 0; i < teams.Size(); ++i)
+ for (i = 0; i < Teams.Size(); ++i)
{
- if (teams[i].players)
+ if (Teams[i].m_iPlayerCount)
{
char score[80];
- mysnprintf (score, countof(score), "%d", teams[i].score);
+ mysnprintf (score, countof(score), "%d", Teams[i].m_iScore);
- screen->DrawText (BigFont, teams[i].GetTextColor(),
+ screen->DrawText (BigFont, Teams[i].GetTextColor(),
scorex - BigFont->StringWidth(score)*CleanXfac/2, y, score,
DTA_CleanNoMove, true, TAG_DONE);
@@ -400,9 +400,9 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2,
screen->DrawText (SmallFont, color, col4, y, player->userinfo.netname,
DTA_CleanNoMove, true, TAG_DONE);
- if (teamplay && teams[player->userinfo.team].logo.IsNotEmpty())
+ if (teamplay && Teams[player->userinfo.team].GetLogo ().IsNotEmpty ())
{
- FTexture *pic = TexMan[teams[player->userinfo.team].logo];
+ FTexture *pic = TexMan[Teams[player->userinfo.team].GetLogo ().GetChars ()];
screen->DrawTexture (pic, col1 - (pic->GetWidth() + 2) * CleanXfac, y,
DTA_CleanNoMove, true, TAG_DONE);
}
@@ -437,8 +437,8 @@ int HU_GetRowColor(player_t *player, bool highlight)
{
if (teamplay && deathmatch)
{
- if (TEAMINFO_IsValidTeam (player->userinfo.team))
- return teams[player->userinfo.team].GetTextColor();
+ if (TeamLibrary.IsValidTeam (player->userinfo.team))
+ return Teams[player->userinfo.team].GetTextColor();
else
return CR_GREY;
}
diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp
index 12356e40..b8b73aa6 100644
--- a/src/m_cheat.cpp
+++ b/src/m_cheat.cpp
@@ -236,7 +236,7 @@ void cht_DoCheat (player_t *player, int cheat)
if (i == 4)
{
- level.flags ^= LEVEL_ALLMAP;
+ level.flags2 ^= LEVEL2_ALLMAP;
}
else if (player->mo != NULL && player->health >= 0)
{
diff --git a/src/m_menu.cpp b/src/m_menu.cpp
index 96b69e8a..45f82a1a 100644
--- a/src/m_menu.cpp
+++ b/src/m_menu.cpp
@@ -2164,8 +2164,8 @@ static void M_PlayerSetupDrawer ()
screen->DrawText (SmallFont, label, PSetupDef.x, PSetupDef.y + LINEHEIGHT+yo, "Team",
DTA_Clean, true, TAG_DONE);
screen->DrawText (SmallFont, value, x, PSetupDef.y + LINEHEIGHT+yo,
- !TEAMINFO_IsValidTeam (players[consoleplayer].userinfo.team) ? "None" :
- teams[players[consoleplayer].userinfo.team].name,
+ !TeamLibrary.IsValidTeam (players[consoleplayer].userinfo.team) ? "None" :
+ Teams[players[consoleplayer].userinfo.team].GetName (),
DTA_Clean, true, TAG_DONE);
// Draw player character
@@ -2640,11 +2640,11 @@ static void M_ChangePlayerTeam (int choice)
{
if (team == 0)
{
- team = TEAM_None;
+ team = TEAM_NONE;
}
- else if (team == TEAM_None)
+ else if (team == TEAM_NONE)
{
- team = teams.Size () - 1;
+ team = Teams.Size () - 1;
}
else
{
@@ -2653,11 +2653,11 @@ static void M_ChangePlayerTeam (int choice)
}
else
{
- if (team == int(teams.Size () - 1))
+ if (team == int(Teams.Size () - 1))
{
- team = TEAM_None;
+ team = TEAM_NONE;
}
- else if (team == TEAM_None)
+ else if (team == TEAM_NONE)
{
team = 0;
}
diff --git a/src/m_menu.h b/src/m_menu.h
index 2d8d72d3..85187a8d 100644
--- a/src/m_menu.h
+++ b/src/m_menu.h
@@ -140,6 +140,7 @@ typedef struct menuitem_s {
int key2;
char *res2;
void *extra;
+ float discretecenter;
} c;
union {
float step;
diff --git a/src/m_options.cpp b/src/m_options.cpp
index 4c1c227d..d0573794 100644
--- a/src/m_options.cpp
+++ b/src/m_options.cpp
@@ -437,6 +437,7 @@ menuitem_t ControlsItems[] =
{ control, "Next item", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"invnext"} },
{ control, "Previous item", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"invprev"} },
{ control, "Drop item", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"invdrop"} },
+ { control, "Drop weapon", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"weapdrop"} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ whitetext,"Other", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ control, "Toggle automap", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"togglemap"} },
@@ -1117,7 +1118,7 @@ static menu_t DMFlagsMenu =
*=======================================*/
static menuitem_t CompatibilityItems[] = {
- { discrete, "Compatibility mode", {&compatmode}, {5.0}, {0.0}, {0.0}, {CompatModes} },
+ { discrete, "Compatibility mode", {&compatmode}, {5.0}, {1.0}, {0.0}, {CompatModes} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ bitflag, "Find shortest textures like Doom", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_SHORTTEX} },
{ bitflag, "Use buggier stair building", {&compatflags}, {0}, {0}, {0}, {(value_t *)COMPATF_STAIRINDEX} },
@@ -1552,7 +1553,8 @@ static void CalcIndent (menu_t *menu)
for (i = 0; i < menu->numitems; i++)
{
item = menu->items + i;
- if (item->type != whitetext && item->type != redtext && item->type != screenres)
+ if (item->type != whitetext && item->type != redtext && item->type != screenres &&
+ (item->type != discrete || !item->c.discretecenter))
{
thiswidth = SmallFont->StringWidth (item->label);
if (thiswidth > widest)
@@ -1682,6 +1684,7 @@ void M_OptDrawer ()
UCVarValue value;
DWORD overlay;
int labelofs;
+ int indent;
if (!CurrentMenu->DontDim)
{
@@ -1733,6 +1736,14 @@ void M_OptDrawer ()
item = CurrentMenu->items + i;
overlay = 0;
+ if (item->type == discrete && item->c.discretecenter)
+ {
+ indent = 160;
+ }
+ else
+ {
+ indent = CurrentMenu->indent;
+ }
if (item->type != screenres)
{
@@ -1741,14 +1752,14 @@ void M_OptDrawer ()
{
case more:
case safemore:
- x = CurrentMenu->indent - width;
+ x = indent - width;
color = MoreColor;
break;
case numberedmore:
case rsafemore:
case rightmore:
- x = CurrentMenu->indent + 14;
+ x = indent + 14;
color = item->type != rightmore ? CR_GREEN : MoreColor;
break;
@@ -1763,12 +1774,12 @@ void M_OptDrawer ()
break;
case listelement:
- x = CurrentMenu->indent + 14;
+ x = indent + 14;
color = LabelColor;
break;
case colorpicker:
- x = CurrentMenu->indent + 14;
+ x = indent + 14;
color = MoreColor;
break;
@@ -1780,7 +1791,7 @@ void M_OptDrawer ()
// Intentional fall-through
default:
- x = CurrentMenu->indent - width;
+ x = indent - width;
color = (item->type == control && menuactive == MENU_WaitKey && i == CurrentItem)
? CR_YELLOW : LabelColor;
break;
@@ -1795,7 +1806,7 @@ void M_OptDrawer ()
char tbuf[16];
mysnprintf (tbuf, countof(tbuf), "%d.", item->b.position);
- x = CurrentMenu->indent - SmallFont->StringWidth (tbuf);
+ x = indent - SmallFont->StringWidth (tbuf);
screen->DrawText (SmallFont, CR_GREY, x, y, tbuf, DTA_Clean, true, TAG_DONE);
}
break;
@@ -1812,13 +1823,13 @@ void M_OptDrawer ()
if (v == vals)
{
- screen->DrawText (SmallFont, ValueColor, CurrentMenu->indent + 14, y, "Unknown",
+ screen->DrawText (SmallFont, ValueColor, indent + 14, y, "Unknown",
DTA_Clean, true, TAG_DONE);
}
else
{
screen->DrawText (SmallFont, item->type == cdiscrete ? v : ValueColor,
- CurrentMenu->indent + 14, y, item->e.values[v].name,
+ indent + 14, y, item->e.values[v].name,
DTA_Clean, true, TAG_DONE);
}
@@ -1861,13 +1872,13 @@ void M_OptDrawer ()
if (v == vals)
{
- screen->DrawText (SmallFont, ValueColor, CurrentMenu->indent + 14, y, "Unknown",
+ screen->DrawText (SmallFont, ValueColor, indent + 14, y, "Unknown",
DTA_Clean, true, DTA_ColorOverlay, overlay, TAG_DONE);
}
else
{
screen->DrawText (SmallFont, item->type == cdiscrete ? v : ValueColor,
- CurrentMenu->indent + 14, y,
+ indent + 14, y,
item->type != discretes ? item->e.values[v].name : item->e.valuestrings[v].name.GetChars(),
DTA_Clean, true, DTA_ColorOverlay, overlay, TAG_DONE);
}
@@ -1881,7 +1892,7 @@ void M_OptDrawer ()
value = item->a.cvar->GetGenericRep (CVAR_String);
v = M_FindCurVal(value.String, item->e.enumvalues, (int)item->b.numvalues);
- screen->DrawText(SmallFont, ValueColor, CurrentMenu->indent + 14, y, v, DTA_Clean, true, TAG_DONE);
+ screen->DrawText(SmallFont, ValueColor, indent + 14, y, v, DTA_Clean, true, TAG_DONE);
}
break;
@@ -1895,11 +1906,11 @@ void M_OptDrawer ()
if (v == vals)
{
UCVarValue val = item->a.guidcvar->GetGenericRep (CVAR_String);
- screen->DrawText (SmallFont, ValueColor, CurrentMenu->indent + 14, y, val.String, DTA_Clean, true, TAG_DONE);
+ screen->DrawText (SmallFont, ValueColor, indent + 14, y, val.String, DTA_Clean, true, TAG_DONE);
}
else
{
- screen->DrawText (SmallFont, ValueColor, CurrentMenu->indent + 14, y, item->e.guidvalues[v].Name,
+ screen->DrawText (SmallFont, ValueColor, indent + 14, y, item->e.guidvalues[v].Name,
DTA_Clean, true, TAG_DONE);
}
@@ -1907,22 +1918,22 @@ void M_OptDrawer ()
break;
case nochoice:
- screen->DrawText (SmallFont, CR_GOLD, CurrentMenu->indent + 14, y,
+ screen->DrawText (SmallFont, CR_GOLD, indent + 14, y,
(item->e.values[(int)item->b.min]).name, DTA_Clean, true, TAG_DONE);
break;
case slider:
value = item->a.cvar->GetGenericRep (CVAR_Float);
- M_DrawSlider (CurrentMenu->indent + 14, y + labelofs, item->b.min, item->c.max, value.Float);
+ M_DrawSlider (indent + 14, y + labelofs, item->b.min, item->c.max, value.Float);
break;
case absslider:
value = item->a.cvar->GetGenericRep (CVAR_Float);
- M_DrawSlider (CurrentMenu->indent + 14, y + labelofs, item->b.min, item->c.max, fabs(value.Float));
+ M_DrawSlider (indent + 14, y + labelofs, item->b.min, item->c.max, fabs(value.Float));
break;
case intslider:
- M_DrawSlider (CurrentMenu->indent + 14, y + labelofs, item->b.min, item->c.max, item->a.fval);
+ M_DrawSlider (indent + 14, y + labelofs, item->b.min, item->c.max, item->a.fval);
break;
case control:
@@ -1932,11 +1943,11 @@ void M_OptDrawer ()
C_NameKeys (description, item->b.key1, item->c.key2);
if (description[0])
{
- M_DrawConText(CR_WHITE, CurrentMenu->indent + 14, y-1+labelofs, description);
+ M_DrawConText(CR_WHITE, indent + 14, y-1+labelofs, description);
}
else
{
- screen->DrawText(SmallFont, CR_BLACK, CurrentMenu->indent + 14, y + labelofs, "---",
+ screen->DrawText(SmallFont, CR_BLACK, indent + 14, y + labelofs, "---",
DTA_Clean, true, TAG_DONE);
}
}
@@ -1945,7 +1956,7 @@ void M_OptDrawer ()
case colorpicker:
{
int box_x, box_y;
- box_x = (CurrentMenu->indent - 35 - 160) * CleanXfac + screen->GetWidth()/2;
+ box_x = (indent - 35 - 160) * CleanXfac + screen->GetWidth()/2;
box_y = (y - ((gameinfo.gametype & GAME_Raven) ? 99 : 100)) * CleanYfac + screen->GetHeight()/2;
screen->Clear (box_x, box_y, box_x + 32*CleanXfac, box_y + (fontheight-1)*CleanYfac,
item->a.colorcvar->GetIndex(), 0);
@@ -1961,7 +1972,7 @@ void M_OptDrawer ()
box_y = (y - 98) * CleanYfac + screen->GetHeight()/2;
p = 0;
- box_x = (CurrentMenu->indent - 32 - 160) * CleanXfac + screen->GetWidth()/2;
+ box_x = (indent - 32 - 160) * CleanXfac + screen->GetWidth()/2;
for (x1 = 0, p = int(item->b.min * 16); x1 < 16; ++p, ++x1)
{
screen->Clear (box_x, box_y, box_x + w, box_y + h, p, 0);
@@ -2016,7 +2027,7 @@ void M_OptDrawer ()
}
screen->DrawText (SmallFont, ValueColor,
- CurrentMenu->indent + 14, y, str, DTA_Clean, true, TAG_DONE);
+ indent + 14, y, str, DTA_Clean, true, TAG_DONE);
}
break;
@@ -2028,7 +2039,7 @@ void M_OptDrawer ()
i == CurrentItem &&
(skullAnimCounter < 6 || menuactive == MENU_WaitKey))
{
- M_DrawConText(CR_RED, CurrentMenu->indent + 3, y-1+labelofs, "\xd");
+ M_DrawConText(CR_RED, indent + 3, y-1+labelofs, "\xd");
}
}
else
diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp
index 07139c52..9bab8bbd 100644
--- a/src/oplsynth/fmopl.cpp
+++ b/src/oplsynth/fmopl.cpp
@@ -1,10 +1,11 @@
/*
This file is based on fmopl.c from MAME 0.95. The non-YM3816 parts have been
-ripped out in the interest of trying to make this a bit faster, since Doom
-music doesn't need them. I also made it render the sound a voice at a time
-instead of a sample at a time, so unused voices don't waste time being
-calculated.
+ripped out in the interest of making this simpler, since Doom music doesn't
+need them. I also made it render the sound a voice at a time instead of a
+sample at a time, so unused voices don't waste time being calculated. If all
+voices are playing, it's not much difference, but it does offer a big
+improvement when only a few voices are playing.
Here is the appropriate section from mame.txt:
@@ -1919,41 +1920,32 @@ void YM3812UpdateOne(void *chip, float *buffer, int length)
UINT32 eg_timer_bak = OPL->eg_timer;
UINT32 eg_cnt_bak = OPL->eg_cnt;
- UINT32 noise_p_bak = OPL->noise_p;
- UINT32 noise_rng_bak = OPL->noise_rng;
-
UINT32 lfo_am_cnt_out = lfo_am_cnt_bak;
UINT32 eg_timer_out = eg_timer_bak;
UINT32 eg_cnt_out = eg_cnt_bak;
- UINT32 noise_p_out = noise_p_bak;
- UINT32 noise_rng_out = noise_rng_bak;
-
for (i = 0; i <= (rhythm ? 5 : 8); ++i)
{
OPL->lfo_am_cnt = lfo_am_cnt_bak;
OPL->eg_timer = eg_timer_bak;
OPL->eg_cnt = eg_cnt_bak;
- OPL->noise_p = noise_p_bak;
- OPL->noise_rng = noise_rng_bak;
if (CalcVoice (OPL, i, buffer, length))
{
lfo_am_cnt_out = OPL->lfo_am_cnt;
eg_timer_out = OPL->eg_timer;
eg_cnt_out = OPL->eg_cnt;
- noise_p_out = OPL->noise_p;
- noise_rng_out = OPL->noise_rng;
}
}
OPL->lfo_am_cnt = lfo_am_cnt_out;
OPL->eg_timer = eg_timer_out;
OPL->eg_cnt = eg_cnt_out;
- OPL->noise_p = noise_p_out;
- OPL->noise_rng = noise_rng_out;
if (rhythm) /* Rhythm part */
{
+ OPL->lfo_am_cnt = lfo_am_cnt_bak;
+ OPL->eg_timer = eg_timer_bak;
+ OPL->eg_cnt = eg_cnt_bak;
CalcRhythm (OPL, buffer, length);
}
}
@@ -1979,7 +1971,6 @@ static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length)
OPL_CALC_CH(CH, buffer + i);
advance(OPL, voice, voice);
- advance_noise(OPL);
}
return true;
}
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index 3769328f..2c192e91 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -69,6 +69,7 @@
#include "r_translate.h"
#include "sbarinfo.h"
#include "cmdlib.h"
+#include "m_png.h"
extern FILE *Logfile;
@@ -118,6 +119,222 @@ struct FBehavior::ArrayInfo
TArray FBehavior::StaticModules;
+
+//============================================================================
+//
+// Global and world variables
+//
+//============================================================================
+
+// ACS variables with world scope
+SDWORD ACS_WorldVars[NUM_WORLDVARS];
+FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
+
+// ACS variables with global scope
+SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
+FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
+
+
+//============================================================================
+//
+//
+//
+//============================================================================
+
+void P_ClearACSVars(bool alsoglobal)
+{
+ int i;
+
+ memset (ACS_WorldVars, 0, sizeof(ACS_WorldVars));
+ for (i = 0; i < NUM_WORLDVARS; ++i)
+ {
+ ACS_WorldArrays[i].Clear ();
+ }
+ if (alsoglobal)
+ {
+ memset (ACS_GlobalVars, 0, sizeof(ACS_GlobalVars));
+ for (i = 0; i < NUM_GLOBALVARS; ++i)
+ {
+ ACS_GlobalArrays[i].Clear ();
+ }
+ }
+}
+
+//============================================================================
+//
+//
+//
+//============================================================================
+
+static void WriteVars (FILE *file, SDWORD *vars, size_t count, DWORD id)
+{
+ size_t i, j;
+
+ for (i = 0; i < count; ++i)
+ {
+ if (vars[i] != 0)
+ break;
+ }
+ if (i < count)
+ {
+ // Find last non-zero var. Anything beyond the last stored variable
+ // will be zeroed at load time.
+ for (j = count-1; j > i; --j)
+ {
+ if (vars[j] != 0)
+ break;
+ }
+ FPNGChunkArchive arc (file, id);
+ for (i = 0; i <= j; ++i)
+ {
+ DWORD var = vars[i];
+ arc << var;
+ }
+ }
+}
+
+//============================================================================
+//
+//
+//
+//============================================================================
+
+static void ReadVars (PNGHandle *png, SDWORD *vars, size_t count, DWORD id)
+{
+ size_t len = M_FindPNGChunk (png, id);
+ size_t used = 0;
+
+ if (len != 0)
+ {
+ DWORD var;
+ size_t i;
+ FPNGChunkArchive arc (png->File->GetFile(), id, len);
+ used = len / 4;
+
+ for (i = 0; i < used; ++i)
+ {
+ arc << var;
+ vars[i] = var;
+ }
+ png->File->ResetFilePtr();
+ }
+ if (used < count)
+ {
+ memset (&vars[used], 0, (count-used)*4);
+ }
+}
+
+//============================================================================
+//
+//
+//
+//============================================================================
+
+static void WriteArrayVars (FILE *file, FWorldGlobalArray *vars, unsigned int count, DWORD id)
+{
+ unsigned int i, j;
+
+ // Find the first non-empty array.
+ for (i = 0; i < count; ++i)
+ {
+ if (vars[i].CountUsed() != 0)
+ break;
+ }
+ if (i < count)
+ {
+ // Find last non-empty array. Anything beyond the last stored array
+ // will be emptied at load time.
+ for (j = count-1; j > i; --j)
+ {
+ if (vars[j].CountUsed() != 0)
+ break;
+ }
+ FPNGChunkArchive arc (file, id);
+ arc.WriteCount (i);
+ arc.WriteCount (j);
+ for (; i <= j; ++i)
+ {
+ arc.WriteCount (vars[i].CountUsed());
+
+ FWorldGlobalArray::ConstIterator it(vars[i]);
+ const FWorldGlobalArray::Pair *pair;
+
+ while (it.NextPair (pair))
+ {
+ arc.WriteCount (pair->Key);
+ arc.WriteCount (pair->Value);
+ }
+ }
+ }
+}
+
+//============================================================================
+//
+//
+//
+//============================================================================
+
+static void ReadArrayVars (PNGHandle *png, FWorldGlobalArray *vars, size_t count, DWORD id)
+{
+ size_t len = M_FindPNGChunk (png, id);
+ unsigned int i, k;
+
+ for (i = 0; i < count; ++i)
+ {
+ vars[i].Clear ();
+ }
+
+ if (len != 0)
+ {
+ DWORD max, size;
+ FPNGChunkArchive arc (png->File->GetFile(), id, len);
+
+ i = arc.ReadCount ();
+ max = arc.ReadCount ();
+
+ for (; i <= max; ++i)
+ {
+ size = arc.ReadCount ();
+ for (k = 0; k < size; ++k)
+ {
+ SDWORD key, val;
+ key = arc.ReadCount();
+ val = arc.ReadCount();
+ vars[i].Insert (key, val);
+ }
+ }
+ png->File->ResetFilePtr();
+ }
+}
+
+//============================================================================
+//
+//
+//
+//============================================================================
+
+void P_ReadACSVars(PNGHandle *png)
+{
+ ReadVars (png, ACS_WorldVars, NUM_WORLDVARS, MAKE_ID('w','v','A','r'));
+ ReadVars (png, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r'));
+ ReadArrayVars (png, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r'));
+ ReadArrayVars (png, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r'));
+}
+
+//============================================================================
+//
+//
+//
+//============================================================================
+
+void P_WriteACSVars(FILE *stdfile)
+{
+ WriteVars (stdfile, ACS_WorldVars, NUM_WORLDVARS, MAKE_ID('w','v','A','r'));
+ WriteVars (stdfile, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r'));
+ WriteArrayVars (stdfile, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r'));
+ WriteArrayVars (stdfile, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r'));
+}
+
//---- Inventory functions --------------------------------------//
//
@@ -2157,24 +2374,28 @@ void DLevelScript::DoSetFont (int fontnum)
}
}
-#define APROP_Health 0
-#define APROP_Speed 1
-#define APROP_Damage 2
-#define APROP_Alpha 3
-#define APROP_RenderStyle 4
-#define APROP_Ambush 10
-#define APROP_Invulnerable 11
-#define APROP_JumpZ 12 // [GRB]
-#define APROP_ChaseGoal 13
-#define APROP_Frightened 14
-#define APROP_Gravity 15
-#define APROP_Friendly 16
-#define APROP_SpawnHealth 17
-#define APROP_SeeSound 5 // Sounds can only be set, not gotten
-#define APROP_AttackSound 6
-#define APROP_PainSound 7
-#define APROP_DeathSound 8
-#define APROP_ActiveSound 9
+enum
+{
+ APROP_Health = 0,
+ APROP_Speed = 1,
+ APROP_Damage = 2,
+ APROP_Alpha = 3,
+ APROP_RenderStyle = 4,
+ APROP_SeeSound = 5, // Sounds can only be set, not gotten
+ APROP_AttackSound = 6,
+ APROP_PainSound = 7,
+ APROP_DeathSound = 8,
+ APROP_ActiveSound = 9,
+ APROP_Ambush = 10,
+ APROP_Invulnerable = 11,
+ APROP_JumpZ = 12, // [GRB]
+ APROP_ChaseGoal = 13,
+ APROP_Frightened = 14,
+ APROP_Gravity = 15,
+ APROP_Friendly = 16,
+ APROP_SpawnHealth = 17,
+ APROP_Dropped = 18,
+};
// These are needed for ACS's APROP_RenderStyle
static const int LegacyRenderStyleIndices[] =
@@ -2253,6 +2474,10 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
if (value) actor->flags |= MF_AMBUSH; else actor->flags &= ~MF_AMBUSH;
break;
+ case APROP_Dropped:
+ if (value) actor->flags |= MF_DROPPED; else actor->flags &= ~MF_DROPPED;
+ break;
+
case APROP_Invulnerable:
if (value) actor->flags2 |= MF2_INVULNERABLE; else actor->flags2 &= ~MF2_INVULNERABLE;
break;
@@ -2356,6 +2581,7 @@ int DLevelScript::GetActorProperty (int tid, int property)
return STYLE_Normal;
case APROP_Gravity: return actor->gravity;
case APROP_Ambush: return !!(actor->flags & MF_AMBUSH);
+ case APROP_Dropped: return !!(actor->flags & MF_DROPPED);
case APROP_ChaseGoal: return !!(actor->flags5 & MF5_CHASEGOAL);
case APROP_Frightened: return !!(actor->flags4 & MF4_FRIGHTENED);
case APROP_Friendly: return !!(actor->flags & MF_FRIENDLY);
diff --git a/src/p_acs.h b/src/p_acs.h
index a92b0d0c..59ff1274 100644
--- a/src/p_acs.h
+++ b/src/p_acs.h
@@ -36,6 +36,7 @@
#define __P_ACS_H__
#include "dobject.h"
+#include "dthinker.h"
#include "doomtype.h"
#define LOCAL_SIZE 20
@@ -44,6 +45,34 @@
class FFont;
class FileReader;
+
+enum
+{
+ NUM_WORLDVARS = 256,
+ NUM_GLOBALVARS = 64
+};
+
+struct InitIntToZero
+{
+ void Init(int &v)
+ {
+ v = 0;
+ }
+};
+typedef TMap, InitIntToZero> FWorldGlobalArray;
+
+// ACS variables with world scope
+extern SDWORD ACS_WorldVars[NUM_WORLDVARS];
+extern FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
+
+// ACS variables with global scope
+extern SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
+extern FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
+
+void P_ReadACSVars(PNGHandle *);
+void P_WriteACSVars(FILE*);
+void P_ClearACSVars(bool);
+
// The in-memory version
struct ScriptPtr
{
diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp
index bcbb0b42..45bb6ff4 100644
--- a/src/p_conversation.cpp
+++ b/src/p_conversation.cpp
@@ -848,7 +848,7 @@ static void DrawConversationMenu ()
}
// [CW] Freeze the game depending on MAPINFO options.
- if (ConversationPauseTic < gametic && !multiplayer && !(level.flags & LEVEL_CONV_SINGLE_UNFREEZE))
+ if (ConversationPauseTic < gametic && !multiplayer && !(level.flags2 & LEVEL2_CONV_SINGLE_UNFREEZE))
{
menuactive = MENU_On;
}
diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index 6b18d4cc..e4abed26 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -1590,10 +1590,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
// Let the self wander around aimlessly looking for a fight
if (self->SeeState != NULL)
{
- if (!(self->flags & MF_INCHASE))
- {
- self->SetState (self->SeeState);
- }
+ self->SetState (self->SeeState);
}
else
{
@@ -1638,7 +1635,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
}
}
- if (self->target && !(self->flags & MF_INCHASE))
+ if (self->target)
{
self->SetState (self->SeeState);
}
@@ -1757,6 +1754,10 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
{
int delta;
+ if (actor->flags & MF_INCHASE)
+ {
+ return;
+ }
actor->flags |= MF_INCHASE;
// [RH] Andy Baker's stealth monsters
@@ -2183,7 +2184,6 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
info = corpsehit->GetDefault ();
- corpsehit->SetState (raisestate);
corpsehit->height = info->height; // [RH] Use real mobj height
corpsehit->radius = info->radius; // [RH] Use real radius
/*
@@ -2207,6 +2207,7 @@ static bool P_CheckForResurrection(AActor *self, bool usevilestates)
// You are the Archvile's minion now, so hate what it hates
corpsehit->CopyFriendliness (self, false);
+ corpsehit->SetState (raisestate);
return true;
}
@@ -2652,9 +2653,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_BossDeath)
// Do generic special death actions first
bool checked = false;
- FSpecialAction *sa = level.info->specialactions;
- while (sa)
+ for(unsigned i=0; ispecialactions.Size(); i++)
{
+ FSpecialAction *sa = &level.info->specialactions[i];
+
if (type == sa->Type || mytype == sa->Type)
{
if (!checked && !CheckBossDeath(self))
@@ -2666,7 +2668,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BossDeath)
LineSpecials[sa->Action](NULL, self, false,
sa->Args[0], sa->Args[1], sa->Args[2], sa->Args[3], sa->Args[4]);
}
- sa = sa->Next;
}
// [RH] These all depend on the presence of level flags now
diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp
index 5f594870..372318e5 100644
--- a/src/p_interaction.cpp
+++ b/src/p_interaction.cpp
@@ -957,6 +957,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
if (df != NULL)
{
fixed_t * pdf = df->CheckKey(mod);
+ if (pdf== NULL && mod != NAME_None) pdf = df->CheckKey(NAME_None);
if (pdf != NULL)
{
damage = FixedMul(damage, *pdf);
@@ -1295,8 +1296,8 @@ bool AActor::OkayToSwitchTarget (AActor *other)
int infight;
if (flags5 & MF5_NOINFIGHTING) infight=-1;
- else if (level.flags & LEVEL_TOTALINFIGHTING) infight=1;
- else if (level.flags & LEVEL_NOINFIGHTING) infight=-1;
+ else if (level.flags2 & LEVEL2_TOTALINFIGHTING) infight=1;
+ else if (level.flags2 & LEVEL2_NOINFIGHTING) infight=-1;
else infight = infighting;
if (infight < 0 && other->player == NULL && !IsHostile (other))
diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp
index 11205343..a26e71be 100644
--- a/src/p_lnspec.cpp
+++ b/src/p_lnspec.cpp
@@ -2489,7 +2489,7 @@ FUNC(LS_SetPlayerProperty)
}
else if (it->player - players == consoleplayer)
{
- level.flags |= LEVEL_ALLMAP;
+ level.flags2 |= LEVEL2_ALLMAP;
}
}
else
@@ -2504,7 +2504,7 @@ FUNC(LS_SetPlayerProperty)
}
else if (it->player - players == consoleplayer)
{
- level.flags &= ~LEVEL_ALLMAP;
+ level.flags2 &= ~LEVEL2_ALLMAP;
}
}
}
@@ -2525,7 +2525,7 @@ FUNC(LS_SetPlayerProperty)
}
else if (i == consoleplayer)
{
- level.flags |= LEVEL_ALLMAP;
+ level.flags2 |= LEVEL2_ALLMAP;
}
}
else
@@ -2540,7 +2540,7 @@ FUNC(LS_SetPlayerProperty)
}
else if (i == consoleplayer)
{
- level.flags &= ~LEVEL_ALLMAP;
+ level.flags2 &= ~LEVEL2_ALLMAP;
}
}
}
diff --git a/src/p_map.cpp b/src/p_map.cpp
index 3307c3d6..3e93882b 100644
--- a/src/p_map.cpp
+++ b/src/p_map.cpp
@@ -672,7 +672,7 @@ bool PIT_CheckLine (line_t *ld, const FBoundingBox &box, FCheckPosition &tm)
// better than Strife's handling of rails, which lets you jump into rails
// from either side. How long until somebody reports this as a bug and I'm
// forced to say, "It's not a bug. It's a feature?" Ugh.
- (!(level.flags & LEVEL_RAILINGHACK) ||
+ (!(level.flags2 & LEVEL2_RAILINGHACK) ||
open.bottom == tm.thing->Sector->floorplane.ZatPoint (sx, sy)))
{
open.bottom += 32*FRACUNIT;
@@ -870,8 +870,8 @@ bool PIT_CheckThing (AActor *thing, FCheckPosition &tm)
if (!thing->player && !tm.thing->target->player)
{
int infight;
- if (level.flags & LEVEL_TOTALINFIGHTING) infight=1;
- else if (level.flags & LEVEL_NOINFIGHTING) infight=-1;
+ if (level.flags2 & LEVEL2_TOTALINFIGHTING) infight=1;
+ else if (level.flags2 & LEVEL2_NOINFIGHTING) infight=-1;
else infight = infighting;
if (infight < 0)
@@ -1412,7 +1412,7 @@ static void CheckForPushSpecial (line_t *line, int side, AActor *mobj)
}
else if (mobj->flags2 & MF2_IMPACT)
{
- if ((level.flags & LEVEL_MISSILESACTIVATEIMPACT) ||
+ if ((level.flags2 & LEVEL2_MISSILESACTIVATEIMPACT) ||
!(mobj->flags & MF_MISSILE) ||
(mobj->target == NULL))
{
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 1ea1e797..4d3f5929 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -1831,7 +1831,7 @@ void P_MonsterFallingDamage (AActor *mo)
int damage;
int mom;
- if (!(level.flags&LEVEL_MONSTERFALLINGDAMAGE))
+ if (!(level.flags2 & LEVEL2_MONSTERFALLINGDAMAGE))
return;
if (mo->floorsector->Flags & SECF_NOFALLINGDAMAGE)
return;
@@ -2536,7 +2536,7 @@ void AActor::Tick ()
if (!(flags5 & MF5_NOTIMEFREEZE))
{
//Added by MC: Freeze mode.
- if (bglobal.freeze || level.flags & LEVEL_FROZEN)
+ if (bglobal.freeze || level.flags2 & LEVEL2_FROZEN)
{
return;
}
@@ -2575,7 +2575,7 @@ void AActor::Tick ()
}
// Apply freeze mode.
- if (( level.flags & LEVEL_FROZEN ) && ( player == NULL || !( player->cheats & CF_TIMEFREEZE )))
+ if (( level.flags2 & LEVEL2_FROZEN ) && ( player == NULL || !( player->cheats & CF_TIMEFREEZE )))
{
return;
}
@@ -3713,7 +3713,7 @@ APlayerPawn *P_SpawnPlayer (FMapThing *mthing, bool tempplayer)
{ // Give all cards in death match mode.
p->mo->GiveDeathmatchInventory ();
}
- else if ((multiplayer || (level.flags & LEVEL_ALLOWRESPAWN)) && state == PST_REBORN && oldactor != NULL)
+ else if ((multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN)) && state == PST_REBORN && oldactor != NULL)
{ // Special inventory handling for respawning in coop
p->mo->FilterCoopRespawnInventory (oldactor);
}
@@ -4023,7 +4023,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
}
// don't spawn any monsters if -nomonsters
- if (((level.flags & LEVEL_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) && info->flags3 & MF3_ISMONSTER )
+ if (((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS)) && info->flags3 & MF3_ISMONSTER )
{
return NULL;
}
@@ -4926,7 +4926,7 @@ bool AActor::IsTeammate (AActor *other)
return false;
if (!deathmatch)
return true;
- if (teamplay && other->player->userinfo.team != TEAM_None &&
+ if (teamplay && other->player->userinfo.team != TEAM_NONE &&
player->userinfo.team == other->player->userinfo.team)
{
return true;
diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp
index d2dd03ee..996886d9 100644
--- a/src/p_saveg.cpp
+++ b/src/p_saveg.cpp
@@ -467,7 +467,7 @@ void P_SerializeSounds (FArchive &arc)
{
if (!S_ChangeMusic (name, order))
if (level.cdtrack == 0 || !S_ChangeCDMusic (level.cdtrack, level.cdid))
- S_ChangeMusic (level.music, level.musicorder);
+ S_ChangeMusic (level.Music, level.musicorder);
}
delete[] name;
}
diff --git a/src/p_setup.cpp b/src/p_setup.cpp
index 46370f2c..c1e34fa0 100644
--- a/src/p_setup.cpp
+++ b/src/p_setup.cpp
@@ -1602,7 +1602,7 @@ void P_SetLineID (line_t *ld)
switch (ld->special)
{
case Line_SetIdentification:
- if (!(level.flags & LEVEL_HEXENHACK))
+ if (!(level.flags2 & LEVEL2_HEXENHACK))
{
ld->id = ld->args[0] + 256 * ld->args[4];
ld->flags |= ld->args[1]<<16;
@@ -1813,9 +1813,9 @@ void P_LoadLineDefs (MapData * map)
P_AdjustLine (ld);
P_SaveLineSpecial (ld);
- if (level.flags & LEVEL_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
- if (level.flags & LEVEL_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
- if (level.flags & LEVEL_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;
+ if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
+ if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
+ if (level.flags2 & LEVEL2_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;
}
delete[] mldf;
}
@@ -1891,9 +1891,9 @@ void P_LoadLineDefs2 (MapData * map)
P_AdjustLine (ld);
P_SetLineID(ld);
P_SaveLineSpecial (ld);
- if (level.flags & LEVEL_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
- if (level.flags & LEVEL_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
- if (level.flags & LEVEL_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;
+ if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
+ if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
+ if (level.flags2 & LEVEL2_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;
// convert the activation type
ld->activation = 1 << GET_SPAC(ld->flags);
@@ -3354,7 +3354,7 @@ void P_SetupLevel (char *lumpname, int position)
{
// We need translators only for Doom format maps.
// If none has been defined in a map use the game's default.
- P_LoadTranslator(level.info->translator != NULL? (const char *)level.info->translator : gameinfo.translator);
+ P_LoadTranslator(!level.info->Translator.IsEmpty()? level.info->Translator.GetChars() : gameinfo.translator);
}
T_LoadScripts(map);
@@ -3362,9 +3362,9 @@ void P_SetupLevel (char *lumpname, int position)
{
// Doom format and UDMF text maps get strict monster activation unless the mapinfo
// specifies differently.
- if (!(level.flags & LEVEL_LAXACTIVATIONMAPINFO))
+ if (!(level.flags2 & LEVEL2_LAXACTIVATIONMAPINFO))
{
- level.flags &= ~LEVEL_LAXMONSTERACTIVATION;
+ level.flags2 &= ~LEVEL2_LAXMONSTERACTIVATION;
}
}
@@ -3373,9 +3373,9 @@ void P_SetupLevel (char *lumpname, int position)
// set compatibility flags
if (gameinfo.gametype == GAME_Strife)
{
- level.flags |= LEVEL_RAILINGHACK;
+ level.flags2 |= LEVEL2_RAILINGHACK;
}
- level.flags |= LEVEL_DUMMYSWITCHES;
+ level.flags2 |= LEVEL2_DUMMYSWITCHES;
}
FBehavior::StaticLoadDefaultModules ();
diff --git a/src/p_spec.cpp b/src/p_spec.cpp
index f128e812..185719b2 100644
--- a/src/p_spec.cpp
+++ b/src/p_spec.cpp
@@ -239,7 +239,7 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType)
}
// some old WADs use this method to create walls that change the texture when shot.
else if (activationType == SPAC_Impact && // only for shootable triggers
- (level.flags & LEVEL_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack!
+ (level.flags2 & LEVEL2_DUMMYSWITCHES) && // this is only a compatibility setting for an old hack!
!repeat && // only non-repeatable triggers
(specialGeneric_Crusher) && // not for Boom's generalized linedefs
special && // not for lines without a special
@@ -322,7 +322,7 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
// lax activation checks, monsters can also activate certain lines
// even without them being marked as monster activate-able. This is
// the default for non-Hexen maps in Hexen format.
- if (!(level.flags & LEVEL_LAXMONSTERACTIVATION))
+ if (!(level.flags2 & LEVEL2_LAXMONSTERACTIVATION))
{
return false;
}
diff --git a/src/p_states.cpp b/src/p_states.cpp
index 68045b66..f3a99798 100644
--- a/src/p_states.cpp
+++ b/src/p_states.cpp
@@ -928,7 +928,7 @@ void DumpStateHelper(FStateLabels *StateList, const FString &prefix)
else
{
Printf(PRINT_LOG, "%s%s: %s.%d\n", prefix.GetChars(), StateList->Labels[i].Label.GetChars(),
- owner->TypeName.GetChars(), StateList->Labels[i].State - owner->ActorInfo->OwnedStates);
+ owner->TypeName.GetChars(), int(StateList->Labels[i].State - owner->ActorInfo->OwnedStates));
}
}
if (StateList->Labels[i].Children != NULL)
diff --git a/src/p_things.cpp b/src/p_things.cpp
index b8273db5..0404ac37 100644
--- a/src/p_things.cpp
+++ b/src/p_things.cpp
@@ -68,7 +68,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog,
kind = kind->ActorInfo->GetReplacement()->Class;
if ((GetDefaultByType (kind)->flags3 & MF3_ISMONSTER) &&
- ((dmflags & DF_NO_MONSTERS) || (level.flags & LEVEL_NOMONSTERS)))
+ ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS)))
return false;
if (tid == 0)
@@ -204,7 +204,7 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam
defflags3 = GetDefaultByType (kind)->flags3;
if ((defflags3 & MF3_ISMONSTER) &&
- ((dmflags & DF_NO_MONSTERS) || (level.flags & LEVEL_NOMONSTERS)))
+ ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS)))
return false;
if (tid == 0)
diff --git a/src/p_tick.cpp b/src/p_tick.cpp
index e0723756..b4a97dd8 100644
--- a/src/p_tick.cpp
+++ b/src/p_tick.cpp
@@ -57,7 +57,7 @@ bool P_CheckTickerPaused ()
&& players[consoleplayer].viewz != 1
&& wipegamestate == gamestate)
{
- S_PauseSound (!(level.flags & LEVEL_PAUSE_MUSIC_IN_MENUS));
+ S_PauseSound (!(level.flags2 & LEVEL2_PAUSE_MUSIC_IN_MENUS));
return true;
}
return false;
@@ -111,7 +111,7 @@ void P_Ticker (void)
// Since things will be moving, it's okay to interpolate them in the renderer.
r_NoInterpolate = false;
- if (!bglobal.freeze && !(level.flags & LEVEL_FROZEN))
+ if (!bglobal.freeze && !(level.flags2 & LEVEL2_FROZEN))
{
P_ThinkParticles (); // [RH] make the particles think
}
@@ -126,7 +126,7 @@ void P_Ticker (void)
DThinker::RunThinkers ();
//if added by MC: Freeze mode.
- if (!bglobal.freeze && !(level.flags & LEVEL_FROZEN))
+ if (!bglobal.freeze && !(level.flags2 & LEVEL2_FROZEN))
{
P_UpdateSpecials ();
P_RunEffects (); // [RH] Run particle effects
diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp
index 94bfdc77..6bd5b26c 100644
--- a/src/p_udmf.cpp
+++ b/src/p_udmf.cpp
@@ -419,9 +419,9 @@ struct UDMFParser
ld->Alpha = FRACUNIT;
ld->id = -1;
ld->sidenum[0] = ld->sidenum[1] = NO_SIDE;
- if (level.flags & LEVEL_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
- if (level.flags & LEVEL_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
- if (level.flags & LEVEL_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;
+ if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
+ if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
+ if (level.flags2 & LEVEL2_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;
sc.MustGetToken('{');
while (!sc.CheckToken('}'))
@@ -1124,19 +1124,19 @@ struct UDMFParser
case NAME_Doom:
namespace_bits = Dm;
P_LoadTranslator("xlat/doom_base.txt");
- level.flags |= LEVEL_DUMMYSWITCHES;
+ level.flags2 |= LEVEL2_DUMMYSWITCHES;
floordrop = true;
break;
case NAME_Heretic:
namespace_bits = Ht;
P_LoadTranslator("xlat/heretic_base.txt");
- level.flags |= LEVEL_DUMMYSWITCHES;
+ level.flags2 |= LEVEL2_DUMMYSWITCHES;
floordrop = true;
break;
case NAME_Strife:
namespace_bits = St;
P_LoadTranslator("xlat/strife_base.txt");
- level.flags |= LEVEL_DUMMYSWITCHES|LEVEL_RAILINGHACK;
+ level.flags2 |= LEVEL2_DUMMYSWITCHES|LEVEL2_RAILINGHACK;
floordrop = true;
break;
default:
diff --git a/src/p_user.cpp b/src/p_user.cpp
index 449fc76d..d1ef70fc 100644
--- a/src/p_user.cpp
+++ b/src/p_user.cpp
@@ -1148,7 +1148,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor)
}
}
}
- if (!multiplayer && (level.flags & LEVEL_DEATHSLIDESHOW))
+ if (!multiplayer && (level.flags2 & LEVEL2_DEATHSLIDESHOW))
{
F_StartSlideshow ();
}
@@ -1876,7 +1876,7 @@ void P_DeathThink (player_t *player)
if (level.time >= player->respawn_time || ((player->cmd.ucmd.buttons & BT_USE) && !player->isbot))
{
player->cls = NULL; // Force a new class if the player is using a random class
- player->playerstate = (multiplayer || (level.flags & LEVEL_ALLOWRESPAWN)) ? PST_REBORN : PST_ENTER;
+ player->playerstate = (multiplayer || (level.flags2 & LEVEL2_ALLOWRESPAWN)) ? PST_REBORN : PST_ENTER;
if (player->mo->special1 > 2)
{
player->mo->special1 = 0;
diff --git a/src/r_segs.cpp b/src/r_segs.cpp
index 3087e0c9..673a585a 100644
--- a/src/r_segs.cpp
+++ b/src/r_segs.cpp
@@ -1441,7 +1441,7 @@ int side_t::GetLightLevel (bool foggy, int baselight) const
{
if (!(Flags & WALLF_NOFAKECONTRAST))
{
- if (((level.flags & LEVEL_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_smoothlighting) &&
+ if (((level.flags2 & LEVEL2_SMOOTHLIGHTING) || (Flags & WALLF_SMOOTHLIGHTING) || r_smoothlighting) &&
lines[linenum].dx != 0)
{
baselight += int // OMG LEE KILLOUGH LIVES! :/
diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp
index 4117930b..0736c80c 100644
--- a/src/s_advsound.cpp
+++ b/src/s_advsound.cpp
@@ -1071,9 +1071,9 @@ static void S_AddSNDINFO (int lump)
mysnprintf (temp, countof(temp), "MAP%02d", sc.Number);
info = FindLevelInfo (temp);
sc.MustGetString ();
- if (info->mapname[0] && (!(info->flags & LEVEL_MUSICDEFINED)))
+ if (info->mapname[0] && (!(info->flags2 & LEVEL2_MUSICDEFINED)))
{
- ReplaceString (&info->music, sc.String);
+ info->Music = sc.String;
}
}
break;
diff --git a/src/s_sound.cpp b/src/s_sound.cpp
index 07b1cb8c..effa0925 100644
--- a/src/s_sound.cpp
+++ b/src/s_sound.cpp
@@ -163,7 +163,8 @@ void S_NoiseDebug (void)
screen->DrawText (SmallFont, CR_GOLD, 220, y, "vol", TAG_DONE);
screen->DrawText (SmallFont, CR_GOLD, 260, y, "dist", TAG_DONE);
screen->DrawText (SmallFont, CR_GOLD, 300, y, "chan", TAG_DONE);
- screen->DrawText (SmallFont, CR_GOLD, 340, y, "flags", TAG_DONE);
+ screen->DrawText (SmallFont, CR_GOLD, 340, y, "pri", TAG_DONE);
+ screen->DrawText (SmallFont, CR_GOLD, 380, y, "flags", TAG_DONE);
y += 8;
if (Channels == NULL)
@@ -231,6 +232,10 @@ void S_NoiseDebug (void)
mysnprintf(temp, countof(temp), "%d", chan->EntChannel);
screen->DrawText(SmallFont, color, 300, y, temp, TAG_DONE);
+ // Priority
+ mysnprintf(temp, countof(temp), "%d", chan->Priority);
+ screen->DrawText(SmallFont, color, 340, y, temp, TAG_DONE);
+
// Flags
mysnprintf(temp, countof(temp), "%s3%sZ%sU%sM%sN%sA%sL%sE",
(chan->ChanFlags & CHAN_IS3D) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK,
@@ -241,7 +246,7 @@ void S_NoiseDebug (void)
(chan->ChanFlags & CHAN_AREA) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK,
(chan->ChanFlags & CHAN_LOOP) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK,
(chan->ChanFlags & CHAN_EVICTED) ? TEXTCOLOR_GREEN : TEXTCOLOR_BLACK);
- screen->DrawText(SmallFont, color, 340, y, temp, TAG_DONE);
+ screen->DrawText(SmallFont, color, 380, y, temp, TAG_DONE);
y += 8;
if (chan->PrevChan == &Channels)
@@ -365,26 +370,18 @@ void S_Start ()
// Check for local sound definitions. Only reload if they differ
// from the previous ones.
- const char *LocalSndInfo;
- const char *LocalSndSeq;
+ FString LocalSndInfo;
+ FString LocalSndSeq;
// To be certain better check whether level is valid!
- if (level.info && level.info->soundinfo)
+ if (level.info)
{
- LocalSndInfo = level.info->soundinfo;
- }
- else
- {
- LocalSndInfo = "";
+ LocalSndInfo = level.info->SoundInfo;
}
- if (level.info && level.info->sndseq)
+ if (level.info)
{
- LocalSndSeq = level.info->sndseq;
- }
- else
- {
- LocalSndSeq = "";
+ LocalSndSeq = level.info->SndSeq;
}
bool parse_ss = false;
@@ -415,11 +412,11 @@ void S_Start ()
{
parse_ss = true;
}
+
if (parse_ss)
{
S_ParseSndSeq(*LocalSndSeq? Wads.CheckNumForFullName(LocalSndSeq, true) : -1);
}
- else
LastLocalSndInfo = LocalSndInfo;
LastLocalSndSeq = LocalSndSeq;
@@ -437,7 +434,7 @@ void S_Start ()
if (!savegamerestore)
{
if (level.cdtrack == 0 || !S_ChangeCDMusic (level.cdtrack, level.cdid))
- S_ChangeMusic (level.music, level.musicorder);
+ S_ChangeMusic (level.Music, level.musicorder);
}
}
@@ -940,7 +937,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO
// Select priority.
if (type == SOURCE_None || actor == players[consoleplayer].camera)
{
- basepriority = 40;
+ basepriority = 80;
}
else
{
@@ -1664,7 +1661,7 @@ void S_EvictAllChannels()
{
S_StopChannel(chan);
}
- assert(chan->NextChan == next);
+// assert(chan->NextChan == next);
}
}
}
@@ -2165,7 +2162,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
{
if (gamestate == GS_LEVEL || gamestate == GS_TITLELEVEL)
{
- musicname = level.music;
+ musicname = level.Music;
order = level.musicorder;
}
else
@@ -2428,9 +2425,9 @@ CCMD (idmus)
if ( (info = FindLevelInfo (map)) )
{
- if (info->music)
+ if (info->Music.IsNotEmpty())
{
- S_ChangeMusic (info->music, info->musicorder);
+ S_ChangeMusic (info->Music, info->musicorder);
Printf ("%s\n", GStrings("STSTR_MUS"));
}
}
diff --git a/src/sc_man.cpp b/src/sc_man.cpp
index 9de966fd..c474439b 100644
--- a/src/sc_man.cpp
+++ b/src/sc_man.cpp
@@ -22,6 +22,7 @@
#include "m_misc.h"
#include "templates.h"
#include "doomstat.h"
+#include "v_text.h"
// MACROS ------------------------------------------------------------------
@@ -752,16 +753,21 @@ void FScanner::UnGet ()
//
//==========================================================================
-int FScanner::MatchString (const char **strings)
+int FScanner::MatchString (const char **strings, size_t stride)
{
int i;
+ assert(stride % sizeof(const char*) == 0);
+
+ stride /= sizeof(const char*);
+
for (i = 0; *strings != NULL; i++)
{
- if (Compare (*strings++))
+ if (Compare (*strings))
{
return i;
}
+ strings += stride;
}
return -1;
}
@@ -772,11 +778,11 @@ int FScanner::MatchString (const char **strings)
//
//==========================================================================
-int FScanner::MustMatchString (const char **strings)
+int FScanner::MustMatchString (const char **strings, size_t stride)
{
int i;
- i = MatchString (strings);
+ i = MatchString (strings, stride);
if (i == -1)
{
ScriptError (NULL);
@@ -1007,7 +1013,7 @@ void STACK_ARGS FScanner::ScriptMessage (const char *message, ...)
va_end (arglist);
}
- Printf ("Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(),
+ Printf (TEXTCOLOR_RED"Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(),
AlreadyGot? AlreadyGotLine : Line, composed.GetChars());
}
diff --git a/src/sc_man.h b/src/sc_man.h
index c74fca94..dcfb9254 100644
--- a/src/sc_man.h
+++ b/src/sc_man.h
@@ -54,8 +54,8 @@ public:
void UnGet();
bool Compare(const char *text);
- int MatchString(const char **strings);
- int MustMatchString(const char **strings);
+ int MatchString(const char **strings, size_t stride = sizeof(char*));
+ int MustMatchString(const char **strings, size_t stride = sizeof(char*));
int GetMessageLine();
void ScriptError(const char *message, ...);
diff --git a/src/sdl/i_input.cpp b/src/sdl/i_input.cpp
index 2f8ba9c6..6cc16feb 100644
--- a/src/sdl/i_input.cpp
+++ b/src/sdl/i_input.cpp
@@ -281,6 +281,25 @@ static void MouseRead ()
}
}
+static void WheelMoved(event_t *event)
+{
+ if (GUICapture)
+ {
+ SDLMod mod = SDL_GetModState();
+ event->type = EV_GUI_Event;
+ event->subtype = event->data1 == KEY_MWHEELUP ? EV_GUI_WheelUp : EV_GUI_WheelDown;
+ event->data1 = 0;
+ event->data3 = ((mod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
+ ((mod & KMOD_CTRL) ? GKM_CTRL : 0) |
+ ((mod & KMOD_ALT) ? GKM_ALT : 0);
+ D_PostEvent(event);
+ }
+ else
+ {
+ D_PostEvent(event);
+ }
+}
+
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
{
if (self < 0) self = 0;
@@ -316,7 +335,7 @@ static void I_CheckNativeMouse ()
{
SDL_ShowCursor (1);
SDL_WM_GrabInput (SDL_GRAB_OFF);
- FlushDIKState (KEY_MOUSE1, KEY_MOUSE4);
+ FlushDIKState (KEY_MOUSE1, KEY_MOUSE8);
}
else
{
@@ -358,6 +377,12 @@ void MessagePump (const SDL_Event &sev)
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
+ /* These button mappings work with my Gentoo system using the
+ * evdev driver and a Logitech MX510 mouse. Whether or not they
+ * carry over to other Linux systems, I have no idea, but I sure
+ * hope so. (Though buttons 11 and 12 are kind of useless, since
+ * they also trigger buttons 4 and 5.)
+ */
switch (sev.button.button)
{
case 1: event.data1 = KEY_MOUSE1; break;
@@ -365,10 +390,28 @@ void MessagePump (const SDL_Event &sev)
case 3: event.data1 = KEY_MOUSE2; break;
case 4: event.data1 = KEY_MWHEELUP; break;
case 5: event.data1 = KEY_MWHEELDOWN; break;
- case 6: event.data1 = KEY_MOUSE4; break; /* dunno */
+ case 6: event.data1 = KEY_MOUSE4; break; /* dunno; not generated by my mouse */
+ case 7: event.data1 = KEY_MOUSE5; break; /* ditto */
+ case 8: event.data1 = KEY_MOUSE4; break;
+ case 9: event.data1 = KEY_MOUSE5; break;
+ case 10: event.data1 = KEY_MOUSE6; break;
+ case 11: event.data1 = KEY_MOUSE7; break;
+ case 12: event.data1 = KEY_MOUSE8; break;
+ default: printf("SDL mouse button %s %d\n",
+ sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break;
+ }
+ if (event.data1 != 0)
+ {
+ //DIKState[ActiveDIKState][event.data1] = (event.type == EV_KeyDown);
+ if (event.data1 == KEY_MWHEELUP || event.data1 == KEY_MWHEELDOWN)
+ {
+ WheelMoved(&event);
+ }
+ else
+ {
+ D_PostEvent(&event);
+ }
}
- //DIKState[ActiveDIKState][event.data1] = (event.type == EV_KeyDown);
- D_PostEvent (&event);
break;
case SDL_KEYDOWN:
diff --git a/src/sdl/i_system.cpp b/src/sdl/i_system.cpp
index bf3ed803..540d6554 100644
--- a/src/sdl/i_system.cpp
+++ b/src/sdl/i_system.cpp
@@ -228,7 +228,6 @@ void I_Quit (void)
if (demorecording)
G_CheckDemoStatus();
- G_ClearSnapshots ();
}
diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp
index 3bcc3714..0d1c5389 100644
--- a/src/sound/fmodsound.cpp
+++ b/src/sound/fmodsound.cpp
@@ -805,7 +805,7 @@ bool FMODSoundRenderer::Init()
}
for (;;)
{
- result = Sys->init(snd_channels + NUM_EXTRA_SOFTWARE_CHANNELS, initflags, 0);
+ result = Sys->init(MAX(*snd_channels, MAX_CHANNELS), initflags, 0);
if (result == FMOD_ERR_OUTPUT_CREATEBUFFER)
{
// Possible causes of a buffer creation failure:
@@ -1435,7 +1435,7 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
GDistScale = distscale;
// Experiments indicate that playSound will ignore priorities and always succeed
- // as long as the paremeters are set properly. It will first try to kick out sounds
+ // as long as the parameters are set properly. It will first try to kick out sounds
// with the same priority level but has no problem with kicking out sounds at
// higher priority levels if it needs to.
result = Sys->playSound(FMOD_CHANNEL_FREE, (FMOD::Sound *)sfx.data, true, &chan);
@@ -1488,6 +1488,7 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *
return NULL;
}
chan->setPaused(false);
+ chan->getPriority(&def_priority);
FISoundChannel *schan = CommonChannelSetup(chan, reuse_chan);
schan->Rolloff = *rolloff;
return schan;
diff --git a/src/svnrevision.h b/src/svnrevision.h
index 5725116b..87718b51 100644
--- a/src/svnrevision.h
+++ b/src/svnrevision.h
@@ -3,5 +3,5 @@
// This file was automatically generated by the
// updaterevision tool. Do not edit by hand.
-#define ZD_SVN_REVISION_STRING "1369"
-#define ZD_SVN_REVISION_NUMBER 1369
+#define ZD_SVN_REVISION_STRING "1401"
+#define ZD_SVN_REVISION_NUMBER 1401
diff --git a/src/teaminfo.cpp b/src/teaminfo.cpp
index 0e6e3da9..39fe58ee 100644
--- a/src/teaminfo.cpp
+++ b/src/teaminfo.cpp
@@ -1,9 +1,9 @@
/*
** teaminfo.cpp
-** Implementation of the TEAMINFO lump.
+** Parses TEAMINFO and manages teams.
**
**---------------------------------------------------------------------------
-** Copyright 2007-2008 Christopher Westley
+** Copyright 2007-2009 Christopher Westley
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@@ -34,12 +34,12 @@
// HEADER FILES ------------------------------------------------------------
+#include "c_dispatch.h"
+#include "gi.h"
#include "i_system.h"
-#include "sc_man.h"
#include "teaminfo.h"
-#include "v_video.h"
-#include "v_palette.h"
#include "v_font.h"
+#include "v_video.h"
#include "w_wad.h"
// MACROS ------------------------------------------------------------------
@@ -50,136 +50,300 @@
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
-void TEAMINFO_Init ();
-void TEAMINFO_ParseTeam (FScanner &sc);
-
-bool TEAMINFO_IsValidTeam (int team);
-
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
-TArray teams;
+FTeam TeamLibrary;
+TArray Teams;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
-static const char *keywords_teaminfo [] = {
- "PLAYERCOLOR",
- "TEXTCOLOR",
- "LOGO",
- NULL
+static const char *TeamInfoOptions[] =
+{
+ "Game",
+ "PlayerColor",
+ "TextColor",
+ "Logo",
+ "AllowCustomPlayerColor",
+ "RailColor",
+ "FlagItem",
+ "SkullItem",
+ "PlayerStartThingNumber",
+ "SmallFlagHUDIcon",
+ "SmallSkullHUDIcon",
+ "LargeFlagHUDIcon",
+ "LargeSkullHUDIcon",
+ "WinnerPic",
+ "LoserPic",
+ "WinnerTheme",
+ "LoserTheme",
+};
+
+enum ETeamOptions
+{
+ TEAMINFO_Game,
+ TEAMINFO_PlayerColor,
+ TEAMINFO_TextColor,
+ TEAMINFO_Logo,
+ TEAMINFO_AllowCustomPlayerColor,
+ TEAMINFO_RailColor,
+ TEAMINFO_FlagItem,
+ TEAMINFO_SkullItem,
+ TEAMINFO_PlayerStartThingNumber,
+ TEAMINFO_SmallFlagHUDIcon,
+ TEAMINFO_SmallSkullHUDIcon,
+ TEAMINFO_LargeFlagHUDIcon,
+ TEAMINFO_LargeSkullHUDIcon,
+ TEAMINFO_WinnerPic,
+ TEAMINFO_LoserPic,
+ TEAMINFO_WinnerTheme,
+ TEAMINFO_LoserTheme,
};
// CODE --------------------------------------------------------------------
//==========================================================================
//
-// TEAMINFO_Init
+// FTeam :: FTeam
//
//==========================================================================
-void TEAMINFO_Init ()
+FTeam::FTeam ()
{
- int lastlump = 0, lump;
-
- while ((lump = Wads.FindLump ("TEAMINFO", &lastlump)) != -1)
- {
- FScanner sc(lump);
- while (sc.GetString ())
- {
- if (sc.Compare("CLEARTEAMS"))
- teams.Clear ();
- else if (sc.Compare("TEAM"))
- TEAMINFO_ParseTeam (sc);
- else
- sc.ScriptError ("Unknown command %s in TEAMINFO", sc.String);
- }
- }
-
- if (teams.Size () < 2)
- I_FatalError ("At least two teams must be defined in TEAMINFO");
+ m_GameFilter = 0;
+ m_iPlayerColor = 0;
+ m_iPlayerCount = 0;
+ m_iScore = 0;
+ m_iPresent = 0;
+ m_iTies = 0;
+ m_bAllowCustomPlayerColor = false;
}
//==========================================================================
//
-// TEAMINFO_ParseTeam
+// FTeam :: ParseTeamInfo
//
//==========================================================================
-void TEAMINFO_ParseTeam (FScanner &sc)
+void FTeam::ParseTeamInfo ()
{
- TEAMINFO team;
- int i;
+ int iLump, iLastLump = 0;
- sc.MustGetString ();
- team.name = sc.String;
-
- sc.MustGetStringName("{");
- while (!sc.CheckString("}"))
+ while ((iLump = Wads.FindLump ("TEAMINFO", &iLastLump)) != -1)
{
- sc.MustGetString();
- switch(i = sc.MatchString (keywords_teaminfo))
+ FScanner Scan (iLump);
+
+ while (Scan.GetString ())
{
- case 0:
- sc.MustGetString ();
- team.playercolor = V_GetColor (NULL, sc.String);
+ if (Scan.Compare ("ClearTeams"))
+ ClearTeams ();
+ else if (Scan.Compare ("Team"))
+ ParseTeamDefinition (Scan);
+ else
+ Scan.ScriptError ("ParseTeamInfo: Unknown team command '%s'.\n", Scan.String);
+ }
+ }
+
+ if (Teams.Size () < 2)
+ I_FatalError ("ParseTeamInfo: At least two teams must be defined in TEAMINFO.");
+ else if (Teams.Size () > TEAM_MAXIMUM)
+ I_FatalError ("ParseTeamInfo: Too many teams defined. (Maximum: %d)", TEAM_MAXIMUM);
+}
+
+//==========================================================================
+//
+// FTeam :: ParseTeamDefinition
+//
+//==========================================================================
+
+void FTeam::ParseTeamDefinition (FScanner &Scan)
+{
+ FTeam Team;
+ Scan.MustGetString ();
+ Team.m_Name = Scan.String;
+ Scan.MustGetStringName ("{");
+
+ while (!Scan.CheckString ("}"))
+ {
+ Scan.MustGetString ();
+
+ switch (Scan.MatchString (TeamInfoOptions))
+ {
+ case TEAMINFO_Game:
+ Scan.MustGetString ();
+
+ if (!stricmp (Scan.String, "Doom"))
+ Team.m_GameFilter |= GAME_Doom;
+ else if (!stricmp (Scan.String, "Heretic"))
+ Team.m_GameFilter |= GAME_Heretic;
+ else if (!stricmp (Scan.String, "Hexen"))
+ Team.m_GameFilter |= GAME_Hexen;
+ else if (!stricmp (Scan.String, "Raven"))
+ Team.m_GameFilter |= GAME_Raven;
+ else if (!stricmp (Scan.String, "Strife"))
+ Team.m_GameFilter |= GAME_Strife;
+ else if (!stricmp (Scan.String, "Chex"))
+ Team.m_GameFilter |= GAME_Chex;
+ else if (!stricmp (Scan.String, "Any"))
+ Team.m_GameFilter |= GAME_Any;
+ else
+ Scan.ScriptError ("ParseTeamDefinition: Unknown game type '%s'.\n", Scan.String);
break;
- case 1:
- sc.MustGetString();
- team.textcolor = '[';
- team.textcolor << sc.String << ']';
+ case TEAMINFO_PlayerColor:
+ Scan.MustGetString ();
+ Team.m_iPlayerColor = V_GetColor (NULL, Scan.String);
break;
- case 2:
- sc.MustGetString ();
- team.logo = sc.String;
+ case TEAMINFO_TextColor:
+ Scan.MustGetString ();
+ Team.m_TextColor.AppendFormat ("[%s]", Scan.String);
+ break;
+
+ case TEAMINFO_Logo:
+ Scan.MustGetString ();
+ Team.m_Logo = Scan.String;
+ break;
+
+ case TEAMINFO_AllowCustomPlayerColor:
+ Team.m_bAllowCustomPlayerColor = true;
+ break;
+
+ case TEAMINFO_PlayerStartThingNumber:
+ Scan.MustGetNumber ();
+ break;
+
+ case TEAMINFO_RailColor:
+ case TEAMINFO_FlagItem:
+ case TEAMINFO_SkullItem:
+ case TEAMINFO_SmallFlagHUDIcon:
+ case TEAMINFO_SmallSkullHUDIcon:
+ case TEAMINFO_LargeFlagHUDIcon:
+ case TEAMINFO_LargeSkullHUDIcon:
+ case TEAMINFO_WinnerPic:
+ case TEAMINFO_LoserPic:
+ case TEAMINFO_WinnerTheme:
+ case TEAMINFO_LoserTheme:
+ Scan.MustGetString ();
break;
default:
+ Scan.ScriptError ("ParseTeamDefinition: Unknown team option '%s'.\n", Scan.String);
break;
}
}
- teams.Push (team);
+ if (Team.m_GameFilter == 0 || Team.m_GameFilter & gameinfo.gametype)
+ Teams.Push (Team);
}
//==========================================================================
//
-// TEAMINFO_IsValidTeam
+// FTeam :: ClearTeams
//
//==========================================================================
-bool TEAMINFO_IsValidTeam (int team)
+void FTeam::ClearTeams ()
{
- if (team < 0 || team >= (signed)teams.Size ())
- {
+ Teams.Clear ();
+}
+
+//==========================================================================
+//
+// FTeam :: IsValidTeam
+//
+//==========================================================================
+
+bool FTeam::IsValidTeam (unsigned int uiTeam)
+{
+ if (uiTeam < 0 || uiTeam >= Teams.Size ())
return false;
- }
return true;
}
//==========================================================================
//
-// TEAMINFO :: GetTextColor
+// FTeam :: GetName
//
//==========================================================================
-int TEAMINFO::GetTextColor () const
+const char *FTeam::GetName () const
{
- if (textcolor.IsEmpty())
+ return m_Name;
+}
+
+//==========================================================================
+//
+// FTeam :: GetPlayerColor
+//
+//==========================================================================
+
+int FTeam::GetPlayerColor () const
+{
+ return m_iPlayerColor;
+}
+
+//==========================================================================
+//
+// FTeam :: GetTextColor
+//
+//==========================================================================
+
+int FTeam::GetTextColor () const
+{
+ if (m_TextColor.IsEmpty ())
+ return CR_UNTRANSLATED;
+
+ const BYTE *pColor = (const BYTE *)m_TextColor.GetChars ();
+ int iColor = V_ParseFontColor (pColor, 0, 0);
+
+ if (iColor == CR_UNDEFINED)
{
+ Printf ("GetTextColor: Undefined color '%s' in definition of team '%s'.\n", m_TextColor.GetChars (), m_Name.GetChars ());
return CR_UNTRANSLATED;
}
- const BYTE *cp = (const BYTE *)textcolor.GetChars();
- int color = V_ParseFontColor(cp, 0, 0);
- if (color == CR_UNDEFINED)
- {
- Printf("Undefined color '%s' in definition of team %s\n", textcolor.GetChars (), name.GetChars ());
- color = CR_UNTRANSLATED;
- }
- return color;
+
+ return iColor;
+}
+
+//==========================================================================
+//
+// FTeam :: GetLogo
+//
+//==========================================================================
+
+FString FTeam::GetLogo () const
+{
+ return m_Logo;
+}
+
+//==========================================================================
+//
+// FTeam :: GetAllowCustomPlayerColor
+//
+//==========================================================================
+
+bool FTeam::GetAllowCustomPlayerColor () const
+{
+ return m_bAllowCustomPlayerColor;
+}
+
+//==========================================================================
+//
+// CCMD teamlist
+//
+//==========================================================================
+
+CCMD (teamlist)
+{
+ Printf ("Defined teams are as follows:\n");
+
+ for (unsigned int uiTeam = 0; uiTeam < Teams.Size (); uiTeam++)
+ Printf ("%d : %s\n", uiTeam, Teams[uiTeam].GetName ());
+
+ Printf ("End of team list.\n");
}
diff --git a/src/teaminfo.h b/src/teaminfo.h
index cacf69fd..f18d63d0 100644
--- a/src/teaminfo.h
+++ b/src/teaminfo.h
@@ -1,9 +1,9 @@
/*
** teaminfo.h
-** Implementation of the TEAMINFO lump.
+** Parses TEAMINFO and manages teams.
**
**---------------------------------------------------------------------------
-** Copyright 2007-2008 Christopher Westley
+** Copyright 2007-2009 Christopher Westley
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@@ -35,28 +35,43 @@
#ifndef __TEAMINFO_H__
#define __TEAMINFO_H__
-#define TEAM_None 255
-
#include "doomtype.h"
+#include "sc_man.h"
-struct TEAMINFO
+const int TEAM_NONE = 255;
+const int TEAM_MAXIMUM = 16;
+
+class FTeam
{
- FString name;
- int playercolor;
- FString textcolor;
- int GetTextColor () const;
- FString logo;
- int players;
- int score;
- int present;
- int ties;
+public:
+ FTeam ();
+ void ParseTeamInfo ();
+ bool IsValidTeam (unsigned int uiTeam);
+
+ const char *GetName () const;
+ int GetPlayerColor () const;
+ int GetTextColor () const;
+ FString GetLogo () const;
+ bool GetAllowCustomPlayerColor () const;
+
+ int m_iPlayerCount;
+ int m_iScore;
+ int m_iPresent;
+ int m_iTies;
+
+private:
+ void ParseTeamDefinition (FScanner &Scan);
+ void ClearTeams ();
+
+ FString m_Name;
+ BYTE m_GameFilter;
+ int m_iPlayerColor;
+ FString m_TextColor;
+ FString m_Logo;
+ bool m_bAllowCustomPlayerColor;
};
-extern TArray teams;
-
-extern void TEAMINFO_Init ();
-extern void TEAMINFO_ParseTeam ();
-
-extern bool TEAMINFO_IsValidTeam (int team);
+extern FTeam TeamLibrary;
+extern TArray Teams;
#endif
diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp
index 811bbc03..5510b1c0 100644
--- a/src/thingdef/thingdef.cpp
+++ b/src/thingdef/thingdef.cpp
@@ -268,7 +268,7 @@ static void FinishThingdef()
// Skip non-actors
if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue;
- if (ti->Size == -1)
+ if (ti->Size == (unsigned)-1)
{
Printf("Class %s referenced but not defined\n", ti->TypeName.GetChars());
errorcount++;
diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h
index 14150d30..611cedc4 100644
--- a/src/thingdef/thingdef.h
+++ b/src/thingdef/thingdef.h
@@ -124,7 +124,7 @@ public:
void Copy(int dest, int src, int cnt);
int ResolveAll();
FxExpression *Get(int no);
- int Size() { return expressions.Size(); }
+ unsigned int Size() { return expressions.Size(); }
};
extern FStateExpressions StateParams;
diff --git a/src/version.h b/src/version.h
index 2e247216..f86cc08b 100644
--- a/src/version.h
+++ b/src/version.h
@@ -77,7 +77,7 @@
// SAVESIG should match SAVEVER.
// MINSAVEVER is the minimum level snapshot version that can be loaded.
-#define MINSAVEVER 1304
+#define MINSAVEVER 1393
#if ZD_SVN_REVISION_NUMBER < MINSAVEVER
// Never write a savegame with a version lower than what we need
diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp
index 5eccd87d..64754950 100644
--- a/src/wi_stuff.cpp
+++ b/src/wi_stuff.cpp
@@ -230,7 +230,7 @@ static FTexture* p; // Player graphic
static FTexture* lnames[2]; // Name graphics of each level (centered)
// [RH] Info to dynamically generate the level name graphics
-static const char *lnametexts[2];
+static FString lnametexts[2];
static FTexture *background;
@@ -297,11 +297,11 @@ void WI_LoadBackground(bool isenterpic)
if (isenterpic)
{
level_info_t * li = FindLevelInfo(wbs->next);
- if (li != NULL) lumpname = li->enterpic;
+ if (li != NULL) lumpname = li->EnterPic;
}
else
{
- lumpname = level.info->exitpic;
+ lumpname = level.info->ExitPic;
}
// Try to get a default if nothing specified
@@ -329,7 +329,7 @@ void WI_LoadBackground(bool isenterpic)
// If going from E1-E3 to E4 the default should be used, not the exit pic.
// Not if the exit pic is user defined!
- if (level.info->exitpic != NULL && level.info->exitpic[0]!=0) return;
+ if (level.info->ExitPic.IsNotEmpty()) return;
// E1-E3 need special treatment when playing Doom 1.
if (gamemode!=commercial)
@@ -712,6 +712,7 @@ int WI_DrawName(int y, const char *levelname)
lumph = BigFont->GetHeight() * CleanYfac;
p = levelname;
+ if (!p) return 0;
l = strlen(p);
if (!l) return 0;
@@ -1885,8 +1886,8 @@ void WI_Ticker(void)
if (bcnt == 1)
{
// intermission music - use the defaults if none specified
- if (level.info->intermusic != NULL)
- S_ChangeMusic(level.info->intermusic, level.info->intermusicorder);
+ if (level.info->InterMusic.IsNotEmpty())
+ S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder);
else if (gameinfo.gametype == GAME_Heretic)
S_ChangeMusic ("mus_intr");
else if (gameinfo.gametype == GAME_Hexen)
@@ -1966,11 +1967,12 @@ void WI_loadData(void)
bstar = star;
}
- // Use the local level structure which can be overridden by hubs if they eventually get names!
- lnametexts[0] = level.level_name;
+ // Use the local level structure which can be overridden by hubs
+ lnametexts[0] = level.LevelName;
level_info_t *li = FindLevelInfo(wbs->next);
- lnametexts[1] = li ? G_MaybeLookupLevelName(li) : NULL;
+ if (li) lnametexts[1] = li->LookupLevelName();
+ else lnametexts[1] = "";
WI_LoadBackground(false);
}
diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp
index 89aa6422..e8e6ce55 100644
--- a/src/win32/fb_d3d9.cpp
+++ b/src/win32/fb_d3d9.cpp
@@ -2405,18 +2405,7 @@ void STACK_ARGS D3DFB::DrawTextureV (FTexture *img, int x, int y, uint32 tags_fi
float u1 = tex->Box->Right;
float v1 = tex->Box->Bottom;
float uscale = 1.f / tex->Box->Owner->Width;
- float vscale = 1.f / tex->Box->Owner->Height / yscale;
-
- if (y0 < parms.uclip)
- {
- v0 += (float(parms.uclip) - y0) * vscale;
- y0 = float(parms.uclip);
- }
- if (y1 > parms.dclip)
- {
- v1 -= (y1 - float(parms.dclip)) * vscale;
- y1 = float(parms.dclip);
- }
+ bool scissoring = false;
if (parms.flipX)
{
@@ -2429,16 +2418,45 @@ void STACK_ARGS D3DFB::DrawTextureV (FTexture *img, int x, int y, uint32 tags_fi
x1 -= (parms.texwidth - parms.windowright) * xscale;
u1 -= (parms.texwidth - parms.windowright) * uscale;
}
+#if 0
+ float vscale = 1.f / tex->Box->Owner->Height / yscale;
+ if (y0 < parms.uclip)
+ {
+ v0 += (float(parms.uclip) - y0) * vscale;
+ y0 = float(parms.uclip);
+ }
+ if (y1 > parms.dclip)
+ {
+ v1 -= (y1 - float(parms.dclip)) * vscale;
+ y1 = float(parms.dclip);
+ }
if (x0 < parms.lclip)
{
- u0 += float(parms.lclip - x0) * uscale / xscale;
+ u0 += float(parms.lclip - x0) * uscale / xscale * 2;
x0 = float(parms.lclip);
}
if (x1 > parms.rclip)
{
- u1 -= float(x1 - parms.rclip) * uscale / xscale;
+ u1 -= (x1 - parms.rclip) * uscale / xscale * 2;
x1 = float(parms.rclip);
}
+#else
+ // Use a scissor test because the math above introduces some jitter
+ // that is noticeable at low resolutions. Unfortunately, this means this
+ // quad has to be in a batch by itself.
+ if (y0 < parms.uclip || y1 > parms.dclip || x0 < parms.lclip || x1 > parms.rclip)
+ {
+ scissoring = true;
+ if (QuadBatchPos > 0)
+ {
+ EndQuadBatch();
+ BeginQuadBatch();
+ }
+ RECT scissor = { parms.lclip, parms.uclip, parms.rclip, parms.dclip };
+ D3DDevice->SetScissorRect(&scissor);
+ D3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
+ }
+#endif
parms.bilinear = false;
D3DCOLOR color0, color1;
@@ -2511,6 +2529,12 @@ void STACK_ARGS D3DFB::DrawTextureV (FTexture *img, int x, int y, uint32 tags_fi
QuadBatchPos++;
VertexPos += 4;
IndexPos += 6;
+
+ if (scissoring)
+ {
+ EndQuadBatch();
+ D3DDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+ }
}
//==========================================================================
diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp
index 4318d95d..9da20744 100644
--- a/src/win32/i_system.cpp
+++ b/src/win32/i_system.cpp
@@ -449,7 +449,6 @@ void I_Quit (void)
if (demorecording)
G_CheckDemoStatus();
- G_ClearSnapshots ();
}
diff --git a/src/zstring.cpp b/src/zstring.cpp
index 9f392643..d126d607 100644
--- a/src/zstring.cpp
+++ b/src/zstring.cpp
@@ -1110,6 +1110,7 @@ void FString::ReallocBuffer (size_t newlen)
#include
static HANDLE StringHeap;
+const SIZE_T STRING_HEAP_SIZE = 64*1024;
#endif
FStringData *FStringData::Alloc (size_t strlen)
@@ -1120,7 +1121,7 @@ FStringData *FStringData::Alloc (size_t strlen)
#ifdef _WIN32
if (StringHeap == NULL)
{
- StringHeap = HeapCreate (0, 64*1024, 0);
+ StringHeap = HeapCreate (0, STRING_HEAP_SIZE, 0);
if (StringHeap == NULL)
{
throw std::bad_alloc();
diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt
index 17b1a1ea..127aeb86 100644
--- a/wadsrc/static/actors/constants.txt
+++ b/wadsrc/static/actors/constants.txt
@@ -13,7 +13,7 @@ const int SXF_ABSOLUTEMOMENTUM=8;
const int SXF_SETMASTER=16;
const int SXF_NOCHECKPOSITION = 32;
const int SXF_TELEFRAG=64;
-// 128 was uses by Skulltag
+const int SXF_CLIENTSPAWN=128; // only used by Skulltag
const int SXF_TRANSFERAMBUSHFLAG=256;
// Flags for A_Chase
diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt
index 129eac58..5db058b3 100644
--- a/wadsrc/static/actors/shared/inventory.txt
+++ b/wadsrc/static/actors/shared/inventory.txt
@@ -327,6 +327,8 @@ Actor Weapon : Inventory native
ACTOR WeaponGiver : Weapon native
{
+ Weapon.AmmoGive1 -1
+ Weapon.AmmoGive2 -1
}
Actor WeaponHolder : Inventory native
diff --git a/wadsrc/static/decaldef.txt b/wadsrc/static/decaldef.txt
index 46d031e0..2bacce72 100644
--- a/wadsrc/static/decaldef.txt
+++ b/wadsrc/static/decaldef.txt
@@ -772,6 +772,30 @@ decal CrossbowScorch2
randomflipy
}
+/***** Phoenix Rod, flamethrower mode **************************************/
+
+decal PhoenixThrowerScorch
+{
+ pic CBALSCR1
+ shade "00 00 00"
+ x-scale 0.4
+ y-scale 0.4
+ randomflipx
+ randomflipy
+}
+
+/***** "Horn Rod", rain maker projectile ***********************************/
+
+decal HornyRainMaker
+{
+ pic TWIRL
+ shade "00 00 00"
+ x-scale 0.7
+ y-scale 0.7
+ randomflipx
+ randomflipy
+}
+
/***** Centaur Scorches ****************************************************/
decal CentaurScorch
@@ -990,15 +1014,17 @@ generator GoldWand RailScorchLower
generator GoldWandPowered RailScorchLower
generator GoldWandFX1 HImpScorch
generator CrossbowFX1 CrossbowScorch
+generator CrossbowFX2 CrossbowScorch
generator CrossbowFX3 CrossbowScorch2
generator MaceFX1 BaronScorch
+generator MaceFX4 BFGScorch
generator Blaster RailScorchLower
generator BlasterFX1 HImpScorch
generator Ripper HImpScorch
generator HornRodFX1 PlasmaScorchLower
-generator HornRodFX2 PlasmaScorchLower
+generator HornRodFX2 HornyRainMaker
generator PhoenixFX1 Scorch
-generator PhoenixFX2 Scorch
+generator PhoenixFX2 PhoenixThrowerScorch
generator CStaffMissile DoomImpScorch
generator HammerMissile Scorch
diff --git a/wadsrc/static/graphics/bfgscrc2.png b/wadsrc/static/graphics/bfgscrc2.png
index 1f8dcf9c..fab62b87 100644
Binary files a/wadsrc/static/graphics/bfgscrc2.png and b/wadsrc/static/graphics/bfgscrc2.png differ