- Externalized all default episode definitions. Added an 'optional' keyword

to handle M4 and 5 in Doom and Heretic.
- Added P_CheckMapData functions and replaced all calls to P_OpenMapData that
  only checked for a map's presence with it.
- Added Martin Howe's player statusbar face submission.
- Added an 'adddefaultmap' option for MAPINFO. This is the same as 'defaultmap'
  but keeps all existing information in the default and just adds to it. This
  is needed because Hexen and Strife set some information in their base
  MAPINFO and using 'defaultmap' in a PWAD would override that.
- Fixed: Using MAPINFO's f1 option could cause memory leaks.
- Added option to load lumps by full name to several places:
  * Finale texts loaded from a text lump
  * Demos
  * Local SNDINFOs
  * Local SNDSEQs
  * Image names in FONTDEFS
  * intermission script names
- Changed the STCFN121 handling. The character is not an 'I' but a '|' so
  instead of discarding it it should be inserted at position 124.
- Renamed indexfont.fon to indexfont so that I could remove a special case
  from V_GetFont that was just added for this one font.
- Added a 'dumpspawnedthings' CVAR that enables a listing of all things in 
  the map and the actor type they spawned.


SVN r882 (trunk)
This commit is contained in:
Christoph Oelckers 2008-04-05 12:14:33 +00:00
commit e105a29e99
34 changed files with 409 additions and 318 deletions

View file

@ -136,7 +136,7 @@ extern const AInventory *SendItemUse, *SendItemDrop;
void *statcopy; // for statistics driver
level_locals_t level; // info about current level
FLevelLocals level; // info about current level
static TArray<cluster_info_t> wadclusterinfos;
TArray<level_info_t> wadlevelinfos;
@ -179,6 +179,7 @@ static const char *MapInfoTopLevel[] =
"clearepisodes",
"skill",
"clearskills",
"adddefaultmap",
NULL
};
@ -191,6 +192,7 @@ enum
MITL_CLEAREPISODES,
MITL_SKILL,
MITL_CLEARSKILLS,
MITL_ADDDEFAULTMAP,
};
static const char *MapInfoMapLevel[] =
@ -336,7 +338,6 @@ enum EMIType
MITYPE_REDIRECT,
MITYPE_SPECIALACTION,
MITYPE_COMPATFLAG,
MITYPE_F1, // [RC] F1 help
};
struct MapInfoHandler
@ -413,18 +414,18 @@ MapHandlers[] =
{ MITYPE_CLRFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
{ MITYPE_SETFLAG, LEVEL_LAXMONSTERACTIVATION, LEVEL_LAXACTIVATIONMAPINFO },
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_LUMPNAME, lioffset(exitpic), 0 },
{ MITYPE_LUMPNAME, lioffset(exitpic), 0 },
{ MITYPE_LUMPNAME, lioffset(enterpic), 0 },
{ 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_LUMPNAME, lioffset(sndseq), 0 },
{ MITYPE_LUMPNAME, lioffset(soundinfo), 0 },
{ MITYPE_LUMPNAME, lioffset(soundinfo), 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 },
@ -445,7 +446,7 @@ MapHandlers[] =
{ MITYPE_COMPATFLAG, COMPATF_BOOMSCROLL},
{ MITYPE_COMPATFLAG, COMPATF_INVISIBILITY},
{ MITYPE_LUMPNAME, lioffset(bordertexture), 0 },
{ MITYPE_F1, lioffset(f1), 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 },
@ -536,10 +537,6 @@ static void SetLevelDefaults (level_info_t *levelinfo)
// For maps without a BEHAVIOR, this will be cleared.
levelinfo->flags |= LEVEL_LAXMONSTERACTIVATION;
}
else
{
levelinfo->flags |= LEVEL_MONSTERFALLINGDAMAGE;
}
levelinfo->airsupply = 10;
}
@ -623,6 +620,48 @@ static FSpecialAction *CopySpecialActions(FSpecialAction *spec)
return spec;
}
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;
}
}
static void ClearClusterInfoStrings(cluster_info_t *cinfo)
{
SafeDelete(cinfo->exittext);
SafeDelete(cinfo->entertext);
SafeDelete(cinfo->messagemusic);
SafeDelete(cinfo->clustername);
}
static void G_DoParseMapInfo (int lump)
{
level_info_t defaultinfo;
@ -647,6 +686,11 @@ static void G_DoParseMapInfo (int lump)
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 <MAPNAME> <Nice Name>
levelflags = defaultinfo.flags;
sc.MustGetString ();
@ -664,7 +708,8 @@ static void G_DoParseMapInfo (int lump)
| LEVEL_FALLDMG_HX
| LEVEL_ACTOWNSPECIAL
| LEVEL_MISSILESACTIVATEIMPACT
| LEVEL_INFINITE_FLIGHT;
| LEVEL_INFINITE_FLIGHT
| LEVEL_MONSTERFALLINGDAMAGE;
}
levelindex = FindWadLevelInfo (sc.String);
if (levelindex == -1)
@ -677,18 +722,13 @@ static void G_DoParseMapInfo (int lump)
}
levelinfo = &wadlevelinfos[levelindex];
memcpy (levelinfo, &defaultinfo, sizeof(*levelinfo));
if (levelinfo->music != NULL)
{
levelinfo->music = copystring (levelinfo->music);
}
if (levelinfo->intermusic != NULL)
{
levelinfo->intermusic = copystring (levelinfo->intermusic);
}
if (levelinfo->translator != NULL)
{
levelinfo->translator = copystring (levelinfo->translator);
}
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);
if (HexenHack)
{
@ -699,13 +739,9 @@ static void G_DoParseMapInfo (int lump)
if (sc.Compare ("lookup"))
{
sc.MustGetString ();
ReplaceString (&levelinfo->level_name, sc.String);
levelflags |= LEVEL_LOOKUPLEVELNAME;
}
else
{
ReplaceString (&levelinfo->level_name, sc.String);
}
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)
@ -730,10 +766,6 @@ static void G_DoParseMapInfo (int lump)
{
strcpy (levelinfo->skypic2, levelinfo->skypic1);
}
if (levelinfo->f1 != NULL)
{
levelinfo->f1 = copystring (levelinfo->f1);
}
SetLevelNum (levelinfo, levelinfo->levelnum); // Wipe out matching levelnums from other maps.
if (levelinfo->pname[0] != 0)
{
@ -755,22 +787,7 @@ static void G_DoParseMapInfo (int lump)
else
{
clusterinfo = &wadclusterinfos[clusterindex];
if (clusterinfo->entertext != NULL)
{
delete[] clusterinfo->entertext;
}
if (clusterinfo->exittext != NULL)
{
delete[] clusterinfo->exittext;
}
if (clusterinfo->messagemusic != NULL)
{
delete[] clusterinfo->messagemusic;
}
if (clusterinfo->clustername != NULL)
{
delete[] clusterinfo->clustername;
}
ClearClusterInfoStrings(clusterinfo);
}
memset (clusterinfo, 0, sizeof(cluster_info_t));
clusterinfo->cluster = sc.Number;
@ -798,60 +815,6 @@ static void G_DoParseMapInfo (int lump)
ClearLevelInfoStrings(&defaultinfo);
}
static void ClearLevelInfoStrings(level_info_t *linfo)
{
if (linfo->music != NULL)
{
delete[] linfo->music;
linfo->music = NULL;
}
if (linfo->intermusic != NULL)
{
delete[] linfo->intermusic;
linfo->intermusic = NULL;
}
if (linfo->level_name != NULL)
{
delete[] linfo->level_name;
linfo->level_name = NULL;
}
if (linfo->translator != NULL)
{
delete[] linfo->translator;
linfo->translator = NULL;
}
for (FSpecialAction *spac = linfo->specialactions; spac != NULL; )
{
FSpecialAction *next = spac->Next;
delete spac;
spac = next;
}
}
static void ClearClusterInfoStrings(cluster_info_t *cinfo)
{
if (cinfo->exittext != NULL)
{
delete[] cinfo->exittext;
cinfo->exittext = NULL;
}
if (cinfo->entertext != NULL)
{
delete[] cinfo->entertext;
cinfo->entertext = NULL;
}
if (cinfo->messagemusic != NULL)
{
delete[] cinfo->messagemusic;
cinfo->messagemusic = NULL;
}
if (cinfo->clustername != NULL)
{
delete[] cinfo->clustername;
cinfo->clustername = NULL;
}
}
static void ClearEpisodes()
{
for (int i = 0; i < EpiDef.numitems; ++i)
@ -916,13 +879,6 @@ static void ParseMapInfoLower (FScanner &sc,
case MITYPE_REDIRECT:
sc.MustGetString ();
levelinfo->RedirectType = sc.String;
/*
if (levelinfo->RedirectType == NULL ||
!(levelinfo->RedirectType->IsDescendantOf (RUNTIME_CLASS(AInventory))))
{
SC_ScriptError ("%s is not an inventory item", sc.String);
}
*/
// Intentional fall-through
case MITYPE_MAPNAME: {
@ -1077,18 +1033,6 @@ static void ParseMapInfoLower (FScanner &sc,
ReplaceString ((char **)(info + handler->data1), sc.String);
break;
case MITYPE_F1:
sc.MustGetString ();
{
char *colon = strchr (sc.String, ':');
if (colon)
{
*colon = 0;
}
ReplaceString ((char **)(info + handler->data1), sc.String);
}
break;
case MITYPE_MUSIC:
sc.MustGetString ();
{
@ -1190,6 +1134,7 @@ static void ParseEpisodeInfo (FScanner &sc)
bool remove = false;
char key = 0;
bool noskill = false;
bool optional = false;
// Get map name
sc.MustGetString ();
@ -1208,7 +1153,12 @@ static void ParseEpisodeInfo (FScanner &sc)
}
do
{
if (sc.Compare ("name"))
if (sc.Compare ("optional"))
{
// For M4 in Doom and M4 and M5 in Heretic
optional = true;
}
else if (sc.Compare ("name"))
{
sc.MustGetString ();
ReplaceString (&pic, sc.String);
@ -1241,6 +1191,17 @@ static void ParseEpisodeInfo (FScanner &sc)
}
while (sc.GetString ());
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)
@ -1408,8 +1369,8 @@ void P_RemoveDefereds (void)
bool CheckWarpTransMap (char mapname[9], bool substitute)
{
if (mapname[0] == '&' && mapname[1] == 'w' &&
mapname[2] == 't' && mapname[3] == '@')
if (mapname[0] == '&' && (mapname[1]&223) == 'W' &&
(mapname[2]&223) == 'T' && mapname[3] == '@')
{
level_info_t *lev = FindLevelByWarpTrans (atoi (mapname + 4));
if (lev != NULL)
@ -1457,12 +1418,12 @@ CCMD (map)
}
if (argv.argc() > 1)
{
MapData * map = P_OpenMapData(argv[1]);
if (map == NULL)
if (!P_CheckMapData(argv[1]))
{
Printf ("No map %s\n", argv[1]);
}
else
{
delete map;
G_DeferedInitNew (argv[1]);
}
}
@ -1482,12 +1443,12 @@ CCMD (open)
if (argv.argc() > 1)
{
sprintf(d_mapname, "file:%s", argv[1]);
MapData * map = P_OpenMapData(d_mapname);
if (map == NULL)
if (!P_CheckMapData(d_mapname))
{
Printf ("No map %s\n", d_mapname);
}
else
{
delete map;
gameaction = ga_newgame2;
d_skill = -1;
}
@ -1638,12 +1599,10 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
}
// [RH] If this map doesn't exist, bomb out
MapData * map = P_OpenMapData(mapname);
if (!map)
if (!P_CheckMapData(mapname))
{
I_Error ("Could not find map %s\n", mapname);
}
delete map;
oldSpeed = GameSpeed;
wantFast = !!G_SkillProperty(SKILLP_FastMonsters);
@ -1815,10 +1774,8 @@ const char *G_GetSecretExitMap()
if (level.secretmap[0] != 0)
{
MapData *map = P_OpenMapData(level.secretmap);
if (map != NULL)
if (P_CheckMapData(level.secretmap))
{
delete map;
nextmap = level.secretmap;
}
}
@ -2061,7 +2018,7 @@ void G_DoLoadLevel (int position, bool autosave)
// DOOM determines the sky texture to be used
// depending on the current episode and the game version.
// [RH] Fetch sky parameters from level_locals_t.
// [RH] Fetch sky parameters from FLevelLocals.
sky1texture = TexMan.GetTexture (level.skypic1, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
sky2texture = TexMan.GetTexture (level.skypic2, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable);
@ -2421,7 +2378,6 @@ void G_InitLevelLocals ()
level.levelnum = info->levelnum;
level.music = info->music;
level.musicorder = info->musicorder;
level.f1 = info->f1; // [RC] And import the f1 name
strncpy (level.level_name, info->level_name, 63);
G_MaybeLookupLevelName (NULL);
@ -2454,7 +2410,7 @@ void G_InitLevelLocals ()
NormalLight.ChangeFade (level.fadeto);
}
bool level_locals_s::IsJumpingAllowed() const
bool FLevelLocals::IsJumpingAllowed() const
{
if (dmflags & DF_NO_JUMP)
return false;
@ -2463,7 +2419,7 @@ bool level_locals_s::IsJumpingAllowed() const
return !(level.flags & LEVEL_JUMP_NO);
}
bool level_locals_s::IsCrouchingAllowed() const
bool FLevelLocals::IsCrouchingAllowed() const
{
if (dmflags & DF_NO_CROUCH)
return false;
@ -2472,7 +2428,7 @@ bool level_locals_s::IsCrouchingAllowed() const
return !(level.flags & LEVEL_CROUCH_NO);
}
bool level_locals_s::IsFreelookAllowed() const
bool FLevelLocals::IsFreelookAllowed() const
{
if (level.flags & LEVEL_FREELOOK_NO)
return false;
@ -2531,10 +2487,8 @@ level_info_t *CheckLevelRedirect (level_info_t *info)
if (playeringame[i] && players[i].mo->FindInventory (type))
{
// check for actual presence of the map.
MapData * map = P_OpenMapData(info->RedirectMap);
if (map != NULL)
if (P_CheckMapData(info->RedirectMap))
{
delete map;
return FindLevelInfo(info->RedirectMap);
}
break;
@ -2621,90 +2575,6 @@ const char *G_MaybeLookupLevelName (level_info_t *ininfo)
return info != NULL ? info->level_name : NULL;
}
void G_MakeEpisodes ()
{
int i;
// Set the default episodes
if (EpiDef.numitems == 0)
{
static const char eps[5][8] =
{
"E1M1", "E2M1", "E3M1", "E4M1", "E5M1"
};
static const char depinames[4][7] =
{
"M_EPI1", "M_EPI2", "M_EPI3", "M_EPI4"
};
static const char depikeys[4] = { 'k', 't', 'i', 't' };
static const char *hepinames[5] =
{
"$MNU_COTD",
"$MNU_HELLSMAW",
"$MNU_DOME",
"$MNU_OSSUARY",
"$MNU_DEMESNE",
};
static const char hepikeys[5] = { 'c', 'h', 'd', 'o', 's' };
if (gameinfo.flags & GI_MAPxx)
{
if (gameinfo.gametype == GAME_Hexen)
{
// "&wt@01" is a magic name that will become whatever map has
// warptrans 1.
strcpy (EpisodeMaps[0], "&wt@01");
EpisodeMenu[0].name = copystring ("Hexen");
}
else
{
strcpy (EpisodeMaps[0], "MAP01");
EpisodeMenu[0].name = copystring ("Hell on Earth");
}
EpisodeMenu[0].alphaKey = 'h';
EpisodeMenu[0].fulltext = true;
EpiDef.numitems = 1;
}
else if (gameinfo.gametype == GAME_Doom)
{
memcpy (EpisodeMaps, eps, 4*8);
for (i = 0; i < 4; ++i)
{
EpisodeMenu[i].name = copystring (depinames[i]);
EpisodeMenu[i].fulltext = false;
EpisodeMenu[i].alphaKey = depikeys[i];
}
if (gameinfo.flags & GI_MENUHACK_RETAIL)
{
EpiDef.numitems = 4;
}
else
{
EpiDef.numitems = 3;
}
}
else
{
memcpy (EpisodeMaps, eps, 5*8);
for (i = 0; i < 5; ++i)
{
EpisodeMenu[i].name = copystring (hepinames[i]);
EpisodeMenu[i].fulltext = true;
EpisodeMenu[i].alphaKey = hepikeys[i];
}
if (gameinfo.flags & GI_MENUHACK_EXTENDED)
{
EpiDef.numitems = 5;
}
else
{
EpiDef.numitems = 3;
}
}
}
}
void G_AirControlChanged ()
{
if (level.aircontrol <= 256)
@ -3145,7 +3015,7 @@ void P_ReadACSDefereds (PNGHandle *png)
}
void level_locals_s::Tick ()
void FLevelLocals::Tick ()
{
// Reset carry sectors
if (Scrolls != NULL)
@ -3154,7 +3024,7 @@ void level_locals_s::Tick ()
}
}
void level_locals_s::AddScroller (DScroller *scroller, int secnum)
void FLevelLocals::AddScroller (DScroller *scroller, int secnum)
{
if (secnum < 0)
{