From bdd20d3887d7ec0c9c5872d218b2180c3f1fa79f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 21 Feb 2017 22:36:20 +0200 Subject: [PATCH 1/8] Fixed initialization of Strife dialogs internal structures Explicit assignment to members, no more memset() on non-PoD types https://mantis.zdoom.org/view.php?id=317 --- src/p_conversation.cpp | 10 ---------- src/p_conversation.h | 28 +++++++++++++--------------- src/p_usdf.cpp | 3 --- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index 449f9e286f..90271333c2 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -568,16 +568,6 @@ FStrifeDialogueNode::~FStrifeDialogueNode () } } -//============================================================================ -// -// FStrifeDialogueReply :: ~FStrifeDialogueReply -// -//============================================================================ - -FStrifeDialogueReply::~FStrifeDialogueReply () -{ -} - //============================================================================ // // FindNode diff --git a/src/p_conversation.h b/src/p_conversation.h index 302203bd2a..7ee24093b6 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -20,19 +20,19 @@ struct FStrifeDialogueItemCheck struct FStrifeDialogueNode { ~FStrifeDialogueNode (); - PClassActor *DropType; + PClassActor *DropType = nullptr; TArray ItemCheck; - int ThisNodeNum; // location of this node in StrifeDialogues - int ItemCheckNode; // index into StrifeDialogues + int ThisNodeNum = 0; // location of this node in StrifeDialogues + int ItemCheckNode = 0; // index into StrifeDialogues - PClassActor *SpeakerType; + PClassActor *SpeakerType = nullptr; FString SpeakerName; FSoundID SpeakerVoice; FString Backdrop; FString Dialogue; FString Goodbye; // must init to null for binary scripts to work as intended - FStrifeDialogueReply *Children; + FStrifeDialogueReply *Children = nullptr; FName MenuClassName; FString UserData; }; @@ -40,13 +40,11 @@ struct FStrifeDialogueNode // FStrifeDialogueReply holds responses the player can give to the NPC struct FStrifeDialogueReply { - ~FStrifeDialogueReply (); - - FStrifeDialogueReply *Next; - PClassActor *GiveType; - int ActionSpecial; - int Args[5]; - int PrintAmount; + FStrifeDialogueReply *Next = nullptr; + PClassActor *GiveType = nullptr; + int ActionSpecial = 0; + int Args[5] = {}; + int PrintAmount = 0; TArray ItemCheck; TArray ItemCheckRequire; TArray ItemCheckExclude; @@ -54,9 +52,9 @@ struct FStrifeDialogueReply FString QuickYes; FString QuickNo; FString LogString; - int NextNode; // index into StrifeDialogues - int LogNumber; - bool NeedsGold; + int NextNode = 0; // index into StrifeDialogues + int LogNumber = 0; + bool NeedsGold = false; }; extern TArray StrifeDialogues; diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index d2a1bb25e5..5a5f3c8269 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -121,7 +121,6 @@ class USDFParser : public UDMFParserBase bool ParseChoice(FStrifeDialogueReply **&replyptr) { FStrifeDialogueReply *reply = new FStrifeDialogueReply; - memset(reply, 0, sizeof(*reply)); reply->Next = *replyptr; *replyptr = reply; @@ -293,8 +292,6 @@ class USDFParser : public UDMFParserBase { FStrifeDialogueNode *node = new FStrifeDialogueNode; FStrifeDialogueReply **replyptr = &node->Children; - memset(node, 0, sizeof(*node)); - //node->ItemCheckCount[0] = node->ItemCheckCount[1] = node->ItemCheckCount[2] = -1; node->ThisNodeNum = StrifeDialogues.Push(node); node->ItemCheckNode = -1; From b45418d3636b4e286fbdb00e9708d30c8149d64e Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 12:21:04 +0200 Subject: [PATCH 2/8] Removed problematic assert() from garbage collector DObject::GetClass() cannot be called from Barrier() function Lazy evaluation it contains screwed up object type if called from base class constructor Example: DSeqSectorNode::DSeqSectorNode() -> DSeqNode::DSeqNode() -> GC::WriteBarrier() -> Barrier() https://mantis.zdoom.org/view.php?id=299 --- src/dobjgc.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dobjgc.cpp b/src/dobjgc.cpp index 4fe609a5a0..3d683aff11 100644 --- a/src/dobjgc.cpp +++ b/src/dobjgc.cpp @@ -544,7 +544,6 @@ void FullGC() void Barrier(DObject *pointing, DObject *pointed) { - assert(pointed->GetClass() != nullptr); assert(pointing == NULL || (pointing->IsBlack() && !pointing->IsDead())); assert(pointed->IsWhite() && !pointed->IsDead()); assert(State != GCS_Finalize && State != GCS_Pause); From 61de40c6788828ec91b3d91caef579567757c6a0 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 17:39:04 +0200 Subject: [PATCH 3/8] Relaxed error check for menu textures Null texture is acceptable as menu patch Total conversion IWADs like Adventures of Square may use this technique https://mantis.zdoom.org/view.php?id=320 --- src/menu/menudef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 16b5671663..bc95198f27 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -411,7 +411,7 @@ static void ParseListMenuBody(FScanner &sc, DListMenuDescriptor *desc) else if (args[i] == TypeTextureID) { auto f = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); - if (!f.isValid()) + if (!f.Exists()) { sc.ScriptError("Unknown texture %s", sc.String); } From 322aee97d60e14f35a381f448e2a1fc214a6fb93 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 22:25:24 +0200 Subject: [PATCH 4/8] Removed dynamic light binding for deleted class StrifeZap1 https://mantis.zdoom.org/view.php?id=311 --- wadsrc_lights/static/filter/strife/gldefs.txt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/wadsrc_lights/static/filter/strife/gldefs.txt b/wadsrc_lights/static/filter/strife/gldefs.txt index 8a2bdcc5dc..7474486ba0 100644 --- a/wadsrc_lights/static/filter/strife/gldefs.txt +++ b/wadsrc_lights/static/filter/strife/gldefs.txt @@ -2651,16 +2651,6 @@ flickerlight LGNTAIL chance 0.8 } -object StrifeZap1 -{ - frame ZAP1A { light ARROWZAP1 } - frame ZAP1B { light ARROWZAP2 } - frame ZAP1C { light ARROWZAP3 } - frame ZAP1D { light ARROWZAP4 } - frame ZAP1E { light ARROWZAP5 } - frame ZAP1F { light ARROWZAP6 } -} - object SpectralLightningBase { frame ZAP1A { light ARROWZAP1 } @@ -2871,4 +2861,4 @@ object TeleportFog frame TFOGD { light TFOG4 } frame TFOGE { light TFOG5 } frame TFOGF { light TFOG6 } -} \ No newline at end of file +} From eb40e8bcf0a035e1922119bcf1b44877719455b1 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 22 Feb 2017 23:02:58 +0200 Subject: [PATCH 5/8] Removed DYNLIGHT preprocessor definition https://mantis.zdoom.org/view.php?id=318 --- src/scripting/decorate/thingdef_states.cpp | 4 +--- src/scripting/zscript/zcc_compile.cpp | 3 +-- src/version.h | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/scripting/decorate/thingdef_states.cpp b/src/scripting/decorate/thingdef_states.cpp index 74c67cf84e..b3d4c904a2 100644 --- a/src/scripting/decorate/thingdef_states.cpp +++ b/src/scripting/decorate/thingdef_states.cpp @@ -315,9 +315,7 @@ do_stop: do { sc.MustGetString(); - #ifdef DYNLIGHT - AddStateLight(&state, sc.String); - #endif + AddStateLight(&state, sc.String); } while (sc.CheckString(",")); sc.MustGetStringName(")"); diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 29f82d90e9..b28226efbb 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2562,7 +2562,7 @@ void ZCCCompiler::CompileStates() state.Misc1 = IntConstFromNode(sl->Offset, c->Type()); state.Misc2 = IntConstFromNode(static_cast(sl->Offset->SiblingNext), c->Type()); } -#ifdef DYNLIGHT + if (sl->Lights != nullptr) { auto l = sl->Lights; @@ -2572,7 +2572,6 @@ void ZCCCompiler::CompileStates() l = static_cast(l->SiblingNext); } while (l != sl->Lights); } -#endif if (sl->Action != nullptr) { diff --git a/src/version.h b/src/version.h index 5ee5472f2f..a03c6a21e8 100644 --- a/src/version.h +++ b/src/version.h @@ -87,8 +87,6 @@ const char *GetVersionString(); // SVN revision ever got. #define SAVEVER 4550 -#define DYNLIGHT - // This is so that derivates can use the same savegame versions without worrying about engine compatibility #define GAMESIG "GZDOOM" #define BASEWAD "gzdoom.pk3" From 59d304274ff7f73423b822bcb8b7e82c68af2b11 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 22 Feb 2017 23:20:54 +0100 Subject: [PATCH 6/8] - Fixed some scripts showing up as 'unknown'. See https://mantis.zdoom.org/view.php?id=322 . --- src/p_acs.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 00b1d7be85..463868d88a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2821,6 +2821,8 @@ void FBehavior::StaticStartTypedScripts (WORD type, AActor *activator, bool alwa "Unloading", "Disconnect", "Return", + "Event", + "Kill", "Reopen" }; DPrintf(DMSG_NOTIFY, "Starting all scripts of type %d (%s)\n", type, From 47ff6ec33fb198aadd1c9b0cc1365ecb6f583f10 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 22 Feb 2017 23:52:25 +0100 Subject: [PATCH 7/8] - converted the intermission stat screen into a class so that its contents can be better exposed to ZScript. --- src/gi.cpp | 3 + src/wi_stuff.cpp | 3885 ++++++++++++++++---------------- wadsrc/static/zscript/base.txt | 9 + 3 files changed, 1951 insertions(+), 1946 deletions(-) diff --git a/src/gi.cpp b/src/gi.cpp index 18fd39f69b..fa8afb5459 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -53,6 +53,9 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gametype) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, norandomplayerclass) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, infoPages) DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenMapNameFont) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenEnteringFont) +DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenFinishedFont) const char *GameNames[17] = diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 73a5b9742e..ebc022df8d 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -54,237 +54,13 @@ #include "cmdlib.h" #include "g_levellocals.h" -// States for the intermission -typedef enum -{ - NoState = -1, - StatCount, - ShowNextLoc, - LeavingIntermission -} stateenum_t; - -CVAR (Bool, wi_percents, true, CVAR_ARCHIVE) -CVAR (Bool, wi_showtotaltime, true, CVAR_ARCHIVE) -CVAR (Bool, wi_noautostartmap, false, CVAR_USERINFO|CVAR_ARCHIVE) -CVAR (Int, wi_autoadvance, 0, CVAR_SERVERINFO) +CVAR(Bool, wi_percents, true, CVAR_ARCHIVE) +CVAR(Bool, wi_showtotaltime, true, CVAR_ARCHIVE) +CVAR(Bool, wi_noautostartmap, false, CVAR_USERINFO | CVAR_ARCHIVE) +CVAR(Int, wi_autoadvance, 0, CVAR_SERVERINFO) -void WI_loadData (); -void WI_unloadData (); - -// GLOBAL LOCATIONS -#define WI_TITLEY 2 -#define WI_SPACINGY 33 - -// SINGPLE-PLAYER STUFF -#define SP_STATSX 50 -#define SP_STATSY 50 - -#define SP_TIMEX 8 -#define SP_TIMEY (200-32) - - -// NET GAME STUFF -#define NG_STATSY 50 -#define NG_STATSX (32 + star->GetScaledWidth()/2 + 32*!dofrags) - -#define NG_SPACINGX 64 - - -// DEATHMATCH STUFF -#define DM_MATRIXX 42 -#define DM_MATRIXY 68 - -#define DM_SPACINGX 40 - -#define DM_TOTALSX 269 - -#define DM_KILLERSX 10 -#define DM_KILLERSY 100 -#define DM_VICTIMSX 5 -#define DM_VICTIMSY 50 - -// These animation variables, structures, etc. are used for the -// DOOM/Ultimate DOOM intermission screen animations. This is -// totally different from any sprite or texture/flat animations -typedef enum -{ - ANIM_ALWAYS, // determined by patch entry - ANIM_PIC, // continuous - - // condition bitflags - ANIM_IFVISITED=8, - ANIM_IFNOTVISITED=16, - ANIM_IFENTERING=32, - ANIM_IFNOTENTERING=64, - ANIM_IFLEAVING=128, - ANIM_IFNOTLEAVING=256, - ANIM_IFTRAVELLING=512, - ANIM_IFNOTTRAVELLING=1024, - - ANIM_TYPE=7, - ANIM_CONDITION=~7, - -} animenum_t; - -struct yahpt_t -{ - int x, y; -}; - -struct lnode_t -{ - int x; // x/y coordinate pair structure - int y; - char level[9]; -} ; - - -#define FACEBACKOFS 4 - - -// -// Animation. -// There is another anim_t used in p_spec. -// (which is why I have renamed this one!) -// - -#define MAX_ANIMATION_FRAMES 20 -struct in_anim_t -{ - int type; // Made an int so I can use '|' - int period; // period in tics between animations - int nanims; // number of animation frames - yahpt_t loc; // location of animation - int data; // ALWAYS: n/a, RANDOM: period deviation (<256) - FTexture * p[MAX_ANIMATION_FRAMES]; // actual graphics for frames of animations - - // following must be initialized to zero before use! - int nexttic; // next value of bcnt (used in conjunction with period) - int ctr; // next frame number to animate - int state; // used by RANDOM and LEVEL when animating - - char levelname[9]; - char levelname2[9]; -}; - -static TArray lnodes; -static TArray anims; - - -// -// GENERAL DATA -// - -// -// Locally used stuff. -// - - -// States for single-player -#define SP_KILLS 0 -#define SP_ITEMS 2 -#define SP_SECRET 4 -#define SP_FRAGS 6 -#define SP_TIME 8 -#define SP_PAR ST_TIME - -#define SP_PAUSE 1 - -#define SHOWNEXTLOCDELAY 4 // in seconds - -static int acceleratestage; // used to accelerate or skip a stage -static bool playerready[MAXPLAYERS]; -static int me; // wbs->pnum -static stateenum_t state; // specifies current state -static wbstartstruct_t *wbs; // contains information passed into intermission -static wbplayerstruct_t*plrs; // wbs->plyr[] -static int cnt; // used for general timing -static int bcnt; // used for timing of background animation -static int cnt_kills[MAXPLAYERS]; -static int cnt_items[MAXPLAYERS]; -static int cnt_secret[MAXPLAYERS]; -static int cnt_frags[MAXPLAYERS]; -static int cnt_deaths[MAXPLAYERS]; -static int cnt_time; -static int cnt_total_time; -static int cnt_par; -static int cnt_pause; -static int total_frags; -static int total_deaths; -static bool noautostartmap; -static int dofrags; -static int ng_state; - -// -// GRAPHICS -// - -struct FPatchInfo -{ - FFont *mFont; - FTexture *mPatch; - EColorRange mColor; - - void Init(FGIFont &gifont) - { - if (gifont.color == NAME_Null) - { - mPatch = TexMan[gifont.fontname]; // "entering" - mColor = mPatch == NULL? CR_UNTRANSLATED : CR_UNDEFINED; - mFont = NULL; - } - else - { - mFont = V_GetFont(gifont.fontname); - mColor = V_FindFontColor(gifont.color); - mPatch = NULL; - } - if (mFont == NULL) - { - mFont = BigFont; - } - } -}; - -static FPatchInfo mapname; -static FPatchInfo finished; -static FPatchInfo entering; - -static TArray yah; // You Are Here graphic -static FTexture* splat; // splat -static FTexture* sp_secret; // "secret" -static FTexture* kills; // "Kills", "Scrt", "Items", "Frags" -static FTexture* secret; -static FTexture* items; -static FTexture* frags; -static FTexture* timepic; // Time sucks. -static FTexture* par; -static FTexture* sucks; -static FTexture* killers; // "killers", "victims" -static FTexture* victims; -static FTexture* total; // "Total", your face, your dead face -//static FTexture* star; -//static FTexture* bstar; -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 FString lnametexts[2]; - -static FTexture *background; - -// -// CODE -// - -// ==================================================================== -// -// Background script commands -// -// ==================================================================== - -static const char *WI_Cmd[]={ +static const char *WI_Cmd[] = { "Background", "Splat", "Pointer", @@ -307,1880 +83,2097 @@ static const char *WI_Cmd[]={ NULL }; -//==================================================================== -// -// Loads the background - either from a single texture -// or an intermission lump. -// Unfortunately the texture manager is incapable of recognizing text -// files so if you use a script you have to prefix its name by '$' in -// MAPINFO. -// -//==================================================================== -static bool IsExMy(const char * name) + +struct FPatchInfo { - // Only check for the first 3 episodes. They are the only ones with default intermission scripts. - // Level names can be upper- and lower case so use tolower to check! - return (tolower(name[0])=='e' && name[1]>='1' && name[1]<='3' && tolower(name[2])=='m'); -} + FFont *mFont; + FTexture *mPatch; + EColorRange mColor; -void WI_LoadBackground(bool isenterpic) -{ - const char *lumpname = NULL; - char buffer[10]; - in_anim_t an; - lnode_t pt; - FTextureID texture; - - bcnt=0; - - texture.SetInvalid(); - if (isenterpic) + void Init(FGIFont &gifont) { - level_info_t * li = FindLevelInfo(wbs->next); - if (li != NULL) lumpname = li->EnterPic; - } - else - { - lumpname = level.info->ExitPic; - } - - // Try to get a default if nothing specified - if (lumpname == NULL || lumpname[0]==0) - { - lumpname = NULL; - switch(gameinfo.gametype) + if (gifont.color == NAME_Null) { - case GAME_Chex: - case GAME_Doom: - if (!(gameinfo.flags & GI_MAPxx)) - { - const char *level = isenterpic ? wbs->next : wbs->current; - if (IsExMy(level)) - { - mysnprintf(buffer, countof(buffer), "$IN_EPI%c", level[1]); - lumpname = buffer; - } - } - if (!lumpname) - { - if (isenterpic) - { - // One special case needs to be handled here! - // 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.IsNotEmpty()) return; - - // E1-E3 need special treatment when playing Doom 1. - if (!(gameinfo.flags & GI_MAPxx)) - { - // not if the last level is not from the first 3 episodes - if (!IsExMy(wbs->current)) return; - - // not if the next level is one of the first 3 episodes - if (IsExMy(wbs->next)) return; - } - } - lumpname = "INTERPIC"; - } - break; - - case GAME_Heretic: - if (isenterpic) - { - if (IsExMy(wbs->next)) - { - mysnprintf(buffer, countof(buffer), "$IN_HTC%c", wbs->next[1]); - lumpname = buffer; - } - } - if (!lumpname) - { - if (isenterpic) return; - lumpname = "FLOOR16"; - } - break; - - case GAME_Hexen: - if (isenterpic) return; - lumpname = "INTERPIC"; - break; - - case GAME_Strife: - default: - // Strife doesn't have an intermission pic so choose something neutral. - if (isenterpic) return; - lumpname = gameinfo.BorderFlat; - break; + mPatch = TexMan[gifont.fontname]; // "entering" + mColor = mPatch == NULL ? CR_UNTRANSLATED : CR_UNDEFINED; + mFont = NULL; + } + else + { + mFont = V_GetFont(gifont.fontname); + mColor = V_FindFontColor(gifont.color); + mPatch = NULL; + } + if (mFont == NULL) + { + mFont = BigFont; } } - if (lumpname == NULL) +}; + + + +class FIntermissionScreen +{ +public: + // States for the intermission + enum EState { - // shouldn't happen! - background = NULL; - return; + NoState = -1, + StatCount, + ShowNextLoc, + LeavingIntermission + }; + + + enum EValues + { + // GLOBAL LOCATIONS + WI_TITLEY = 2, + + // SINGPLE-PLAYER STUFF + SP_STATSX = 50, + SP_STATSY = 50, + + SP_TIMEX = 8, + SP_TIMEY = (200 - 32), + + // NET GAME STUFF + NG_STATSY = 50, + }; + + + + // These animation variables, structures, etc. are used for the + // DOOM/Ultimate DOOM intermission screen animations. This is + // totally different from any sprite or texture/flat animations + enum EAnim + { + ANIM_ALWAYS, // determined by patch entry + ANIM_PIC, // continuous + + // condition bitflags + ANIM_IFVISITED = 8, + ANIM_IFNOTVISITED = 16, + ANIM_IFENTERING = 32, + ANIM_IFNOTENTERING = 64, + ANIM_IFLEAVING = 128, + ANIM_IFNOTLEAVING = 256, + ANIM_IFTRAVELLING = 512, + ANIM_IFNOTTRAVELLING = 1024, + + ANIM_TYPE = 7, + ANIM_CONDITION = ~7, + + }; + + // States for single-player + enum ESPState + { + SP_KILLS = 0, + SP_ITEMS = 2, + SP_SECRET = 4, + SP_FRAGS = 6, + SP_TIME = 8, + }; + + static const int SHOWNEXTLOCDELAY = 4; // in seconds + + struct yahpt_t + { + int x, y; + }; + + struct lnode_t + { + int x; // x/y coordinate pair structure + int y; + char level[9]; + }; + + + // + // Animation. + // There is another anim_t used in p_spec. + // (which is why I have renamed this one!) + // + + static const int MAX_ANIMATION_FRAMES = 20; + struct in_anim_t + { + int type; // Made an int so I can use '|' + int period; // period in tics between animations + int nanims; // number of animation frames + yahpt_t loc; // location of animation + int data; // ALWAYS: n/a, RANDOM: period deviation (<256) + FTexture * p[MAX_ANIMATION_FRAMES]; // actual graphics for frames of animations + + // following must be initialized to zero before use! + int nexttic; // next value of bcnt (used in conjunction with period) + int ctr; // next frame number to animate + int state; // used by RANDOM and LEVEL when animating + + char levelname[9]; + char levelname2[9]; + }; + + TArray lnodes; + TArray anims; + + int acceleratestage; // used to accelerate or skip a stage + bool playerready[MAXPLAYERS]; + int me; // wbs->pnum + EState state; // specifies current state + wbstartstruct_t *wbs; // contains information passed into intermission + wbplayerstruct_t*plrs; // wbs->plyr[] + int cnt; // used for general timing + int bcnt; // used for timing of background animation + int cnt_kills[MAXPLAYERS]; + int cnt_items[MAXPLAYERS]; + int cnt_secret[MAXPLAYERS]; + int cnt_frags[MAXPLAYERS]; + int cnt_deaths[MAXPLAYERS]; + int cnt_time; + int cnt_total_time; + int cnt_par; + int cnt_pause; + int total_frags; + int total_deaths; + bool noautostartmap; + int dofrags; + int ng_state; + + // + // GRAPHICS + // + + FPatchInfo mapname; + FPatchInfo finished; + FPatchInfo entering; + + TArray yah; // You Are Here graphic + FTexture* splat; // splat + FTexture* sp_secret; // "secret" + FTexture* kills; // "Kills", "Scrt", "Items", "Frags" + FTexture* secret; + FTexture* items; + FTexture* frags; + FTexture* timepic; // Time sucks. + FTexture* par; + FTexture* sucks; + FTexture* killers; // "killers", "victims" + FTexture* victims; + FTexture* total; // "Total", your face, your dead face + FTexture* p; // Player graphic + FTexture* lnames[2]; // Name graphics of each level (centered) + + // [RH] Info to dynamically generate the level name graphics + FString lnametexts[2]; + + FTexture *background; + + bool snl_pointeron = false; + + int player_deaths[MAXPLAYERS]; + int sp_state; + + // + // CODE + // + + + //==================================================================== + // + // Loads the background - either from a single texture + // or an intermission lump. + // Unfortunately the texture manager is incapable of recognizing text + // files so if you use a script you have to prefix its name by '$' in + // MAPINFO. + // + //==================================================================== + static bool IsExMy(const char * name) + { + // Only check for the first 3 episodes. They are the only ones with default intermission scripts. + // Level names can be upper- and lower case so use tolower to check! + return (tolower(name[0])=='e' && name[1]>='1' && name[1]<='3' && tolower(name[2])=='m'); } - lnodes.Clear(); - anims.Clear(); - yah.Clear(); - splat = NULL; + void WI_LoadBackground(bool isenterpic) + { + const char *lumpname = NULL; + char buffer[10]; + in_anim_t an; + lnode_t pt; + FTextureID texture; - // a name with a starting '$' indicates an intermission script - if (*lumpname!='$') - { - texture = TexMan.CheckForTexture(lumpname, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); - } - else - { - int lumpnum=Wads.CheckNumForFullName(lumpname+1, true); - if (lumpnum>=0) + bcnt=0; + + texture.SetInvalid(); + if (isenterpic) { - FScanner sc(lumpnum); - while (sc.GetString()) + level_info_t * li = FindLevelInfo(wbs->next); + if (li != NULL) lumpname = li->EnterPic; + } + else + { + lumpname = level.info->ExitPic; + } + + // Try to get a default if nothing specified + if (lumpname == NULL || lumpname[0]==0) + { + lumpname = NULL; + switch(gameinfo.gametype) { - memset(&an,0,sizeof(an)); - int caseval = sc.MustMatchString(WI_Cmd); - switch(caseval) + case GAME_Chex: + case GAME_Doom: + if (!(gameinfo.flags & GI_MAPxx)) { - case 0: // Background - sc.MustGetString(); - texture = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); - break; - - case 1: // Splat - sc.MustGetString(); - splat = TexMan[sc.String]; - break; - - case 2: // Pointers - while (sc.GetString() && !sc.Crossed) + const char *level = isenterpic ? wbs->next : wbs->current; + if (IsExMy(level)) { - yah.Push(TexMan[sc.String]); + mysnprintf(buffer, countof(buffer), "$IN_EPI%c", level[1]); + lumpname = buffer; } - if (sc.Crossed) - sc.UnGet(); - break; - - case 3: // Spots - sc.MustGetStringName("{"); - while (!sc.CheckString("}")) + } + if (!lumpname) + { + if (isenterpic) { - sc.MustGetString(); - strncpy(pt.level, sc.String,8); - pt.level[8] = 0; - sc.MustGetNumber(); - pt.x = sc.Number; - sc.MustGetNumber(); - pt.y = sc.Number; - lnodes.Push(pt); - } - break; + // One special case needs to be handled here! + // If going from E1-E3 to E4 the default should be used, not the exit pic. - case 4: // IfEntering - an.type = ANIM_IFENTERING; - goto readanimation; + // Not if the exit pic is user defined! + if (level.info->ExitPic.IsNotEmpty()) return; - case 5: // IfEntering - an.type = ANIM_IFNOTENTERING; - goto readanimation; - - case 6: // IfVisited - an.type = ANIM_IFVISITED; - goto readanimation; - - case 7: // IfNotVisited - an.type = ANIM_IFNOTVISITED; - goto readanimation; - - case 8: // IfLeaving - an.type = ANIM_IFLEAVING; - goto readanimation; - - case 9: // IfNotLeaving - an.type = ANIM_IFNOTLEAVING; - goto readanimation; - - case 10: // IfTravelling - an.type = ANIM_IFTRAVELLING; - sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; - goto readanimation; - - case 11: // IfNotTravelling - an.type = ANIM_IFTRAVELLING; - sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; - goto readanimation; - - case 14: // NoAutostartMap - noautostartmap = true; - break; - - readanimation: - sc.MustGetString(); - strncpy(an.levelname, sc.String, 8); - an.levelname[8] = 0; - sc.MustGetString(); - caseval=sc.MustMatchString(WI_Cmd); - - default: - switch (caseval) - { - case 12: // Animation - an.type |= ANIM_ALWAYS; - sc.MustGetNumber(); - an.loc.x = sc.Number; - sc.MustGetNumber(); - an.loc.y = sc.Number; - sc.MustGetNumber(); - an.period = sc.Number; - an.nexttic = 1 + (M_Random() % an.period); - if (sc.GetString()) + // E1-E3 need special treatment when playing Doom 1. + if (!(gameinfo.flags & GI_MAPxx)) { - if (sc.Compare("ONCE")) + // not if the last level is not from the first 3 episodes + if (!IsExMy(wbs->current)) return; + + // not if the next level is one of the first 3 episodes + if (IsExMy(wbs->next)) return; + } + } + lumpname = "INTERPIC"; + } + break; + + case GAME_Heretic: + if (isenterpic) + { + if (IsExMy(wbs->next)) + { + mysnprintf(buffer, countof(buffer), "$IN_HTC%c", wbs->next[1]); + lumpname = buffer; + } + } + if (!lumpname) + { + if (isenterpic) return; + lumpname = "FLOOR16"; + } + break; + + case GAME_Hexen: + if (isenterpic) return; + lumpname = "INTERPIC"; + break; + + case GAME_Strife: + default: + // Strife doesn't have an intermission pic so choose something neutral. + if (isenterpic) return; + lumpname = gameinfo.BorderFlat; + break; + } + } + if (lumpname == NULL) + { + // shouldn't happen! + background = NULL; + return; + } + + lnodes.Clear(); + anims.Clear(); + yah.Clear(); + splat = NULL; + + // a name with a starting '$' indicates an intermission script + if (*lumpname!='$') + { + texture = TexMan.CheckForTexture(lumpname, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); + } + else + { + int lumpnum=Wads.CheckNumForFullName(lumpname+1, true); + if (lumpnum>=0) + { + FScanner sc(lumpnum); + while (sc.GetString()) + { + memset(&an,0,sizeof(an)); + int caseval = sc.MustMatchString(WI_Cmd); + switch(caseval) + { + case 0: // Background + sc.MustGetString(); + texture = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch, FTextureManager::TEXMAN_TryAny); + break; + + case 1: // Splat + sc.MustGetString(); + splat = TexMan[sc.String]; + break; + + case 2: // Pointers + while (sc.GetString() && !sc.Crossed) + { + yah.Push(TexMan[sc.String]); + } + if (sc.Crossed) + sc.UnGet(); + break; + + case 3: // Spots + sc.MustGetStringName("{"); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + strncpy(pt.level, sc.String,8); + pt.level[8] = 0; + sc.MustGetNumber(); + pt.x = sc.Number; + sc.MustGetNumber(); + pt.y = sc.Number; + lnodes.Push(pt); + } + break; + + case 4: // IfEntering + an.type = ANIM_IFENTERING; + goto readanimation; + + case 5: // IfEntering + an.type = ANIM_IFNOTENTERING; + goto readanimation; + + case 6: // IfVisited + an.type = ANIM_IFVISITED; + goto readanimation; + + case 7: // IfNotVisited + an.type = ANIM_IFNOTVISITED; + goto readanimation; + + case 8: // IfLeaving + an.type = ANIM_IFLEAVING; + goto readanimation; + + case 9: // IfNotLeaving + an.type = ANIM_IFNOTLEAVING; + goto readanimation; + + case 10: // IfTravelling + an.type = ANIM_IFTRAVELLING; + sc.MustGetString(); + strncpy(an.levelname2, sc.String, 8); + an.levelname2[8] = 0; + goto readanimation; + + case 11: // IfNotTravelling + an.type = ANIM_IFTRAVELLING; + sc.MustGetString(); + strncpy(an.levelname2, sc.String, 8); + an.levelname2[8] = 0; + goto readanimation; + + case 14: // NoAutostartMap + noautostartmap = true; + break; + + readanimation: + sc.MustGetString(); + strncpy(an.levelname, sc.String, 8); + an.levelname[8] = 0; + sc.MustGetString(); + caseval=sc.MustMatchString(WI_Cmd); + + default: + switch (caseval) + { + case 12: // Animation + an.type |= ANIM_ALWAYS; + sc.MustGetNumber(); + an.loc.x = sc.Number; + sc.MustGetNumber(); + an.loc.y = sc.Number; + sc.MustGetNumber(); + an.period = sc.Number; + an.nexttic = 1 + (M_Random() % an.period); + if (sc.GetString()) { - an.data = 1; + if (sc.Compare("ONCE")) + { + an.data = 1; + } + else + { + sc.UnGet(); + } + } + if (!sc.CheckString("{")) + { + sc.MustGetString(); + an.p[an.nanims++] = TexMan[sc.String]; } else { - sc.UnGet(); + while (!sc.CheckString("}")) + { + sc.MustGetString(); + if (an.nanimstype & ANIM_TYPE) - { - case ANIM_ALWAYS: - if (bcnt >= a->nexttic) + else { - if (++a->ctr >= a->nanims) + Printf("Intermission script %s not found!\n", lumpname+1); + texture = TexMan.GetTexture("INTERPIC", FTexture::TEX_MiscPatch); + } + } + background=TexMan[texture]; + } + + //==================================================================== + // + // made this more generic and configurable through a script + // Removed all the ugly special case handling for different game modes + // + //==================================================================== + + void WI_updateAnimatedBack() + { + unsigned int i; + + for(i=0;itype & ANIM_TYPE) + { + case ANIM_ALWAYS: + if (bcnt >= a->nexttic) { - if (a->data==0) a->ctr = 0; - else a->ctr--; + if (++a->ctr >= a->nanims) + { + if (a->data==0) a->ctr = 0; + else a->ctr--; + } + a->nexttic = bcnt + a->period; } - a->nexttic = bcnt + a->period; + break; + + case ANIM_PIC: + a->ctr = 0; + break; + } - break; - - case ANIM_PIC: - a->ctr = 0; - break; - } } -} -//==================================================================== -// -// Draws the background including all animations -// -//==================================================================== + //==================================================================== + // + // Draws the background including all animations + // + //==================================================================== -void WI_drawBackground() -{ - unsigned int i; - double animwidth=320; // For a flat fill or clear background scale animations to 320x200 - double animheight=200; - - if (background) + void WI_drawBackground() { - // background - if (background->UseType == FTexture::TEX_MiscPatch) + unsigned int i; + double animwidth=320; // For a flat fill or clear background scale animations to 320x200 + double animheight=200; + + if (background) { - // scale all animations below to fit the size of the base pic - // The base pic is always scaled to fit the screen so this allows - // placing the animations precisely where they belong on the base pic - animwidth = background->GetScaledWidthDouble(); - animheight = background->GetScaledHeightDouble(); - screen->FillBorder (NULL); - screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); + // background + if (background->UseType == FTexture::TEX_MiscPatch) + { + // scale all animations below to fit the size of the base pic + // The base pic is always scaled to fit the screen so this allows + // placing the animations precisely where they belong on the base pic + animwidth = background->GetScaledWidthDouble(); + animheight = background->GetScaledHeightDouble(); + screen->FillBorder (NULL); + screen->DrawTexture(background, 0, 0, DTA_Fullscreen, true, TAG_DONE); + } + else + { + screen->FlatFill(0, 0, SCREENWIDTH, SCREENHEIGHT, background); + } } else { - screen->FlatFill(0, 0, SCREENWIDTH, SCREENHEIGHT, background); + screen->Clear(0,0, SCREENWIDTH, SCREENHEIGHT, 0, 0); } - } - else - { - screen->Clear(0,0, SCREENWIDTH, SCREENHEIGHT, 0, 0); - } - for(i=0;itype & ANIM_CONDITION) + for(i=0;ilevelname); - if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; - break; + in_anim_t * a = &anims[i]; + level_info_t * li; - case ANIM_IFNOTVISITED: - li = FindLevelInfo(a->levelname); - if (li == NULL || (li->flags & LEVEL_VISITED)) continue; - break; + switch (a->type & ANIM_CONDITION) + { + case ANIM_IFVISITED: + li = FindLevelInfo(a->levelname); + if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; + break; - // StatCount means 'leaving' - everything else means 'entering'! - case ANIM_IFENTERING: - if (state == StatCount || strnicmp(a->levelname, wbs->next, 8)) continue; - break; + case ANIM_IFNOTVISITED: + li = FindLevelInfo(a->levelname); + if (li == NULL || (li->flags & LEVEL_VISITED)) continue; + break; - case ANIM_IFNOTENTERING: - if (state != StatCount && !strnicmp(a->levelname, wbs->next, 8)) continue; - break; + // StatCount means 'leaving' - everything else means 'entering'! + case ANIM_IFENTERING: + if (state == StatCount || strnicmp(a->levelname, wbs->next, 8)) continue; + break; - case ANIM_IFLEAVING: - if (state != StatCount || strnicmp(a->levelname, wbs->current, 8)) continue; - break; + case ANIM_IFNOTENTERING: + if (state != StatCount && !strnicmp(a->levelname, wbs->next, 8)) continue; + break; - case ANIM_IFNOTLEAVING: - if (state == StatCount && !strnicmp(a->levelname, wbs->current, 8)) continue; - break; + case ANIM_IFLEAVING: + if (state != StatCount || strnicmp(a->levelname, wbs->current, 8)) continue; + break; - case ANIM_IFTRAVELLING: - if (strnicmp(a->levelname2, wbs->current, 8) || strnicmp(a->levelname, wbs->next, 8)) continue; - break; + case ANIM_IFNOTLEAVING: + if (state == StatCount && !strnicmp(a->levelname, wbs->current, 8)) continue; + break; - case ANIM_IFNOTTRAVELLING: - if (!strnicmp(a->levelname2, wbs->current, 8) && !strnicmp(a->levelname, wbs->next, 8)) continue; - break; + case ANIM_IFTRAVELLING: + if (strnicmp(a->levelname2, wbs->current, 8) || strnicmp(a->levelname, wbs->next, 8)) continue; + break; + + case ANIM_IFNOTTRAVELLING: + if (!strnicmp(a->levelname2, wbs->current, 8) && !strnicmp(a->levelname, wbs->next, 8)) continue; + break; + } + if (a->ctr >= 0) + screen->DrawTexture(a->p[a->ctr], a->loc.x, a->loc.y, + DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); } - if (a->ctr >= 0) - screen->DrawTexture(a->p[a->ctr], a->loc.x, a->loc.y, - DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); } -} -//==================================================================== -// -// Draws a single character with a shadow -// -//==================================================================== + //==================================================================== + // + // Draws a single character with a shadow + // + //==================================================================== -static int WI_DrawCharPatch (FFont *font, int charcode, int x, int y, EColorRange translation=CR_UNTRANSLATED, bool nomove=false) -{ - int width; - font->GetChar(charcode, &width); - screen->DrawChar(font, translation, x, y, charcode, - nomove ? DTA_CleanNoMove : DTA_Clean, true, - DTA_ShadowAlpha, (gameinfo.gametype & GAME_DoomChex) ? 0 : 0.5, - TAG_DONE); - return x - width; -} - -//==================================================================== -// -// CheckRealHeight -// -// Checks the posts in a texture and returns the lowest row (plus one) -// of the texture that is actually used. -// -//==================================================================== - -int CheckRealHeight(FTexture *tex) -{ - const FTexture::Span *span; - int maxy = 0, miny = tex->GetHeight(); - - for (int i = 0; i < tex->GetWidth(); ++i) + int WI_DrawCharPatch (FFont *font, int charcode, int x, int y, EColorRange translation=CR_UNTRANSLATED, bool nomove=false) { - tex->GetColumn(i, &span); - while (span->Length != 0) + int width; + font->GetChar(charcode, &width); + screen->DrawChar(font, translation, x, y, charcode, + nomove ? DTA_CleanNoMove : DTA_Clean, true, + DTA_ShadowAlpha, (gameinfo.gametype & GAME_DoomChex) ? 0 : 0.5, + TAG_DONE); + return x - width; + } + + //==================================================================== + // + // CheckRealHeight + // + // Checks the posts in a texture and returns the lowest row (plus one) + // of the texture that is actually used. + // + //==================================================================== + + int CheckRealHeight(FTexture *tex) + { + const FTexture::Span *span; + int maxy = 0, miny = tex->GetHeight(); + + for (int i = 0; i < tex->GetWidth(); ++i) { - if (span->TopOffset < miny) + tex->GetColumn(i, &span); + while (span->Length != 0) { - miny = span->TopOffset; + if (span->TopOffset < miny) + { + miny = span->TopOffset; + } + if (span->TopOffset + span->Length > maxy) + { + maxy = span->TopOffset + span->Length; + } + span++; } - if (span->TopOffset + span->Length > maxy) - { - maxy = span->TopOffset + span->Length; - } - span++; } + // Scale maxy before returning it + maxy = int((maxy *2) / tex->Scale.Y); + maxy = (maxy >> 1) + (maxy & 1); + return maxy; } - // Scale maxy before returning it - maxy = int((maxy *2) / tex->Scale.Y); - maxy = (maxy >> 1) + (maxy & 1); - return maxy; -} -//==================================================================== -// -// Draws a level name with the big font -// -// x is no longer passed as a parameter because the text is now broken into several lines -// if it is too long -// -//==================================================================== + //==================================================================== + // + // Draws a level name with the big font + // + // x is no longer passed as a parameter because the text is now broken into several lines + // if it is too long + // + //==================================================================== -int WI_DrawName(int y, FTexture *tex, const char *levelname) -{ - // draw - if (tex) + int WI_DrawName(int y, FTexture *tex, const char *levelname) { - screen->DrawTexture(tex, (screen->GetWidth() - tex->GetScaledWidth()*CleanXfac) /2, y, DTA_CleanNoMove, true, TAG_DONE); - int h = tex->GetScaledHeight(); - if (h > 50) - { // Fix for Deus Vult II and similar wads that decide to make these hugely tall - // patches with vast amounts of empty space at the bottom. - h = CheckRealHeight(tex); + // draw + if (tex) + { + screen->DrawTexture(tex, (screen->GetWidth() - tex->GetScaledWidth()*CleanXfac) /2, y, DTA_CleanNoMove, true, TAG_DONE); + int h = tex->GetScaledHeight(); + if (h > 50) + { // Fix for Deus Vult II and similar wads that decide to make these hugely tall + // patches with vast amounts of empty space at the bottom. + h = CheckRealHeight(tex); + } + return y + (h + BigFont->GetHeight()/4) * CleanYfac; + } + else + { + int i; + size_t l; + const char *p; + int h = 0; + int lumph; + + lumph = mapname.mFont->GetHeight() * CleanYfac; + + p = levelname; + if (!p) return 0; + l = strlen(p); + if (!l) return 0; + + FBrokenLines *lines = V_BreakLines(mapname.mFont, screen->GetWidth() / CleanXfac, p); + + if (lines) + { + for (i = 0; lines[i].Width >= 0; i++) + { + screen->DrawText(mapname.mFont, mapname.mColor, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h, + lines[i].Text, DTA_CleanNoMove, true, TAG_DONE); + h += lumph; + } + V_FreeBrokenLines(lines); + } + return y + h + lumph/4; } - return y + (h + BigFont->GetHeight()/4) * CleanYfac; } - else + + //==================================================================== + // + // Draws a text, either as patch or as string from the string table + // + //==================================================================== + + int WI_DrawPatchText(int y, FPatchInfo *pinfo, const char *stringname) + { + const char *string = GStrings(stringname); + int midx = screen->GetWidth() / 2; + + if (pinfo->mPatch != NULL) + { + screen->DrawTexture(pinfo->mPatch, midx - pinfo->mPatch->GetScaledWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE); + return y + (pinfo->mPatch->GetScaledHeight() * CleanYfac); + } + else + { + screen->DrawText(pinfo->mFont, pinfo->mColor, midx - pinfo->mFont->StringWidth(string)*CleanXfac/2, + y, string, DTA_CleanNoMove, true, TAG_DONE); + return y + pinfo->mFont->GetHeight() * CleanYfac; + } + } + + + //==================================================================== + // + // Draws " Finished!" + // + // Either uses the specified patch or the big font + // A level name patch can be specified for all games now, not just Doom. + // + //==================================================================== + + int WI_drawLF () + { + int y = WI_TITLEY * CleanYfac; + + y = WI_DrawName(y, wbs->LName0, lnametexts[0]); + + // Adjustment for different font sizes for map name and 'finished'. + y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4; + + // draw "Finished!" + if (y < (NG_STATSY - finished.mFont->GetHeight()*3/4) * CleanYfac) + { + // don't draw 'finished' if the level name is too tall + y = WI_DrawPatchText(y, &finished, "WI_FINISHED"); + } + return y; + } + + + //==================================================================== + // + // Draws "Entering " + // + // Either uses the specified patch or the big font + // A level name patch can be specified for all games now, not just Doom. + // + //==================================================================== + + void WI_drawEL () + { + int y = WI_TITLEY * CleanYfac; + + y = WI_DrawPatchText(y, &entering, "WI_ENTERING"); + y += entering.mFont->GetHeight() * CleanYfac / 4; + WI_DrawName(y, wbs->LName1, lnametexts[1]); + } + + + //==================================================================== + // + // Draws the splats and the 'You are here' arrows + // + //==================================================================== + + int WI_MapToIndex (const char *map) + { + unsigned int i; + + for (i = 0; i < lnodes.Size(); i++) + { + if (!strnicmp (lnodes[i].level, map, 8)) + break; + } + return i; + } + + + //==================================================================== + // + // Draws the splats and the 'You are here' arrows + // + //==================================================================== + + void WI_drawOnLnode( int n, FTexture * c[] ,int numc) + { + int i; + for(i=0;iGetScaledWidth(); + bottom = c[i]->GetScaledHeight(); + left = lnodes[n].x - c[i]->GetScaledLeftOffset(); + top = lnodes[n].y - c[i]->GetScaledTopOffset(); + right += left; + bottom += top; + + if (left >= 0 && right < 320 && top >= 0 && bottom < 200) + { + screen->DrawTexture (c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE); + break; + } + } + } + + //==================================================================== + // + // Draws a number. + // If digits > 0, then use that many digits minimum, + // otherwise only use as many as necessary. + // x is the right edge of the number. + // Returns new x position, that is, the left edge of the number. + // + //==================================================================== + int WI_drawNum (FFont *font, int x, int y, int n, int digits, bool leadingzeros=true, EColorRange translation=CR_UNTRANSLATED) + { + int fontwidth = font->GetCharWidth('3'); + char text[8]; + int len; + char *text_p; + bool nomove = font != IntermissionFont; + + if (nomove) + { + fontwidth *= CleanXfac; + } + if (leadingzeros) + { + len = mysnprintf (text, countof(text), "%0*d", digits, n); + } + else + { + len = mysnprintf (text, countof(text), "%d", n); + } + text_p = text + MIN(len, countof(text)-1); + + while (--text_p >= text) + { + // Digits are centered in a box the width of the '3' character. + // Other characters (specifically, '-') are right-aligned in their cell. + if (*text_p >= '0' && *text_p <= '9') + { + x -= fontwidth; + WI_DrawCharPatch(font, *text_p, x + (fontwidth - font->GetCharWidth(*text_p)) / 2, y, translation, nomove); + } + else + { + WI_DrawCharPatch(font, *text_p, x - font->GetCharWidth(*text_p), y, translation, nomove); + x -= fontwidth; + } + } + if (len < digits) + { + x -= fontwidth * (digits - len); + } + return x; + } + + //==================================================================== + // + // + // + //==================================================================== + + void WI_drawPercent (FFont *font, int x, int y, int p, int b, bool show_total=true, EColorRange color=CR_UNTRANSLATED) + { + if (p < 0) + return; + + if (wi_percents) + { + if (font != IntermissionFont) + { + x -= font->GetCharWidth('%') * CleanXfac; + } + else + { + x -= font->GetCharWidth('%'); + } + screen->DrawText(font, color, x, y, "%", font != IntermissionFont ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE); + if (font != IntermissionFont) + { + x -= 2*CleanXfac; + } + WI_drawNum(font, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color); + } + else + { + if (show_total) + { + x = WI_drawNum(font, x, y, b, 2, false); + x -= font->GetCharWidth('/'); + screen->DrawText (IntermissionFont, color, x, y, "/", + DTA_Clean, true, TAG_DONE); + } + WI_drawNum (font, x, y, p, -1, false, color); + } + } + + //==================================================================== + // + // Display level completion time and par, or "sucks" message if overflow. + // + //==================================================================== + void WI_drawTime (int x, int y, int t, bool no_sucks=false) + { + bool sucky; + + if (t<0) + return; + + sucky = !no_sucks && t >= wbs->sucktime * 60 * 60 && wbs->sucktime > 0; + + if (sucky) + { // "sucks" + if (sucks != NULL) + { + screen->DrawTexture (sucks, x - sucks->GetScaledWidth(), y - IntermissionFont->GetHeight() - 2, + DTA_Clean, true, TAG_DONE); + } + else + { + screen->DrawText (BigFont, CR_UNTRANSLATED, x - BigFont->StringWidth("SUCKS"), y - IntermissionFont->GetHeight() - 2, + "SUCKS", DTA_Clean, true, TAG_DONE); + } + } + + int hours = t / 3600; + t -= hours * 3600; + int minutes = t / 60; + t -= minutes * 60; + int seconds = t; + + // Why were these offsets hard coded? Half the WADs with custom patches + // I tested screwed up miserably in this function! + int num_spacing = IntermissionFont->GetCharWidth('3'); + int colon_spacing = IntermissionFont->GetCharWidth(':'); + + x = WI_drawNum (IntermissionFont, x, y, seconds, 2) - 1; + WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); + x = WI_drawNum (IntermissionFont, x, y, minutes, 2, hours!=0); + if (hours) + { + WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); + WI_drawNum (IntermissionFont, x, y, hours, 2); + } + } + + void WI_End () + { + state = LeavingIntermission; + WI_unloadData (); + + //Added by mc + if (deathmatch) + { + bglobal.RemoveAllBots (consoleplayer != Net_Arbitrator); + } + } + + bool WI_autoSkip() + { + return wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE); + } + + void WI_initNoState () + { + state = NoState; + acceleratestage = 0; + cnt = 10; + } + + void WI_updateNoState () + { + WI_updateAnimatedBack(); + + if (acceleratestage) + { + cnt = 0; + } + else + { + bool noauto = noautostartmap; + bool autoskip = WI_autoSkip(); + + for (int i = 0; !noauto && i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + noauto |= players[i].userinfo.GetNoAutostartMap(); + } + } + if (!noauto || autoskip) + { + cnt--; + } + } + + if (cnt == 0) + { + WI_End(); + G_WorldDone(); + } + } + + + void WI_initShowNextLoc () + { + if (wbs->next_ep == -1) + { + // Last map in episode - there is no next location! + WI_End(); + G_WorldDone(); + return; + } + + state = ShowNextLoc; + acceleratestage = 0; + cnt = SHOWNEXTLOCDELAY * TICRATE; + WI_LoadBackground(true); + } + + void WI_updateShowNextLoc () + { + WI_updateAnimatedBack(); + + if (!--cnt || acceleratestage) + WI_initNoState(); + else + snl_pointeron = (cnt & 31) < 20; + } + + void WI_drawShowNextLoc(void) + { + unsigned int i; + + WI_drawBackground(); + + if (splat) + { + for (i=0 ; iflags & LEVEL_VISITED) WI_drawOnLnode(i, &splat,1); // draw a splat on taken cities. + } + } + + // draw flashing ptr + if (snl_pointeron && yah.Size()) + { + unsigned int v = WI_MapToIndex (wbs->next); + // Draw only if it points to a valid level on the current screen! + if (vGetHeight() * CleanYfac; - - p = levelname; - if (!p) return 0; - l = strlen(p); - if (!l) return 0; - - FBrokenLines *lines = V_BreakLines(mapname.mFont, screen->GetWidth() / CleanXfac, p); - - if (lines) - { - for (i = 0; lines[i].Width >= 0; i++) - { - screen->DrawText(mapname.mFont, mapname.mColor, (SCREENWIDTH - lines[i].Width * CleanXfac) / 2, y + h, - lines[i].Text, DTA_CleanNoMove, true, TAG_DONE); - h += lumph; - } - V_FreeBrokenLines(lines); - } - return y + h + lumph/4; - } -} - -//==================================================================== -// -// Draws a text, either as patch or as string from the string table -// -//==================================================================== - -int WI_DrawPatchText(int y, FPatchInfo *pinfo, const char *stringname) -{ - const char *string = GStrings(stringname); - int midx = screen->GetWidth() / 2; - - if (pinfo->mPatch != NULL) - { - screen->DrawTexture(pinfo->mPatch, midx - pinfo->mPatch->GetScaledWidth()*CleanXfac/2, y, DTA_CleanNoMove, true, TAG_DONE); - return y + (pinfo->mPatch->GetScaledHeight() * CleanYfac); - } - else - { - screen->DrawText(pinfo->mFont, pinfo->mColor, midx - pinfo->mFont->StringWidth(string)*CleanXfac/2, - y, string, DTA_CleanNoMove, true, TAG_DONE); - return y + pinfo->mFont->GetHeight() * CleanYfac; - } -} - - -//==================================================================== -// -// Draws " Finished!" -// -// Either uses the specified patch or the big font -// A level name patch can be specified for all games now, not just Doom. -// -//==================================================================== - -int WI_drawLF () -{ - int y = WI_TITLEY * CleanYfac; - - y = WI_DrawName(y, wbs->LName0, lnametexts[0]); + int frags = 0; - // Adjustment for different font sizes for map name and 'finished'. - y -= ((mapname.mFont->GetHeight() - finished.mFont->GetHeight()) * CleanYfac) / 4; - - // draw "Finished!" - if (y < (NG_STATSY - finished.mFont->GetHeight()*3/4) * CleanYfac) - { - // don't draw 'finished' if the level name is too tall - y = WI_DrawPatchText(y, &finished, "WI_FINISHED"); - } - return y; -} - - -//==================================================================== -// -// Draws "Entering " -// -// Either uses the specified patch or the big font -// A level name patch can be specified for all games now, not just Doom. -// -//==================================================================== - -void WI_drawEL () -{ - int y = WI_TITLEY * CleanYfac; - - y = WI_DrawPatchText(y, &entering, "WI_ENTERING"); - y += entering.mFont->GetHeight() * CleanYfac / 4; - WI_DrawName(y, wbs->LName1, lnametexts[1]); -} - - -//==================================================================== -// -// Draws the splats and the 'You are here' arrows -// -//==================================================================== - -int WI_MapToIndex (const char *map) -{ - unsigned int i; - - for (i = 0; i < lnodes.Size(); i++) - { - if (!strnicmp (lnodes[i].level, map, 8)) - break; - } - return i; -} - - -//==================================================================== -// -// Draws the splats and the 'You are here' arrows -// -//==================================================================== - -void WI_drawOnLnode( int n, FTexture * c[] ,int numc) -{ - int i; - for(i=0;iGetScaledWidth(); - bottom = c[i]->GetScaledHeight(); - left = lnodes[n].x - c[i]->GetScaledLeftOffset(); - top = lnodes[n].y - c[i]->GetScaledTopOffset(); - right += left; - bottom += top; + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] + && i!=playernum) + { + frags += plrs[playernum].frags[i]; + } + } - if (left >= 0 && right < 320 && top >= 0 && bottom < 200) - { - screen->DrawTexture (c[i], lnodes[n].x, lnodes[n].y, DTA_320x200, true, TAG_DONE); - break; - } - } -} + // JDC hack - negative frags. + frags -= plrs[playernum].frags[playernum]; -//==================================================================== -// -// Draws a number. -// If digits > 0, then use that many digits minimum, -// otherwise only use as many as necessary. -// x is the right edge of the number. -// Returns new x position, that is, the left edge of the number. -// -//==================================================================== -int WI_drawNum (FFont *font, int x, int y, int n, int digits, bool leadingzeros=true, EColorRange translation=CR_UNTRANSLATED) -{ - int fontwidth = font->GetCharWidth('3'); - char text[8]; - int len; - char *text_p; - bool nomove = font != IntermissionFont; - - if (nomove) - { - fontwidth *= CleanXfac; - } - if (leadingzeros) - { - len = mysnprintf (text, countof(text), "%0*d", digits, n); - } - else - { - len = mysnprintf (text, countof(text), "%d", n); - } - text_p = text + MIN(len, countof(text)-1); - - while (--text_p >= text) - { - // Digits are centered in a box the width of the '3' character. - // Other characters (specifically, '-') are right-aligned in their cell. - if (*text_p >= '0' && *text_p <= '9') - { - x -= fontwidth; - WI_DrawCharPatch(font, *text_p, x + (fontwidth - font->GetCharWidth(*text_p)) / 2, y, translation, nomove); - } - else - { - WI_DrawCharPatch(font, *text_p, x - font->GetCharWidth(*text_p), y, translation, nomove); - x -= fontwidth; - } - } - if (len < digits) - { - x -= fontwidth * (digits - len); - } - return x; -} - -//==================================================================== -// -// -// -//==================================================================== - -void WI_drawPercent (FFont *font, int x, int y, int p, int b, bool show_total=true, EColorRange color=CR_UNTRANSLATED) -{ - if (p < 0) - return; - - if (wi_percents) - { - if (font != IntermissionFont) - { - x -= font->GetCharWidth('%') * CleanXfac; - } - else - { - x -= font->GetCharWidth('%'); - } - screen->DrawText(font, color, x, y, "%", font != IntermissionFont ? DTA_CleanNoMove : DTA_Clean, true, TAG_DONE); - if (font != IntermissionFont) - { - x -= 2*CleanXfac; - } - WI_drawNum(font, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color); - } - else - { - if (show_total) - { - x = WI_drawNum(font, x, y, b, 2, false); - x -= font->GetCharWidth('/'); - screen->DrawText (IntermissionFont, color, x, y, "/", - DTA_Clean, true, TAG_DONE); - } - WI_drawNum (font, x, y, p, -1, false, color); - } -} - -//==================================================================== -// -// Display level completion time and par, or "sucks" message if overflow. -// -//==================================================================== -void WI_drawTime (int x, int y, int t, bool no_sucks=false) -{ - bool sucky; - - if (t<0) - return; - - sucky = !no_sucks && t >= wbs->sucktime * 60 * 60 && wbs->sucktime > 0; - - if (sucky) - { // "sucks" - if (sucks != NULL) - { - screen->DrawTexture (sucks, x - sucks->GetScaledWidth(), y - IntermissionFont->GetHeight() - 2, - DTA_Clean, true, TAG_DONE); - } - else - { - screen->DrawText (BigFont, CR_UNTRANSLATED, x - BigFont->StringWidth("SUCKS"), y - IntermissionFont->GetHeight() - 2, - "SUCKS", DTA_Clean, true, TAG_DONE); - } + return frags; } - int hours = t / 3600; - t -= hours * 3600; - int minutes = t / 60; - t -= minutes * 60; - int seconds = t; - // Why were these offsets hard coded? Half the WADs with custom patches - // I tested screwed up miserably in this function! - int num_spacing = IntermissionFont->GetCharWidth('3'); - int colon_spacing = IntermissionFont->GetCharWidth(':'); - - x = WI_drawNum (IntermissionFont, x, y, seconds, 2) - 1; - WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); - x = WI_drawNum (IntermissionFont, x, y, minutes, 2, hours!=0); - if (hours) + void WI_initDeathmatchStats (void) { - WI_DrawCharPatch (IntermissionFont, ':', x -= colon_spacing, y); - WI_drawNum (IntermissionFont, x, y, hours, 2); - } -} + int i, j; -void WI_End () -{ - state = LeavingIntermission; - WI_unloadData (); + state = StatCount; + acceleratestage = 0; + memset(playerready, 0, sizeof(playerready)); + memset(cnt_frags, 0, sizeof(cnt_frags)); + memset(cnt_deaths, 0, sizeof(cnt_deaths)); + memset(player_deaths, 0, sizeof(player_deaths)); + total_frags = 0; + total_deaths = 0; - //Added by mc - if (deathmatch) - { - bglobal.RemoveAllBots (consoleplayer != Net_Arbitrator); - } -} + ng_state = 1; + cnt_pause = TICRATE; -bool WI_autoSkip() -{ - return wi_autoadvance > 0 && bcnt > (wi_autoadvance * TICRATE); -} - -void WI_initNoState () -{ - state = NoState; - acceleratestage = 0; - cnt = 10; -} - -void WI_updateNoState () -{ - WI_updateAnimatedBack(); - - if (acceleratestage) - { - cnt = 0; - } - else - { - bool noauto = noautostartmap; - bool autoskip = WI_autoSkip(); - - for (int i = 0; !noauto && i < MAXPLAYERS; ++i) + for (i=0 ; inext_ep == -1) - { - // Last map in episode - there is no next location! - WI_End(); - G_WorldDone(); - return; - } - - state = ShowNextLoc; - acceleratestage = 0; - cnt = SHOWNEXTLOCDELAY * TICRATE; - WI_LoadBackground(true); -} - -void WI_updateShowNextLoc () -{ - WI_updateAnimatedBack(); - - if (!--cnt || acceleratestage) - WI_initNoState(); - else - snl_pointeron = (cnt & 31) < 20; -} - -void WI_drawShowNextLoc(void) -{ - unsigned int i; - - WI_drawBackground(); - - if (splat) - { - for (i=0 ; iflags & LEVEL_VISITED) WI_drawOnLnode(i, &splat,1); // draw a splat on taken cities. - } - } - - // draw flashing ptr - if (snl_pointeron && yah.Size()) - { - unsigned int v = WI_MapToIndex (wbs->next); - // Draw only if it points to a valid level on the current screen! - if (v plrs[i].fragcount) cnt_frags[i] = plrs[i].fragcount; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 4) - { - if (!(bcnt & 3)) - S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i = 0; i player_deaths[i]) cnt_deaths[i] = player_deaths[i]; - else - stillticking = true; - } - if (!stillticking) - { + } S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; + ng_state = 6; + } + + if (ng_state == 2) + { + if (!(bcnt & 3)) + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i = 0; i plrs[i].fragcount) + cnt_frags[i] = plrs[i].fragcount; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 4) + { + if (!(bcnt & 3)) + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i = 0; i player_deaths[i]) + cnt_deaths[i] = player_deaths[i]; + else + stillticking = true; + } + if (!stillticking) + { + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 6) + { + int i; + for (i = 0; i < MAXPLAYERS; i++) + { + // If the player is in the game and not ready, stop checking + if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) + break; + } + + // All players are ready; proceed. + if ((i == MAXPLAYERS && acceleratestage) || autoskip) + { + S_Sound(CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE); + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } } } - else if (ng_state == 6) + + + + void WI_drawDeathmatchStats () { - int i; + int i, pnum, x, y, ypadding, height, lineheight; + int maxnamewidth, maxscorewidth, maxiconheight; + int pwidth = IntermissionFont->GetCharWidth('%'); + int icon_x, name_x, frags_x, deaths_x; + int deaths_len; + float h, s, v, r, g, b; + EColorRange color; + const char *text_deaths, *text_frags; + FTexture *readyico = TexMan.FindTexture("READYICO"); + player_t *sortedplayers[MAXPLAYERS]; + + // draw animated background + WI_drawBackground(); + + y = WI_drawLF(); + + HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); + // Use the readyico height if it's bigger. + height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); + maxiconheight = MAX(height, maxiconheight); + height = SmallFont->GetHeight() * CleanYfac; + lineheight = MAX(height, maxiconheight * CleanYfac); + ypadding = (lineheight - height + 1) / 2; + y += CleanYfac; + + text_deaths = GStrings("SCORE_DEATHS"); + //text_color = GStrings("SCORE_COLOR"); + text_frags = GStrings("SCORE_FRAGS"); + + icon_x = 8 * CleanXfac; + name_x = icon_x + maxscorewidth * CleanXfac; + frags_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_frags)) + 8) * CleanXfac; + deaths_x = frags_x + ((deaths_len = SmallFont->StringWidth(text_deaths)) + 8) * CleanXfac; + + x = (SCREENWIDTH - deaths_x) >> 1; + icon_x += x; + name_x += x; + frags_x += x; + deaths_x += x; + + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, frags_x - SmallFont->StringWidth(text_frags)*CleanXfac, y, text_frags, DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, deaths_x - deaths_len*CleanXfac, y, text_deaths, DTA_CleanNoMove, true, TAG_DONE); + y += height + 6 * CleanYfac; + + // Sort all players for (i = 0; i < MAXPLAYERS; i++) { - // If the player is in the game and not ready, stop checking - if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) - break; + sortedplayers[i] = &players[i]; } - // All players are ready; proceed. - if ((i == MAXPLAYERS && acceleratestage) || autoskip) - { - S_Sound(CHAN_VOICE | CHAN_UI, "intermission/pastdmstats", 1, ATTN_NONE); - WI_initShowNextLoc(); - } - } - else if (ng_state & 1) - { - if (!--cnt_pause) - { - ng_state++; - cnt_pause = TICRATE; - } - } -} + if (teamplay) + qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams); + else + qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints); - - -void WI_drawDeathmatchStats () -{ - int i, pnum, x, y, ypadding, height, lineheight; - int maxnamewidth, maxscorewidth, maxiconheight; - int pwidth = IntermissionFont->GetCharWidth('%'); - int icon_x, name_x, frags_x, deaths_x; - int deaths_len; - float h, s, v, r, g, b; - EColorRange color; - const char *text_deaths, *text_frags; - FTexture *readyico = TexMan.FindTexture("READYICO"); - player_t *sortedplayers[MAXPLAYERS]; - - // draw animated background - WI_drawBackground(); - - y = WI_drawLF(); - - HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); - // Use the readyico height if it's bigger. - height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); - maxiconheight = MAX(height, maxiconheight); - height = SmallFont->GetHeight() * CleanYfac; - lineheight = MAX(height, maxiconheight * CleanYfac); - ypadding = (lineheight - height + 1) / 2; - y += CleanYfac; - - text_deaths = GStrings("SCORE_DEATHS"); - //text_color = GStrings("SCORE_COLOR"); - text_frags = GStrings("SCORE_FRAGS"); - - icon_x = 8 * CleanXfac; - name_x = icon_x + maxscorewidth * CleanXfac; - frags_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_frags)) + 8) * CleanXfac; - deaths_x = frags_x + ((deaths_len = SmallFont->StringWidth(text_deaths)) + 8) * CleanXfac; - - x = (SCREENWIDTH - deaths_x) >> 1; - icon_x += x; - name_x += x; - frags_x += x; - deaths_x += x; - - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, frags_x - SmallFont->StringWidth(text_frags)*CleanXfac, y, text_frags, DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, deaths_x - deaths_len*CleanXfac, y, text_deaths, DTA_CleanNoMove, true, TAG_DONE); - y += height + 6 * CleanYfac; - - // Sort all players - for (i = 0; i < MAXPLAYERS; i++) - { - sortedplayers[i] = &players[i]; - } - - if (teamplay) - qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams); - else - qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints); - - // Draw lines for each player - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *player = sortedplayers[i]; - pnum = int(player - players); - - if (!playeringame[pnum]) - continue; - - D_GetPlayerColor(pnum, &h, &s, &v, NULL); - HSVtoRGB(&r, &g, &b, h, s, v); - - screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), - clamp(int(g*255.f), 0, 255), - clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (deaths_x - x) + (8 * CleanXfac), lineheight); - - if (playerready[pnum] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion - screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); - - color = (EColorRange)HU_GetRowColor(player, pnum == consoleplayer); - if (player->mo->ScoreIcon.isValid()) - { - FTexture *pic = TexMan[player->mo->ScoreIcon]; - screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); - } - screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); - WI_drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, color); - if (ng_state >= 2) - { - WI_drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, color); - } - y += lineheight + CleanYfac; - } - - // Draw "TOTAL" line - y += height + 3 * CleanYfac; - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); - WI_drawNum(SmallFont, frags_x, y, total_frags, 0, false, color); - if (ng_state >= 4) - { - WI_drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, color); - } - - // Draw game time - y += height + CleanYfac; - - int seconds = Tics2Seconds(plrs[me].stime); - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - seconds = seconds % 60; - - FString leveltime = GStrings("SCORE_LVLTIME"); - leveltime += ": "; - - char timer[sizeof "HH:MM:SS"]; - mysnprintf(timer, sizeof(timer), "%02i:%02i:%02i", hours, minutes, seconds); - leveltime += timer; - - screen->DrawText(SmallFont, color, x, y, leveltime, DTA_CleanNoMove, true, TAG_DONE); -} - -void WI_initNetgameStats () -{ - - int i; - - state = StatCount; - acceleratestage = 0; - memset(playerready, 0, sizeof(playerready)); - ng_state = 1; - - cnt_pause = TICRATE; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0; - - dofrags += WI_fragSum (i); - } - - dofrags = !!dofrags; -} - -void WI_updateNetgameStats () -{ - - int i; - int fsum; - bool stillticking; - bool autoskip = WI_autoSkip(); - - WI_updateAnimatedBack (); - - if ((acceleratestage || autoskip) && ng_state != 10) - { - acceleratestage = 0; - - for (i=0 ; i plrs[i].skills) - cnt_kills[i] = plrs[i].skills; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 4) - { - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i=0 ; i plrs[i].sitems) - cnt_items[i] = plrs[i].sitems; - else - stillticking = true; - } - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 6) - { - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i=0 ; i plrs[i].ssecret) - cnt_secret[i] = plrs[i].ssecret; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - ng_state += 1 + 2*!dofrags; - } - } - else if (ng_state == 8) - { - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - - stillticking = false; - - for (i=0 ; i= (fsum = WI_fragSum(i))) - cnt_frags[i] = fsum; - else - stillticking = true; - } - - if (!stillticking) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/cooptotal", 1, ATTN_NONE); - ng_state++; - } - } - else if (ng_state == 10) - { - int i; + // Draw lines for each player for (i = 0; i < MAXPLAYERS; i++) { - // If the player is in the game and not ready, stop checking - if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) - break; + player_t *player = sortedplayers[i]; + pnum = int(player - players); + + if (!playeringame[pnum]) + continue; + + D_GetPlayerColor(pnum, &h, &s, &v, NULL); + HSVtoRGB(&r, &g, &b, h, s, v); + + screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), + clamp(int(g*255.f), 0, 255), + clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (deaths_x - x) + (8 * CleanXfac), lineheight); + + if (playerready[pnum] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion + screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); + + color = (EColorRange)HU_GetRowColor(player, pnum == consoleplayer); + if (player->mo->ScoreIcon.isValid()) + { + FTexture *pic = TexMan[player->mo->ScoreIcon]; + screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); + } + screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); + WI_drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, color); + if (ng_state >= 2) + { + WI_drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, color); + } + y += lineheight + CleanYfac; } - // All players are ready; proceed. - if ((i == MAXPLAYERS && acceleratestage) || autoskip) - { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE); - WI_initShowNextLoc(); - } - } - else if (ng_state & 1) - { - if (!--cnt_pause) - { - ng_state++; - cnt_pause = TICRATE; - } - } -} - -void WI_drawNetgameStats () -{ - int i, x, y, ypadding, height, lineheight; - int maxnamewidth, maxscorewidth, maxiconheight; - int pwidth = IntermissionFont->GetCharWidth('%'); - int icon_x, name_x, kills_x, bonus_x, secret_x; - int bonus_len, secret_len; - int missed_kills, missed_items, missed_secrets; - float h, s, v, r, g, b; - EColorRange color; - const char *text_bonus, *text_secret, *text_kills; - FTexture *readyico = TexMan.FindTexture("READYICO"); - - // draw animated background - WI_drawBackground(); - - y = WI_drawLF(); - - HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); - // Use the readyico height if it's bigger. - height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); - if (height > maxiconheight) - { - maxiconheight = height; - } - height = SmallFont->GetHeight() * CleanYfac; - lineheight = MAX(height, maxiconheight * CleanYfac); - ypadding = (lineheight - height + 1) / 2; - y += CleanYfac; - - text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS"); - text_secret = GStrings("SCORE_SECRET"); - text_kills = GStrings("SCORE_KILLS"); - - icon_x = 8 * CleanXfac; - name_x = icon_x + maxscorewidth * CleanXfac; - kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac; - bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac; - secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac; - - x = (SCREENWIDTH - secret_x) >> 1; - icon_x += x; - name_x += x; - kills_x += x; - bonus_x += x; - secret_x += x; - - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE); - screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true, TAG_DONE); - y += height + 6 * CleanYfac; - - missed_kills = wbs->maxkills; - missed_items = wbs->maxitems; - missed_secrets = wbs->maxsecret; - - // Draw lines for each player - for (i = 0; i < MAXPLAYERS; ++i) - { - player_t *player; - - if (!playeringame[i]) - continue; - - player = &players[i]; - - D_GetPlayerColor(i, &h, &s, &v, NULL); - HSVtoRGB(&r, &g, &b, h, s, v); - - screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), - clamp(int(g*255.f), 0, 255), - clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (secret_x - x) + (8 * CleanXfac), lineheight); - - if (playerready[i] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion - screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); - - color = (EColorRange)HU_GetRowColor(player, i == consoleplayer); - if (player->mo->ScoreIcon.isValid()) - { - FTexture *pic = TexMan[player->mo->ScoreIcon]; - screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); - } - screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); - WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color); - missed_kills -= cnt_kills[i]; + // Draw "TOTAL" line + y += height + 3 * CleanYfac; + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); + WI_drawNum(SmallFont, frags_x, y, total_frags, 0, false, color); if (ng_state >= 4) { - WI_drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs->maxitems, false, color); - missed_items -= cnt_items[i]; - if (ng_state >= 6) + WI_drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, color); + } + + // Draw game time + y += height + CleanYfac; + + int seconds = Tics2Seconds(plrs[me].stime); + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + seconds = seconds % 60; + + FString leveltime = GStrings("SCORE_LVLTIME"); + leveltime += ": "; + + char timer[sizeof "HH:MM:SS"]; + mysnprintf(timer, sizeof(timer), "%02i:%02i:%02i", hours, minutes, seconds); + leveltime += timer; + + screen->DrawText(SmallFont, color, x, y, leveltime, DTA_CleanNoMove, true, TAG_DONE); + } + + void WI_initNetgameStats () + { + + int i; + + state = StatCount; + acceleratestage = 0; + memset(playerready, 0, sizeof(playerready)); + ng_state = 1; + + cnt_pause = TICRATE; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0; + + dofrags += WI_fragSum (i); + } + + dofrags = !!dofrags; + } + + void WI_updateNetgameStats () + { + + int i; + int fsum; + bool stillticking; + bool autoskip = WI_autoSkip(); + + WI_updateAnimatedBack (); + + if ((acceleratestage || autoskip) && ng_state != 10) + { + acceleratestage = 0; + + for (i=0 ; imaxsecret, false, color); - missed_secrets -= cnt_secret[i]; + if (!playeringame[i]) + continue; + + cnt_kills[i] = plrs[i].skills; + cnt_items[i] = plrs[i].sitems; + cnt_secret[i] = plrs[i].ssecret; + + if (dofrags) + cnt_frags[i] = WI_fragSum (i); + } + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state = 10; + } + + if (ng_state == 2) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i=0 ; i plrs[i].skills) + cnt_kills[i] = plrs[i].skills; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; } } - y += lineheight + CleanYfac; - } - - // Draw "MISSED" line - y += 3 * CleanYfac; - screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE); - WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY); - if (ng_state >= 4) - { - WI_drawPercent(SmallFont, bonus_x, y, missed_items, wbs->maxitems, false, CR_DARKGRAY); - if (ng_state >= 6) - { - WI_drawPercent(SmallFont, secret_x, y, missed_secrets, wbs->maxsecret, false, CR_DARKGRAY); - } - } - - // Draw "TOTAL" line - y += height + 3 * CleanYfac; - color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; - screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); - WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color); - if (ng_state >= 4) - { - WI_drawNum(SmallFont, bonus_x, y, wbs->maxitems, 0, false, color); - if (ng_state >= 6) - { - WI_drawNum(SmallFont, secret_x, y, wbs->maxsecret, 0, false, color); - } - } -} - -static int sp_state; - -void WI_initStats () -{ - state = StatCount; - acceleratestage = 0; - sp_state = 1; - cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1; - cnt_time = cnt_par = -1; - cnt_pause = TICRATE; - - cnt_total_time = -1; -} - -void WI_updateStats () -{ - WI_updateAnimatedBack (); - - if (acceleratestage && sp_state != 10) - { - acceleratestage = 0; - sp_state = 10; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - - cnt_kills[0] = plrs[me].skills; - cnt_items[0] = plrs[me].sitems; - cnt_secret[0] = plrs[me].ssecret; - cnt_time = Tics2Seconds(plrs[me].stime); - cnt_par = wbs->partime / TICRATE; - cnt_total_time = Tics2Seconds(wbs->totaltime); - } - - if (sp_state == 2) - { - if (gameinfo.intermissioncounter) - { - cnt_kills[0] += 2; - - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - } - if (!gameinfo.intermissioncounter || cnt_kills[0] >= plrs[me].skills) - { - cnt_kills[0] = plrs[me].skills; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - sp_state++; - } - } - else if (sp_state == 4) - { - if (gameinfo.intermissioncounter) - { - cnt_items[0] += 2; - - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - } - if (!gameinfo.intermissioncounter || cnt_items[0] >= plrs[me].sitems) - { - cnt_items[0] = plrs[me].sitems; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - sp_state++; - } - } - else if (sp_state == 6) - { - if (gameinfo.intermissioncounter) - { - cnt_secret[0] += 2; - - if (!(bcnt&3)) - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - } - if (!gameinfo.intermissioncounter || cnt_secret[0] >= plrs[me].ssecret) - { - cnt_secret[0] = plrs[me].ssecret; - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); - sp_state++; - } - } - else if (sp_state == 8) - { - if (gameinfo.intermissioncounter) + else if (ng_state == 4) { if (!(bcnt&3)) S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); - cnt_time += 3; - cnt_par += 3; - cnt_total_time += 3; - } + stillticking = false; - int sec = Tics2Seconds(plrs[me].stime); - if (!gameinfo.intermissioncounter || cnt_time >= sec) - cnt_time = sec; - - int tsec = Tics2Seconds(wbs->totaltime); - if (!gameinfo.intermissioncounter || cnt_total_time >= tsec) - cnt_total_time = tsec; - - if (!gameinfo.intermissioncounter || cnt_par >= wbs->partime / TICRATE) - { - cnt_par = wbs->partime / TICRATE; - - if (cnt_time >= sec) + for (i=0 ; i plrs[i].sitems) + cnt_items[i] = plrs[i].sitems; + else + stillticking = true; + } + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 6) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i=0 ; i plrs[i].ssecret) + cnt_secret[i] = plrs[i].ssecret; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + ng_state += 1 + 2*!dofrags; + } + } + else if (ng_state == 8) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + stillticking = false; + + for (i=0 ; i= (fsum = WI_fragSum(i))) + cnt_frags[i] = fsum; + else + stillticking = true; + } + + if (!stillticking) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/cooptotal", 1, ATTN_NONE); + ng_state++; + } + } + else if (ng_state == 10) + { + int i; + for (i = 0; i < MAXPLAYERS; i++) + { + // If the player is in the game and not ready, stop checking + if (playeringame[i] && players[i].Bot == NULL && !playerready[i]) + break; + } + + // All players are ready; proceed. + if ((i == MAXPLAYERS && acceleratestage) || autoskip) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/pastcoopstats", 1, ATTN_NONE); + WI_initShowNextLoc(); + } + } + else if (ng_state & 1) + { + if (!--cnt_pause) + { + ng_state++; + cnt_pause = TICRATE; + } + } + } + + void WI_drawNetgameStats () + { + int i, x, y, ypadding, height, lineheight; + int maxnamewidth, maxscorewidth, maxiconheight; + int pwidth = IntermissionFont->GetCharWidth('%'); + int icon_x, name_x, kills_x, bonus_x, secret_x; + int bonus_len, secret_len; + int missed_kills, missed_items, missed_secrets; + float h, s, v, r, g, b; + EColorRange color; + const char *text_bonus, *text_secret, *text_kills; + FTexture *readyico = TexMan.FindTexture("READYICO"); + + // draw animated background + WI_drawBackground(); + + y = WI_drawLF(); + + HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight); + // Use the readyico height if it's bigger. + height = readyico->GetScaledHeight() - readyico->GetScaledTopOffset(); + if (height > maxiconheight) + { + maxiconheight = height; + } + height = SmallFont->GetHeight() * CleanYfac; + lineheight = MAX(height, maxiconheight * CleanYfac); + ypadding = (lineheight - height + 1) / 2; + y += CleanYfac; + + text_bonus = GStrings((gameinfo.gametype & GAME_Raven) ? "SCORE_BONUS" : "SCORE_ITEMS"); + text_secret = GStrings("SCORE_SECRET"); + text_kills = GStrings("SCORE_KILLS"); + + icon_x = 8 * CleanXfac; + name_x = icon_x + maxscorewidth * CleanXfac; + kills_x = name_x + (maxnamewidth + MAX(SmallFont->StringWidth("XXXXX"), SmallFont->StringWidth(text_kills)) + 8) * CleanXfac; + bonus_x = kills_x + ((bonus_len = SmallFont->StringWidth(text_bonus)) + 8) * CleanXfac; + secret_x = bonus_x + ((secret_len = SmallFont->StringWidth(text_secret)) + 8) * CleanXfac; + + x = (SCREENWIDTH - secret_x) >> 1; + icon_x += x; + name_x += x; + kills_x += x; + bonus_x += x; + secret_x += x; + + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_NAME"), DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, kills_x - SmallFont->StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true, TAG_DONE); + screen->DrawText(SmallFont, color, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true, TAG_DONE); + y += height + 6 * CleanYfac; + + missed_kills = wbs->maxkills; + missed_items = wbs->maxitems; + missed_secrets = wbs->maxsecret; + + // Draw lines for each player + for (i = 0; i < MAXPLAYERS; ++i) + { + player_t *player; + + if (!playeringame[i]) + continue; + + player = &players[i]; + + D_GetPlayerColor(i, &h, &s, &v, NULL); + HSVtoRGB(&r, &g, &b, h, s, v); + + screen->Dim(MAKERGB(clamp(int(r*255.f), 0, 255), + clamp(int(g*255.f), 0, 255), + clamp(int(b*255.f), 0, 255)), 0.8f, x, y - ypadding, (secret_x - x) + (8 * CleanXfac), lineheight); + + if (playerready[i] || player->Bot != NULL) // Bots are automatically assumed ready, to prevent confusion + screen->DrawTexture(readyico, x - (readyico->GetWidth() * CleanXfac), y, DTA_CleanNoMove, true, TAG_DONE); + + color = (EColorRange)HU_GetRowColor(player, i == consoleplayer); + if (player->mo->ScoreIcon.isValid()) + { + FTexture *pic = TexMan[player->mo->ScoreIcon]; + screen->DrawTexture(pic, icon_x, y, DTA_CleanNoMove, true, TAG_DONE); + } + screen->DrawText(SmallFont, color, name_x, y + ypadding, player->userinfo.GetName(), DTA_CleanNoMove, true, TAG_DONE); + WI_drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs->maxkills, false, color); + missed_kills -= cnt_kills[i]; + if (ng_state >= 4) + { + WI_drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs->maxitems, false, color); + missed_items -= cnt_items[i]; + if (ng_state >= 6) + { + WI_drawPercent(SmallFont, secret_x, y + ypadding, cnt_secret[i], wbs->maxsecret, false, color); + missed_secrets -= cnt_secret[i]; + } + } + y += lineheight + CleanYfac; + } + + // Draw "MISSED" line + y += 3 * CleanYfac; + screen->DrawText(SmallFont, CR_DARKGRAY, name_x, y, GStrings("SCORE_MISSED"), DTA_CleanNoMove, true, TAG_DONE); + WI_drawPercent(SmallFont, kills_x, y, missed_kills, wbs->maxkills, false, CR_DARKGRAY); + if (ng_state >= 4) + { + WI_drawPercent(SmallFont, bonus_x, y, missed_items, wbs->maxitems, false, CR_DARKGRAY); + if (ng_state >= 6) + { + WI_drawPercent(SmallFont, secret_x, y, missed_secrets, wbs->maxsecret, false, CR_DARKGRAY); + } + } + + // Draw "TOTAL" line + y += height + 3 * CleanYfac; + color = (gameinfo.gametype & GAME_Raven) ? CR_GREEN : CR_UNTRANSLATED; + screen->DrawText(SmallFont, color, name_x, y, GStrings("SCORE_TOTAL"), DTA_CleanNoMove, true, TAG_DONE); + WI_drawNum(SmallFont, kills_x, y, wbs->maxkills, 0, false, color); + if (ng_state >= 4) + { + WI_drawNum(SmallFont, bonus_x, y, wbs->maxitems, 0, false, color); + if (ng_state >= 6) + { + WI_drawNum(SmallFont, secret_x, y, wbs->maxsecret, 0, false, color); + } + } + } + + + void WI_initStats () + { + state = StatCount; + acceleratestage = 0; + sp_state = 1; + cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1; + cnt_time = cnt_par = -1; + cnt_pause = TICRATE; + + cnt_total_time = -1; + } + + void WI_updateStats () + { + WI_updateAnimatedBack (); + + if (acceleratestage && sp_state != 10) + { + acceleratestage = 0; + sp_state = 10; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + + cnt_kills[0] = plrs[me].skills; + cnt_items[0] = plrs[me].sitems; + cnt_secret[0] = plrs[me].ssecret; + cnt_time = Tics2Seconds(plrs[me].stime); + cnt_par = wbs->partime / TICRATE; + cnt_total_time = Tics2Seconds(wbs->totaltime); + } + + if (sp_state == 2) + { + if (gameinfo.intermissioncounter) + { + cnt_kills[0] += 2; + + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + } + if (!gameinfo.intermissioncounter || cnt_kills[0] >= plrs[me].skills) + { + cnt_kills[0] = plrs[me].skills; S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); sp_state++; } } - } - else if (sp_state == 10) - { - if (acceleratestage) + else if (sp_state == 4) { - S_Sound (CHAN_VOICE | CHAN_UI, "intermission/paststats", 1, ATTN_NONE); - WI_initShowNextLoc(); + if (gameinfo.intermissioncounter) + { + cnt_items[0] += 2; + + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + } + if (!gameinfo.intermissioncounter || cnt_items[0] >= plrs[me].sitems) + { + cnt_items[0] = plrs[me].sitems; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + sp_state++; + } + } + else if (sp_state == 6) + { + if (gameinfo.intermissioncounter) + { + cnt_secret[0] += 2; + + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + } + if (!gameinfo.intermissioncounter || cnt_secret[0] >= plrs[me].ssecret) + { + cnt_secret[0] = plrs[me].ssecret; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + sp_state++; + } + } + else if (sp_state == 8) + { + if (gameinfo.intermissioncounter) + { + if (!(bcnt&3)) + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/tick", 1, ATTN_NONE); + + cnt_time += 3; + cnt_par += 3; + cnt_total_time += 3; + } + + int sec = Tics2Seconds(plrs[me].stime); + if (!gameinfo.intermissioncounter || cnt_time >= sec) + cnt_time = sec; + + int tsec = Tics2Seconds(wbs->totaltime); + if (!gameinfo.intermissioncounter || cnt_total_time >= tsec) + cnt_total_time = tsec; + + if (!gameinfo.intermissioncounter || cnt_par >= wbs->partime / TICRATE) + { + cnt_par = wbs->partime / TICRATE; + + if (cnt_time >= sec) + { + cnt_total_time = tsec; + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/nextstage", 1, ATTN_NONE); + sp_state++; + } + } + } + else if (sp_state == 10) + { + if (acceleratestage) + { + S_Sound (CHAN_VOICE | CHAN_UI, "intermission/paststats", 1, ATTN_NONE); + WI_initShowNextLoc(); + } + } + else if (sp_state & 1) + { + if (!--cnt_pause) + { + sp_state++; + cnt_pause = TICRATE; + } } } - else if (sp_state & 1) + + void WI_drawStats (void) { - if (!--cnt_pause) - { - sp_state++; - cnt_pause = TICRATE; - } - } -} + // line height + int lh; -void WI_drawStats (void) -{ - // line height - int lh; + lh = IntermissionFont->GetHeight() * 3 / 2; - lh = IntermissionFont->GetHeight() * 3 / 2; - - // draw animated background - WI_drawBackground(); + // draw animated background + WI_drawBackground(); - WI_drawLF(); + WI_drawLF(); - if (gameinfo.gametype & GAME_DoomChex) - { - screen->DrawTexture (kills, SP_STATSX, SP_STATSY, DTA_Clean, true, TAG_DONE); - WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY, cnt_kills[0], wbs->maxkills); - - screen->DrawTexture (items, SP_STATSX, SP_STATSY+lh, DTA_Clean, true, TAG_DONE); - WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+lh, cnt_items[0], wbs->maxitems); - - screen->DrawTexture (sp_secret, SP_STATSX, SP_STATSY+2*lh, DTA_Clean, true, TAG_DONE); - WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0], wbs->maxsecret); - - screen->DrawTexture (timepic, SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); - WI_drawTime (160 - SP_TIMEX, SP_TIMEY, cnt_time); - if (wi_showtotaltime) + if (gameinfo.gametype & GAME_DoomChex) { - WI_drawTime (160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, true); // no 'sucks' for total time ever! - } + screen->DrawTexture (kills, SP_STATSX, SP_STATSY, DTA_Clean, true, TAG_DONE); + WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY, cnt_kills[0], wbs->maxkills); - if (wbs->partime) - { - screen->DrawTexture (par, 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); - WI_drawTime (320 - SP_TIMEX, SP_TIMEY, cnt_par); - } + screen->DrawTexture (items, SP_STATSX, SP_STATSY+lh, DTA_Clean, true, TAG_DONE); + WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+lh, cnt_items[0], wbs->maxitems); - } - else - { - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, GStrings("TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, GStrings("TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, GStrings("TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawTexture (sp_secret, SP_STATSX, SP_STATSY+2*lh, DTA_Clean, true, TAG_DONE); + WI_drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0], wbs->maxsecret); - int countpos = gameinfo.gametype==GAME_Strife? 285:270; - if (sp_state >= 2) - { - WI_drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs->maxkills); - } - if (sp_state >= 4) - { - WI_drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs->maxitems); - } - if (sp_state >= 6) - { - WI_drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs->maxsecret); - } - if (sp_state >= 8) - { - screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, GStrings("TXT_IMTIME"), - DTA_Clean, true, DTA_Shadow, true, TAG_DONE); - WI_drawTime (249, 160, cnt_time); + screen->DrawTexture (timepic, SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); + WI_drawTime (160 - SP_TIMEX, SP_TIMEY, cnt_time); if (wi_showtotaltime) { - WI_drawTime (249, 180, cnt_total_time); + WI_drawTime (160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, true); // no 'sucks' for total time ever! } - } - } -} -// ==================================================================== -// WI_checkForAccelerate -// Purpose: See if the player has hit either the attack or use key -// or mouse button. If so we set acceleratestage to 1 and -// all those display routines above jump right to the end. -// Args: none -// Returns: void -// -// ==================================================================== -void WI_checkForAccelerate(void) -{ - int i; - player_t *player; - - // check for button presses to skip delays - for (i = 0, player = players; i < MAXPLAYERS; i++, player++) - { - if (playeringame[i]) - { - if ((player->cmd.ucmd.buttons ^ player->oldbuttons) && - ((players[i].cmd.ucmd.buttons & players[i].oldbuttons) - == players[i].oldbuttons) && player->Bot == NULL) + if (wbs->partime) { - acceleratestage = 1; - playerready[i] = true; + screen->DrawTexture (par, 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true, TAG_DONE); + WI_drawTime (320 - SP_TIMEX, SP_TIMEY, cnt_par); } - player->oldbuttons = player->cmd.ucmd.buttons; + } - } -} - -// ==================================================================== -// WI_Ticker -// Purpose: Do various updates every gametic, for stats, animation, -// checking that intermission music is running, etc. -// Args: none -// Returns: void -// -// ==================================================================== -void WI_Ticker(void) -{ - // counter for general background animation - bcnt++; - - if (bcnt == 1) - { - // intermission music - use the defaults if none specified - if (level.info->InterMusic.IsNotEmpty()) - S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder); else - S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); - - } - - WI_checkForAccelerate(); - - switch (state) - { - case StatCount: - if (deathmatch) WI_updateDeathmatchStats(); - else if (multiplayer) WI_updateNetgameStats(); - else WI_updateStats(); - break; - - case ShowNextLoc: - WI_updateShowNextLoc(); - break; - - case NoState: - WI_updateNoState(); - break; - - case LeavingIntermission: - // Hush, GCC. - break; - } -} - - -void WI_loadData(void) -{ - entering.Init(gameinfo.mStatscreenEnteringFont); - finished.Init(gameinfo.mStatscreenFinishedFont); - mapname.Init(gameinfo.mStatscreenMapNameFont); - - if (gameinfo.gametype & GAME_DoomChex) - { - kills = TexMan["WIOSTK"]; // "kills" - secret = TexMan["WIOSTS"]; // "scrt" - sp_secret = TexMan["WISCRT2"]; // "secret" - items = TexMan["WIOSTI"]; // "items" - frags = TexMan["WIFRGS"]; // "frgs" - timepic = TexMan["WITIME"]; // "time" - sucks = TexMan["WISUCKS"]; // "sucks" - par = TexMan["WIPAR"]; // "par" - killers = TexMan["WIKILRS"]; // "killers" (vertical] - victims = TexMan["WIVCTMS"]; // "victims" (horiz] - total = TexMan["WIMSTT"]; // "total" -// star = TexMan["STFST01"]; // your face -// bstar = TexMan["STFDEAD0"]; // dead face - p = TexMan["STPBANY"]; - } -#if 0 - else if (gameinfo.gametype & GAME_Raven) - { - if (gameinfo.gametype == GAME_Heretic) { - star = TexMan["FACEA0"]; - bstar = TexMan["FACEB0"]; + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 65, GStrings("TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 90, GStrings("TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + screen->DrawText (BigFont, CR_UNTRANSLATED, 50, 115, GStrings("TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + + int countpos = gameinfo.gametype==GAME_Strife? 285:270; + if (sp_state >= 2) + { + WI_drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs->maxkills); + } + if (sp_state >= 4) + { + WI_drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs->maxitems); + } + if (sp_state >= 6) + { + WI_drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs->maxsecret); + } + if (sp_state >= 8) + { + screen->DrawText (BigFont, CR_UNTRANSLATED, 85, 160, GStrings("TXT_IMTIME"), + DTA_Clean, true, DTA_Shadow, true, TAG_DONE); + WI_drawTime (249, 160, cnt_time); + if (wi_showtotaltime) + { + WI_drawTime (249, 180, cnt_total_time); + } + } } - else + } + + // ==================================================================== + // WI_checkForAccelerate + // Purpose: See if the player has hit either the attack or use key + // or mouse button. If so we set acceleratestage to 1 and + // all those display routines above jump right to the end. + // Args: none + // Returns: void + // + // ==================================================================== + void WI_checkForAccelerate(void) + { + int i; + player_t *player; + + // check for button presses to skip delays + for (i = 0, player = players; i < MAXPLAYERS; i++, player++) + { + if (playeringame[i]) + { + if ((player->cmd.ucmd.buttons ^ player->oldbuttons) && + ((players[i].cmd.ucmd.buttons & players[i].oldbuttons) + == players[i].oldbuttons) && player->Bot == NULL) + { + acceleratestage = 1; + playerready[i] = true; + } + player->oldbuttons = player->cmd.ucmd.buttons; + } + } + } + + // ==================================================================== + // WI_Ticker + // Purpose: Do various updates every gametic, for stats, animation, + // checking that intermission music is running, etc. + // Args: none + // Returns: void + // + // ==================================================================== + void WI_Ticker(void) + { + // counter for general background animation + bcnt++; + + if (bcnt == 1) + { + // intermission music - use the defaults if none specified + if (level.info->InterMusic.IsNotEmpty()) + S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder); + else + S_ChangeMusic (gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder); + + } + + WI_checkForAccelerate(); + + switch (state) + { + case StatCount: + if (deathmatch) WI_updateDeathmatchStats(); + else if (multiplayer) WI_updateNetgameStats(); + else WI_updateStats(); + break; + + case ShowNextLoc: + WI_updateShowNextLoc(); + break; + + case NoState: + WI_updateNoState(); + break; + + case LeavingIntermission: + // Hush, GCC. + break; + } + } + + + void WI_loadData(void) + { + entering.Init(gameinfo.mStatscreenEnteringFont); + finished.Init(gameinfo.mStatscreenFinishedFont); + mapname.Init(gameinfo.mStatscreenMapNameFont); + + if (gameinfo.gametype & GAME_DoomChex) + { + kills = TexMan["WIOSTK"]; // "kills" + secret = TexMan["WIOSTS"]; // "scrt" + sp_secret = TexMan["WISCRT2"]; // "secret" + items = TexMan["WIOSTI"]; // "items" + frags = TexMan["WIFRGS"]; // "frgs" + timepic = TexMan["WITIME"]; // "time" + sucks = TexMan["WISUCKS"]; // "sucks" + par = TexMan["WIPAR"]; // "par" + killers = TexMan["WIKILRS"]; // "killers" (vertical] + victims = TexMan["WIVCTMS"]; // "victims" (horiz] + total = TexMan["WIMSTT"]; // "total" + // star = TexMan["STFST01"]; // your face + // bstar = TexMan["STFDEAD0"]; // dead face + p = TexMan["STPBANY"]; + } + #if 0 + else if (gameinfo.gametype & GAME_Raven) + { + if (gameinfo.gametype == GAME_Heretic) + { + star = TexMan["FACEA0"]; + bstar = TexMan["FACEB0"]; + } + else + { + star = BigFont->GetChar('*', NULL); + bstar = star; + } + } + else // Strife needs some handling, too! { star = BigFont->GetChar('*', NULL); bstar = star; } + #endif + + // Use the local level structure which can be overridden by hubs + lnametexts[0] = level.LevelName; + + level_info_t *li = FindLevelInfo(wbs->next); + if (li) lnametexts[1] = li->LookupLevelName(); + else lnametexts[1] = ""; + + WI_LoadBackground(false); } - else // Strife needs some handling, too! + + void WI_unloadData () { - star = BigFont->GetChar('*', NULL); - bstar = star; + // [RH] The texture data gets unloaded at pre-map time, so there's nothing to do here + return; } -#endif - // Use the local level structure which can be overridden by hubs - lnametexts[0] = level.LevelName; - - level_info_t *li = FindLevelInfo(wbs->next); - if (li) lnametexts[1] = li->LookupLevelName(); - else lnametexts[1] = ""; - - WI_LoadBackground(false); -} - -void WI_unloadData () -{ - // [RH] The texture data gets unloaded at pre-map time, so there's nothing to do here - return; -} - -void WI_Drawer (void) -{ - switch (state) + void WI_Drawer (void) { - case StatCount: + switch (state) + { + case StatCount: + if (deathmatch) + WI_drawDeathmatchStats(); + else if (multiplayer) + WI_drawNetgameStats(); + else + WI_drawStats(); + break; + + case ShowNextLoc: + WI_drawShowNextLoc(); + break; + + case LeavingIntermission: + break; + + default: + WI_drawNoState(); + break; + } + } + + + void WI_initVariables (wbstartstruct_t *wbstartstruct) + { + wbs = wbstartstruct; + acceleratestage = 0; + cnt = bcnt = 0; + me = wbs->pnum; + plrs = wbs->plyr; + } + + void WI_Start (wbstartstruct_t *wbstartstruct) + { + noautostartmap = false; + V_SetBlend (0,0,0,0); + WI_initVariables (wbstartstruct); + WI_loadData (); if (deathmatch) - WI_drawDeathmatchStats(); + WI_initDeathmatchStats(); else if (multiplayer) - WI_drawNetgameStats(); + WI_initNetgameStats(); else - WI_drawStats(); - break; - - case ShowNextLoc: - WI_drawShowNextLoc(); - break; - - case LeavingIntermission: - break; - - default: - WI_drawNoState(); - break; + WI_initStats(); + S_StopAllChannels (); + SN_StopAllSequences (); } -} +}; +static FIntermissionScreen WI_Screen; -void WI_initVariables (wbstartstruct_t *wbstartstruct) +void WI_Ticker() { - wbs = wbstartstruct; - acceleratestage = 0; - cnt = bcnt = 0; - me = wbs->pnum; - plrs = wbs->plyr; + WI_Screen.WI_Ticker(); } -void WI_Start (wbstartstruct_t *wbstartstruct) +// Called by main loop, +// draws the intermission directly into the screen buffer. +void WI_Drawer() { - noautostartmap = false; - V_SetBlend (0,0,0,0); - WI_initVariables (wbstartstruct); - WI_loadData (); - if (deathmatch) - WI_initDeathmatchStats(); - else if (multiplayer) - WI_initNetgameStats(); - else - WI_initStats(); - S_StopAllChannels (); - SN_StopAllSequences (); + WI_Screen.WI_Drawer(); +} + +// Setup for an intermission screen. +void WI_Start(wbstartstruct_t *wbstartstruct) +{ + WI_Screen.WI_Start(wbstartstruct); } diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index e9a89b0abc..0aba717cb1 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -290,6 +290,12 @@ struct CVar native native int ResetToDefault(); } +struct GIFont +{ + Name fontname; + Name color; +}; + struct GameInfoStruct native { // will be extended as needed. @@ -301,6 +307,9 @@ struct GameInfoStruct native native bool norandomplayerclass; native Array infoPages; native String mBackButton; + native GIFont mStatscreenMapNameFont; + native GIFont mStatscreenEnteringFont; + native GIFont mStatscreenFinishedFont; } class Object native From d295186378b4e96f19274b973710248b6160943e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 23 Feb 2017 00:16:14 +0100 Subject: [PATCH 8/8] - made all fields of in_anim_t script-safe (except for the texture pointer which will have to be replaced by a Texture ID. --- src/wi_stuff.cpp | 55 +++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index ebc022df8d..5bb1786655 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -198,23 +198,29 @@ public: // (which is why I have renamed this one!) // - static const int MAX_ANIMATION_FRAMES = 20; struct in_anim_t { int type; // Made an int so I can use '|' int period; // period in tics between animations - int nanims; // number of animation frames yahpt_t loc; // location of animation int data; // ALWAYS: n/a, RANDOM: period deviation (<256) - FTexture * p[MAX_ANIMATION_FRAMES]; // actual graphics for frames of animations + TArray frames; // actual graphics for frames of animations // following must be initialized to zero before use! int nexttic; // next value of bcnt (used in conjunction with period) int ctr; // next frame number to animate int state; // used by RANDOM and LEVEL when animating - char levelname[9]; - char levelname2[9]; + FString LevelName; + FString LevelName2; + + void Reset() + { + type = period = loc.x = loc.y = data = nexttic = ctr = state = 0; + LevelName = ""; + LevelName2 = ""; + frames.Clear(); + } }; TArray lnodes; @@ -414,7 +420,7 @@ public: FScanner sc(lumpnum); while (sc.GetString()) { - memset(&an,0,sizeof(an)); + an.Reset(); int caseval = sc.MustMatchString(WI_Cmd); switch(caseval) { @@ -479,15 +485,13 @@ public: case 10: // IfTravelling an.type = ANIM_IFTRAVELLING; sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; + an.LevelName2 = sc.String; goto readanimation; case 11: // IfNotTravelling an.type = ANIM_IFTRAVELLING; sc.MustGetString(); - strncpy(an.levelname2, sc.String, 8); - an.levelname2[8] = 0; + an.LevelName2 = sc.String; goto readanimation; case 14: // NoAutostartMap @@ -496,8 +500,7 @@ public: readanimation: sc.MustGetString(); - strncpy(an.levelname, sc.String, 8); - an.levelname[8] = 0; + an.LevelName = sc.String; sc.MustGetString(); caseval=sc.MustMatchString(WI_Cmd); @@ -527,15 +530,14 @@ public: if (!sc.CheckString("{")) { sc.MustGetString(); - an.p[an.nanims++] = TexMan[sc.String]; + an.frames.Push(TexMan[sc.String]); } else { while (!sc.CheckString("}")) { sc.MustGetString(); - if (an.nanims= a->nexttic) { - if (++a->ctr >= a->nanims) + if (++a->ctr >= (int)a->frames.Size()) { if (a->data==0) a->ctr = 0; else a->ctr--; @@ -647,42 +650,42 @@ public: switch (a->type & ANIM_CONDITION) { case ANIM_IFVISITED: - li = FindLevelInfo(a->levelname); + li = FindLevelInfo(a->LevelName); if (li == NULL || !(li->flags & LEVEL_VISITED)) continue; break; case ANIM_IFNOTVISITED: - li = FindLevelInfo(a->levelname); + li = FindLevelInfo(a->LevelName); if (li == NULL || (li->flags & LEVEL_VISITED)) continue; break; // StatCount means 'leaving' - everything else means 'entering'! case ANIM_IFENTERING: - if (state == StatCount || strnicmp(a->levelname, wbs->next, 8)) continue; + if (state == StatCount || strnicmp(a->LevelName, wbs->next, 8)) continue; break; case ANIM_IFNOTENTERING: - if (state != StatCount && !strnicmp(a->levelname, wbs->next, 8)) continue; + if (state != StatCount && !strnicmp(a->LevelName, wbs->next, 8)) continue; break; case ANIM_IFLEAVING: - if (state != StatCount || strnicmp(a->levelname, wbs->current, 8)) continue; + if (state != StatCount || strnicmp(a->LevelName, wbs->current, 8)) continue; break; case ANIM_IFNOTLEAVING: - if (state == StatCount && !strnicmp(a->levelname, wbs->current, 8)) continue; + if (state == StatCount && !strnicmp(a->LevelName, wbs->current, 8)) continue; break; case ANIM_IFTRAVELLING: - if (strnicmp(a->levelname2, wbs->current, 8) || strnicmp(a->levelname, wbs->next, 8)) continue; + if (strnicmp(a->LevelName2, wbs->current, 8) || strnicmp(a->LevelName, wbs->next, 8)) continue; break; case ANIM_IFNOTTRAVELLING: - if (!strnicmp(a->levelname2, wbs->current, 8) && !strnicmp(a->levelname, wbs->next, 8)) continue; + if (!strnicmp(a->LevelName2, wbs->current, 8) && !strnicmp(a->LevelName, wbs->next, 8)) continue; break; } if (a->ctr >= 0) - screen->DrawTexture(a->p[a->ctr], a->loc.x, a->loc.y, + screen->DrawTexture(a->frames[a->ctr], a->loc.x, a->loc.y, DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); } }