diff --git a/src/g_level.h b/src/g_level.h index 5ca7157c6f..d3f5bd9310 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -54,6 +54,7 @@ class FScanner; #define GCC_YSEG __attribute__((section(SECTION_YREG))) #endif +struct FIntermissionAction; struct FMapInfoParser { @@ -99,6 +100,7 @@ struct FMapInfoParser void SkipToNext(); void CheckEndOfFile(const char *block); + FIntermissionAction *ParseIntermissionAction(); void ParseIntermission(); FName CheckEndSequence(); FName ParseEndGame(); diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index d50ab28bad..fc9077f8cb 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -37,10 +37,13 @@ #include "w_wad.h" #include "intermission/intermission.h" +FIntermissionDescriptorList IntermissionDescriptors; + IMPLEMENT_CLASS(DIntermissionScreen) IMPLEMENT_CLASS(DIntermissionScreenFader) IMPLEMENT_CLASS(DIntermissionScreenText) IMPLEMENT_CLASS(DIntermissionScreenCast) +IMPLEMENT_CLASS(DIntermissionScreenScroller) IMPLEMENT_CLASS(DIntermissionController) void DIntermissionScreen::Init(FIntermissionDescriptor *desc) diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index 37bd18ebaa..51671fffd4 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -39,6 +39,32 @@ struct FICastSound FSoundID mSound; }; +enum EFadeType +{ + FADE_In, + FADE_Out, +}; + +enum EWipeType +{ + WIPE_Default, + WIPE_Cross, + WIPE_Melt, + WIPE_Burn +}; + +enum EScrollDir +{ + SCROLL_Left, + SCROLL_Right, + SCROLL_Up, + SCROLL_Down, +}; + +// actions that don't create objects +#define WIPER_ID ((const PClass*)intptr_t(-1)) +#define TITLE_ID ((const PClass*)intptr_t(-2)) + //========================================================================== struct FIntermissionAction @@ -51,6 +77,7 @@ struct FIntermissionAction int mCdId; int mDuration; FString mBackground; + FString mPalette; FString mSound; bool mFlatfill; TArray mOverlays; @@ -62,16 +89,6 @@ struct FIntermissionAction struct FIntermissionActionFader : public FIntermissionAction { - enum EFadeType - { - FADE_In, - FADE_Out, - FADE_Cross, - FADE_Melt, - FADE_Burn, - FADE_Wipe - }; - typedef FIntermissionAction Super; EFadeType mFadeType; @@ -80,6 +97,16 @@ struct FIntermissionActionFader : public FIntermissionAction virtual bool ParseKey(FScanner &sc); }; +struct FIntermissionActionWiper : public FIntermissionAction +{ + typedef FIntermissionAction Super; + + EWipeType mWipeType; + + FIntermissionActionWiper(); + virtual bool ParseKey(FScanner &sc); +}; + struct FIntermissionActionTextscreen : public FIntermissionAction { typedef FIntermissionAction Super; @@ -96,10 +123,8 @@ struct FIntermissionActionCast : public FIntermissionAction { typedef FIntermissionAction Super; - FString mWalking; - FString mAttacking1; - FString mAttacking2; - FString mDying; + FString mName; + FName mCastClass; TArray mCastSounds; FIntermissionActionCast(); @@ -158,7 +183,7 @@ class DIntermissionScreenFader : public DIntermissionScreen int mTotalTime; int mCounter; - int mType; + EFadeType mType; public: @@ -192,10 +217,7 @@ class DIntermissionScreenCast : public DIntermissionScreen { DECLARE_CLASS (DIntermissionScreenCast, DIntermissionScreen) - FState *mWalking; - FState *mAttacking1; - FState *mAttacking2; - FState *mDying; + FString mName; TArray mCastSounds; public: diff --git a/src/intermission/intermission_parse.cpp b/src/intermission/intermission_parse.cpp index cf78828c13..91b9e94cfb 100644 --- a/src/intermission/intermission_parse.cpp +++ b/src/intermission/intermission_parse.cpp @@ -89,7 +89,7 @@ bool FIntermissionAction::ParseKey(FScanner &sc) sc.MustGetToken('='); if (!sc.CheckToken('-')) { - sc.MustGetToken(TK_FloatConst); + sc.MustGetFloat(); mDuration = xs_RoundToInt(sc.Float*TICRATE); } else @@ -109,6 +109,11 @@ bool FIntermissionAction::ParseKey(FScanner &sc) { sc.MustGetToken(TK_IntConst); mFlatfill = !!sc.Number; + if (sc.CheckToken(',')) + { + sc.MustGetToken(TK_StringConst); + mPalette = sc.String; + } } return true; } @@ -151,7 +156,9 @@ bool FIntermissionAction::ParseKey(FScanner &sc) FIntermissionActionFader::FIntermissionActionFader() { - mFadeType = FADE_Cross; + mSize = sizeof(FIntermissionActionFader); + mClass = RUNTIME_CLASS(DIntermissionScreenFader); + mFadeType = FADE_In; } bool FIntermissionActionFader::ParseKey(FScanner &sc) @@ -164,10 +171,6 @@ bool FIntermissionActionFader::ParseKey(FScanner &sc) const FT[] = { { "FadeIn", FADE_In }, { "FadeOut", FADE_Out }, - { "Crossfade", FADE_Cross }, - { "Melt", FADE_Melt }, - { "Burn", FADE_Burn }, - { "Wipe", FADE_Wipe }, { NULL, FADE_In } }; @@ -175,13 +178,52 @@ bool FIntermissionActionFader::ParseKey(FScanner &sc) { sc.MustGetToken('='); sc.MustGetToken(TK_Identifier); - int v = sc.MustMatchString(&FT[0].Name, sizeof(FT[0])); + int v = sc.MatchString(&FT[0].Name, sizeof(FT[0])); if (v != -1) mFadeType = FT[v].Type; return true; } else return Super::ParseKey(sc); } +//========================================================================== +// +// FIntermissionActionWiper +// +//========================================================================== + +FIntermissionActionWiper::FIntermissionActionWiper() +{ + mSize = sizeof(FIntermissionActionWiper); + mClass = WIPER_ID; + mWipeType = WIPE_Default; +} + +bool FIntermissionActionWiper::ParseKey(FScanner &sc) +{ + struct WipeType + { + const char *Name; + EWipeType Type; + } + const FT[] = { + { "Crossfade", WIPE_Cross }, + { "Melt", WIPE_Melt }, + { "Burn", WIPE_Burn }, + { "Default", WIPE_Default }, + { NULL, WIPE_Default } + }; + + if (sc.Compare("WipeType")) + { + sc.MustGetToken('='); + sc.MustGetToken(TK_Identifier); + int v = sc.MatchString(&FT[0].Name, sizeof(FT[0])); + if (v != -1) mWipeType = FT[v].Type; + return true; + } + else return Super::ParseKey(sc); +} + //========================================================================== // // FIntermissionActionFader @@ -190,6 +232,8 @@ bool FIntermissionActionFader::ParseKey(FScanner &sc) FIntermissionActionTextscreen::FIntermissionActionTextscreen() { + mSize = sizeof(FIntermissionActionTextscreen); + mClass = RUNTIME_CLASS(DIntermissionScreenText); mTextSpeed = 2; mTextX = -1; // use gameinfo defaults mTextY = -1; @@ -218,8 +262,10 @@ bool FIntermissionActionTextscreen::ParseKey(FScanner &sc) } else { - sc.ScriptMessage("Unknown text lump '%s'", sc.String); - mText = "(no message)"; + // only print an error if coming from a PWAD + if (Wads.GetLumpFile(sc.LumpNum) > 1) + sc.ScriptMessage("Unknown text lump '%s'", sc.String); + mText.Format("Unknown text lump '%s'", sc.String); } return true; } @@ -244,44 +290,226 @@ bool FIntermissionActionTextscreen::ParseKey(FScanner &sc) else return Super::ParseKey(sc); } +//========================================================================== +// +// FIntermissionAction +// +//========================================================================== - -void FMapInfoParser::ParseIntermission() +FIntermissionActionCast::FIntermissionActionCast() { - FIntermissionAction *desc; + mSize = sizeof(FIntermissionActionCast); + mClass = RUNTIME_CLASS(DIntermissionScreenCast); +} - while (!sc.CheckString("}")) +bool FIntermissionActionCast::ParseKey(FScanner &sc) +{ + if (sc.Compare("CastName")) { - sc.MustGetString(); - if (sc.Compare("image")) - { - desc = new FIntermissionAction; - } - else if (sc.Compare("scroller")) - { - } - else if (sc.Compare("cast")) - { - } - else if (sc.Compare("Fader")) - { - desc = new FIntermissionActionFader; - } - else if (sc.Compare("TextScreen")) - { - desc = new FIntermissionActionTextscreen; - } - else if (sc.Compare("GotoTitle")) + sc.MustGetToken('='); + sc.MustGetToken(TK_StringConst); + mName = sc.String; + return true; + } + else if (sc.Compare("CastClass")) + { + sc.MustGetToken('='); + sc.MustGetToken(TK_StringConst); + mCastClass = sc.String; + return true; + } + else if (sc.Compare("AttackSound")) + { + static const char *const seqs[] = {"Missile", "Melee", NULL}; + FCastSound *cs = &mCastSounds[mCastSounds.Reserve(1)]; + sc.MustGetToken('='); + sc.MustGetToken(TK_StringConst); + cs->mSequence = (BYTE)sc.MatchString(seqs); + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + cs->mIndex = (BYTE)sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_StringConst); + cs->mSound = sc.String; + return true; + } + else return Super::ParseKey(sc); +} + +//========================================================================== +// +// FIntermissionActionScroller +// +//========================================================================== + +FIntermissionActionScroller::FIntermissionActionScroller() +{ + mSize = sizeof(FIntermissionActionScroller); + mClass = RUNTIME_CLASS(DIntermissionScreenScroller); + mScrollDelay = 0; + mScrollTime = 640; + mScrollDir = SCROLL_Right; +} + +bool FIntermissionActionScroller::ParseKey(FScanner &sc) +{ + struct ScrollType + { + const char *Name; + EScrollDir Type; + } + const ST[] = { + { "Left", SCROLL_Left }, + { "Right", SCROLL_Right }, + { "Up", SCROLL_Up }, + { "Down", SCROLL_Down }, + { NULL, SCROLL_Left } + }; + + if (sc.Compare("ScrollDirection")) + { + sc.MustGetToken('='); + sc.MustGetToken(TK_Identifier); + int v = sc.MatchString(&ST[0].Name, sizeof(ST[0])); + if (v != -1) mScrollDir = ST[v].Type; + return true; + } + else if (sc.Compare("InitialDelay")) + { + sc.MustGetToken('='); + if (!sc.CheckToken('-')) { + sc.MustGetFloat(); + mScrollDelay = xs_RoundToInt(sc.Float*TICRATE); } else { - sc.ScriptMessage("Unknown intermission type '%s'", sc.String); + sc.MustGetToken(TK_IntConst); + mScrollDelay = sc.Number; } + return true; } - + else if (sc.Compare("ScrollTime")) + { + sc.MustGetToken('='); + if (!sc.CheckToken('-')) + { + sc.MustGetFloat(); + mScrollTime = xs_RoundToInt(sc.Float*TICRATE); + } + else + { + sc.MustGetToken(TK_IntConst); + mScrollTime = sc.Number; + } + return true; + } + else if (sc.Compare("Background2")) + { + sc.MustGetToken('='); + sc.MustGetToken(TK_StringConst); + mSecondPic = sc.String; + return true; + } + else return Super::ParseKey(sc); } +//========================================================================== +// +// ParseIntermission +// +//========================================================================== + +FIntermissionAction *FMapInfoParser::ParseIntermissionAction() +{ + FIntermissionAction *desc = NULL; + + sc.MustGetToken(TK_Identifier); + if (sc.Compare("image")) + { + desc = new FIntermissionAction; + } + else if (sc.Compare("scroller")) + { + desc = new FIntermissionActionScroller; + } + else if (sc.Compare("cast")) + { + desc = new FIntermissionActionCast; + } + else if (sc.Compare("Fader")) + { + desc = new FIntermissionActionFader; + } + else if (sc.Compare("Wiper")) + { + desc = new FIntermissionActionWiper; + } + else if (sc.Compare("TextScreen")) + { + desc = new FIntermissionActionTextscreen; + } + else if (sc.Compare("GotoTitle")) + { + desc = new FIntermissionAction; + desc->mClass = TITLE_ID; + } + else + { + sc.ScriptMessage("Unknown intermission type '%s'", sc.String); + } + + sc.MustGetToken('{'); + while (!sc.CheckToken('}')) + { + bool success = false; + if (!sc.CheckToken(TK_Sound)) + { + sc.MustGetToken(TK_Identifier); + } + if (desc != NULL) + { + success = desc->ParseKey(sc); + if (!success) + { + sc.ScriptMessage("Unknown key name '%s'\n", sc.String); + } + } + if (!success) SkipToNext(); + } + return desc; +} + +//========================================================================== +// +// ParseIntermission +// +//========================================================================== + +void FMapInfoParser::ParseIntermission() +{ + sc.MustGetString(); + FName intname = sc.String; + + FIntermissionDescriptor ** pDesc = IntermissionDescriptors.CheckKey(intname); + if (pDesc != NULL && *pDesc != NULL) delete *pDesc; + + FIntermissionDescriptor *desc = new FIntermissionDescriptor(); + IntermissionDescriptors[intname] = desc; + + sc.MustGetToken('{'); + while (!sc.CheckToken('}')) + { + FIntermissionAction *ac = ParseIntermissionAction(); + if (ac != NULL) desc->mActions.Push(ac); + } +} + +//========================================================================== +// +// Parse old style endsequence +// +//========================================================================== struct EndSequence { @@ -383,6 +611,12 @@ FName FMapInfoParser::ParseEndGame() return FName(seq); } +//========================================================================== +// +// Checks map name for end sequence +// +//========================================================================== + FName FMapInfoParser::CheckEndSequence() { const char *seqname = NULL; diff --git a/wadsrc/static/mapinfo/chex.txt b/wadsrc/static/mapinfo/chex.txt index 44d89ae2b0..f006ad751b 100644 --- a/wadsrc/static/mapinfo/chex.txt +++ b/wadsrc/static/mapinfo/chex.txt @@ -1,5 +1,5 @@ // MAPINFO for Chex Quest -#include "mapinfo/common.txt" +include "mapinfo/common.txt" gameinfo { diff --git a/wadsrc/static/mapinfo/common.txt b/wadsrc/static/mapinfo/common.txt index bc548d2e38..15651007cd 100644 --- a/wadsrc/static/mapinfo/common.txt +++ b/wadsrc/static/mapinfo/common.txt @@ -27,7 +27,7 @@ Intermission Inter_Bunny { Scroller { - FadeType = Right + ScrollDirection = Right Background = "PFUB1" Background2 = "PFUB2" Music = "$MUSIC_BUNNY" @@ -94,8 +94,7 @@ Intermission Inter_Underwater { Image { - Background = "E2END" - Palette = "E2PAL" + Background = "E2END", 0, "E2PAL" Time = 10000000 // advance only manually } GotoTitle @@ -107,7 +106,7 @@ Intermission Inter_Demonscroll { Scroller { - FadeType = Up + ScrollDirection = Up Background = "FINAL1" Background2 = "FINAL2" InitialDelay = 2 @@ -119,7 +118,7 @@ Intermission Inter_BuyStrife { Scroller { - FadeType = Right + ScrollDirection = Right Background = "CREDIT" Background2 = "VELLOGO" InitialDelay = -230 @@ -131,125 +130,126 @@ Intermission Inter_Cast { Image { - // This is only here to initialize the background + // This is only here to initialize the background and the music Background = "$bgcastcall" Time = -1 Music = "$MUSIC_EVIL" Link = Doom2Cast } +} Intermission Doom2Cast { Cast { - Class = "Zombieman" - Name = "$CC_ZOMBIE" - Sound = "Missile", 1, "grunt/attack" + CastClass = "Zombieman" + CastName = "$CC_ZOMBIE" + AttackSound = "Missile", 1, "grunt/attack" } Cast { - Class = "ShotgunGuy" - Name = "$CC_SHOTGUN" - Sound = "Missile", 1, "shotguy/attack" + CastClass = "ShotgunGuy" + CastName = "$CC_SHOTGUN" + AttackSound = "Missile", 1, "shotguy/attack" } Cast { - Class = "ChaingunGuy" - Name = "$CC_HEAVY" - Sound = "Missile", 1, "chainguy/attack" - Sound = "Missile", 2, "chainguy/attack" - Sound = "Missile", 3, "chainguy/attack" + CastClass = "ChaingunGuy" + CastName = "$CC_HEAVY" + AttackSound = "Missile", 1, "chainguy/attack" + AttackSound = "Missile", 2, "chainguy/attack" + AttackSound = "Missile", 3, "chainguy/attack" } Cast { - Class = "DoomImp" - Name = "$CC_IMP" - Sound = "Missile", 2, "imp/attack" + CastClass = "DoomImp" + CastName = "$CC_IMP" + AttackSound = "Missile", 2, "imp/attack" } Cast { - Class = "Demon" - Name = "$CC_DEMON" - Sound = "Melee", 1, "demon/melee" + CastClass = "Demon" + CastName = "$CC_DEMON" + AttackSound = "Melee", 1, "demon/melee" } Cast { - Class = "LostSoul" - Name = "$CC_LOST" - Sound = "Missile", 1, "grunt/attack" + CastClass = "LostSoul" + CastName = "$CC_LOST" + AttackSound = "Missile", 1, "grunt/attack" } Cast { - Class = "Cacodemon" - Name = "$CC_CACO" - Sound = "Missile", 1, "caco/attack" + CastClass = "Cacodemon" + CastName = "$CC_CACO" + AttackSound = "Missile", 1, "caco/attack" } Cast { - Class = "HellKnight" - Name = "$CC_HELL" - Sound = "Missile", 1, "baron/attack" + CastClass = "HellKnight" + CastName = "$CC_HELL" + AttackSound = "Missile", 1, "baron/attack" } Cast { - Class = "BaronOfHell" - Name = "$CC_BARON" - Sound = "Missile", 1, "baron/attack" + CastClass = "BaronOfHell" + CastName = "$CC_BARON" + AttackSound = "Missile", 1, "baron/attack" } Cast { - Class = "Arachnotron" - Name = "$CC_ARACH" - Sound = "Missile", 1, "baby/attack" + CastClass = "Arachnotron" + CastName = "$CC_ARACH" + AttackSound = "Missile", 1, "baby/attack" } Cast { - Class = "PainElemental" - Name = "$CC_PAIN" - Sound = "Missile", 2, "skull/melee" + CastClass = "PainElemental" + CastName = "$CC_PAIN" + AttackSound = "Missile", 2, "skull/melee" } Cast { - Class = "Revenant" - Name = "$CC_REVEN" - Sound = "Missile", 1, "skeleton/attack" - Sound = "Melee", 1, "skeleton/swing" - Sound = "Melee", 3, "skeleton/melee" + CastClass = "Revenant" + CastName = "$CC_REVEN" + AttackSound = "Missile", 1, "skeleton/attack" + AttackSound = "Melee", 1, "skeleton/swing" + AttackSound = "Melee", 3, "skeleton/melee" } Cast { - Class = "Fatso" - Name = "$CC_FATSO" - Sound = "Missile", 1, "fatso/attack" - Sound = "Missile", 4, "fatso/attack" - Sound = "Missile", 7, "fatso/attack" + CastClass = "Fatso" + CastName = "$CC_FATSO" + AttackSound = "Missile", 1, "fatso/attack" + AttackSound = "Missile", 4, "fatso/attack" + AttackSound = "Missile", 7, "fatso/attack" } Cast { - Class = "Archvile" - Name = "$CC_ARCH" - Sound = "Missile", 1, "vile/start" + CastClass = "Archvile" + CastName = "$CC_ARCH" + AttackSound = "Missile", 1, "vile/start" } Cast { - Class = "SpiderMastermind" - Name = "$CC_SPIDER" - Sound = "Missile", 1, "spider/attack" - Sound = "Missile", 2, "spider/attack" + CastClass = "SpiderMastermind" + CastName = "$CC_SPIDER" + AttackSound = "Missile", 1, "spider/attack" + AttackSound = "Missile", 2, "spider/attack" } Cast { - Class = "Cyberdemon" - Name = "$CC_CYBER" - Sound = "Missile", 1, "weapons/rocklf" - Sound = "Missile", 3, "weapons/rocklf" - Sound = "Missile", 5, "weapons/rocklf" + CastClass = "Cyberdemon" + CastName = "$CC_CYBER" + AttackSound = "Missile", 1, "weapons/rocklf" + AttackSound = "Missile", 3, "weapons/rocklf" + AttackSound = "Missile", 5, "weapons/rocklf" } Cast { - Class = "DoomPlayer" - Name = "$CC_HERO" - Sound = "Missile", 0, "weapons/sshotf" + CastClass = "DoomPlayer" + CastName = "$CC_HERO" + AttackSound = "Missile", 0, "weapons/sshotf" Link = Doom2Cast // restart cast call } } @@ -338,12 +338,14 @@ Intermission Inter_Strife_Good Background = "SS4F4" Time = 28 } - Fader + Wiper + { + WipeType = Crossfade + } + Image { - Background = "CREDIT" Music = "D_FAST" - Time = 2 - FadeType = Crossfade + Background = "CREDIT" } } @@ -369,12 +371,14 @@ Intermission Inter_Strife_Sad Sound = "svox/ss603a" Time = 9 } - Fader + Wiper + { + WipeType = Crossfade + } + Image { - Background = "CREDIT" Music = "D_FAST" - Time = 2 - FadeType = Crossfade + Background = "CREDIT" } } @@ -399,12 +403,14 @@ Intermission Inter_Strife_Lose Sound = "svox/ss503b" Time = 11 } - Fader + Wiper + { + WipeType = Crossfade + } + Image { - Background = "CREDIT" Music = "D_FAST" - Time = 2 - FadeType = Crossfade + Background = "CREDIT" } } diff --git a/wadsrc/static/mapinfo/doomcommon.txt b/wadsrc/static/mapinfo/doomcommon.txt index 63a86ba178..0ea66d2bd3 100644 --- a/wadsrc/static/mapinfo/doomcommon.txt +++ b/wadsrc/static/mapinfo/doomcommon.txt @@ -1,4 +1,4 @@ -#include "mapinfo/common.txt" +include "mapinfo/common.txt" gameinfo { diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index dee7ad95d1..6b57739778 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -1,5 +1,5 @@ // MAPINFO for Heretic (Shareware and Retail) -#include "mapinfo/common.txt" +include "mapinfo/common.txt" gameinfo { diff --git a/wadsrc/static/mapinfo/hexen.txt b/wadsrc/static/mapinfo/hexen.txt index 6c21eef51e..94e5a1c755 100644 --- a/wadsrc/static/mapinfo/hexen.txt +++ b/wadsrc/static/mapinfo/hexen.txt @@ -1,5 +1,5 @@ // A bare-bones MAPINFO for Hexen. -#include "mapinfo/common.txt" +include "mapinfo/common.txt" // Most of the MAPINFO is still in hexen.wad. diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt index 0568776cc6..61cd849996 100644 --- a/wadsrc/static/mapinfo/strife.txt +++ b/wadsrc/static/mapinfo/strife.txt @@ -1,5 +1,5 @@ // MAPINFO for Strife (full version and teaser) -#include "mapinfo/common.txt" +include "mapinfo/common.txt" gameinfo {