- status screen fully scriptified but not active yet.

This commit is contained in:
Christoph Oelckers 2017-03-18 19:34:03 +01:00
parent 9a10a0f136
commit a2f2be17ef
18 changed files with 1137 additions and 41 deletions

View File

@ -217,6 +217,18 @@ void D_GetPlayerColor (int player, float *h, float *s, float *v, FPlayerColorSet
}
}
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetDisplayColor)
{
float h, s, v, r, g, b;
PARAM_SELF_STRUCT_PROLOGUE(player_t);
D_GetPlayerColor(int(self-players), &h, &s, &v, NULL);
HSVtoRGB(&r, &g, &b, h, s, v);
int c = MAKERGB(clamp(int(r*255.f), 0, 255),
clamp(int(g*255.f), 0, 255),
clamp(int(b*255.f), 0, 255));
ACTION_RETURN_INT(c);
}
// Find out which teams are present. If there is only one,
// then another team should be chosen at random.
//

View File

@ -1893,6 +1893,30 @@ void FLevelLocals::AddScroller (int secnum)
}
}
//==========================================================================
//
//
//==========================================================================
void FLevelLocals::SetInterMusic(const char *nextmap)
{
auto mus = level.info->MapInterMusic.CheckKey(nextmap);
if (mus != nullptr)
S_ChangeMusic(mus->first, mus->second);
else if (level.info->InterMusic.IsNotEmpty())
S_ChangeMusic(level.info->InterMusic, level.info->intermusicorder);
else
S_ChangeMusic(gameinfo.intermissionMusic.GetChars(), gameinfo.intermissionOrder);
}
DEFINE_ACTION_FUNCTION(FLevelLocals, SetInterMusic)
{
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_STRING(map);
self->SetInterMusic(map);
return 0;
}
//==========================================================================
//
//

View File

@ -10,6 +10,7 @@ struct FLevelLocals
{
void Tick ();
void AddScroller (int secnum);
void FLevelLocals::SetInterMusic(const char *nextmap);
uint8_t md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded.
int time; // time in the hub

View File

@ -58,6 +58,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenMapNameFont)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenEnteringFont)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenFinishedFont)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gibfactor)
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, intermissioncounter)
const char *GameNames[17] =

View File

@ -119,6 +119,16 @@ int compareteams (const void *arg1, const void *arg2)
return diff;
}
/*
void HU_SortPlayers
{
if (teamplay)
qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), compareteams);
else
qsort(sortedplayers, MAXPLAYERS, sizeof(player_t *), comparepoints);
}
*/
bool SB_ForceActive = false;
// PRIVATE DATA DEFINITIONS ------------------------------------------------

View File

@ -3471,6 +3471,7 @@ DEFINE_FIELD_X(PlayerInfo, player_t, cmd)
DEFINE_FIELD_X(PlayerInfo, player_t, original_cmd)
DEFINE_FIELD_X(PlayerInfo, player_t, userinfo)
DEFINE_FIELD_X(PlayerInfo, player_t, weapons)
DEFINE_FIELD_NAMED_X(PlayerInfo, player_t, cmd.ucmd.buttons, buttons)
DEFINE_FIELD(FPlayerClass, Type)
DEFINE_FIELD(FPlayerClass, Flags)

View File

@ -59,6 +59,7 @@
#include "teaminfo.h"
#include "r_data/sprites.h"
#include "serializer.h"
#include "wi_stuff.h"
static TArray<FPropertyInfo*> properties;
static TArray<AFuncDesc> AFTable;
@ -874,6 +875,11 @@ void InitThingdef()
}
);
auto wbplayerstruct = NewNativeStruct("WBPlayerStruct", nullptr);
wbplayerstruct->Size = sizeof(wbplayerstruct_t);
wbplayerstruct->Align = alignof(wbplayerstruct_t);
// Argh. It sucks when bad hacks need to be supported. WP_NOCHANGE is just a bogus pointer but it used everywhere as a special flag.
// It cannot be defined as constant because constants can either be numbers or strings but nothing else, so the only 'solution'
// is to create a static variable from it and reference that in the script. Yuck!!!

View File

@ -1236,6 +1236,24 @@ DEFINE_ACTION_FUNCTION(_TexMan, GetScaledSize)
//
//==========================================================================
DEFINE_ACTION_FUNCTION(_TexMan, GetScaledOffset)
{
PARAM_PROLOGUE;
PARAM_INT(texid);
auto tex = TexMan.ByIndex(texid);
if (tex != nullptr)
{
ACTION_RETURN_VEC2(DVector2(tex->GetScaledLeftOffsetDouble(), tex->GetScaledTopOffsetDouble()));
}
ACTION_RETURN_VEC2(DVector2(-1, -1));
}
//==========================================================================
//
//
//
//==========================================================================
DEFINE_ACTION_FUNCTION(_TexMan, CheckRealHeight)
{
PARAM_PROLOGUE;

View File

@ -2084,10 +2084,7 @@ public:
// 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] = "";
lnametexts[1] = wbs->nextname;
bg = new DInterBackground(wbs);
GC::AddSoftRoot(bg);
@ -2140,14 +2137,7 @@ public:
void WI_Start (wbstartstruct_t *wbstartstruct)
{
auto info = FindLevelInfo(wbstartstruct->next, false);
if (info == nullptr)
{
wbstartstruct->next = "";
}
noautostartmap = false;
V_SetBlend (0,0,0,0);
WI_initVariables (wbstartstruct);
WI_loadData ();
if (deathmatch)
@ -2156,8 +2146,6 @@ public:
WI_initNetgameStats();
else
WI_initStats();
S_StopAllChannels ();
SN_StopAllSequences ();
}
};
@ -2190,11 +2178,67 @@ void WI_Drawer()
void WI_Start(wbstartstruct_t *wbstartstruct)
{
WI_Screen = new DStatusScreen;
auto info = FindLevelInfo(wbstartstruct->next, false);
if (info == nullptr)
{
wbstartstruct->next = "";
}
else wbstartstruct->nextname = info->LookupLevelName();
V_SetBlend(0, 0, 0, 0);
S_StopAllChannels();
SN_StopAllSequences();
WI_Screen->WI_Start(wbstartstruct);
GC::AddSoftRoot(WI_Screen);
}
DEFINE_ACTION_FUNCTION(DStatusScreen, GetPlayerWidths)
{
PARAM_PROLOGUE;
int maxnamewidth, maxscorewidth, maxiconheight;
HU_GetPlayerWidths(maxnamewidth, maxscorewidth, maxiconheight);
if (numret > 0) ret[0].SetInt(maxnamewidth);
if (numret > 1) ret[1].SetInt(maxscorewidth);
if (numret > 2) ret[2].SetInt(maxiconheight);
return MIN(numret, 3);
}
DEFINE_ACTION_FUNCTION(DStatusScreen, GetRowColor)
{
PARAM_PROLOGUE;
PARAM_POINTER(p, player_t);
PARAM_BOOL(highlight);
ACTION_RETURN_INT(HU_GetRowColor(p, highlight));
}
DEFINE_ACTION_FUNCTION(DStatusScreen, GetSortedPlayers)
{
PARAM_PROLOGUE;
PARAM_POINTER(array, TArray<int>);
PARAM_BOOL(teamplay);
player_t *sortedplayers[MAXPLAYERS];
// Sort all players
for (int 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);
array->Resize(MAXPLAYERS);
for (unsigned i = 0; i < MAXPLAYERS; i++)
{
(*array)[i] = int(sortedplayers[i] - players);
}
return 0;
}
DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, skills);
DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, sitems);
DEFINE_FIELD_X(WBPlayerStruct, wbplayerstruct_t, ssecret);
@ -2206,6 +2250,7 @@ DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, finished_ep);
DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, next_ep);
DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, current);
DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, next);
DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, nextname);
DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName0);
DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, LName1);
DEFINE_FIELD_X(WBStartStruct, wbstartstruct_t, maxkills);

View File

@ -48,6 +48,7 @@ struct wbstartstruct_t
FString current; // [RH] Name of map just finished
FString next; // next level, [RH] actual map name
FString nextname; // printable name for next level.
FTextureID LName0;
FTextureID LName1;

View File

@ -28,6 +28,9 @@ version "2.4"
#include "zscript/statscreen/types.txt"
#include "zscript/statscreen/statscreen.txt"
#include "zscript/statscreen/statscreen_sp.txt"
#include "zscript/statscreen/statscreen_dm.txt"
#include "zscript/statscreen/statscreen_coop.txt"
#include "zscript/inventory/inventory.txt"
#include "zscript/inventory/inv_misc.txt"

View File

@ -88,6 +88,7 @@ struct TexMan
native static void ReplaceTextures(String from, String to, int flags);
native static int, int GetSize(TextureID tex);
native static Vector2 GetScaledSize(TextureID tex);
native static Vector2 GetScaledOffset(TextureID tex);
native static int CheckRealHeight(TextureID tex);
}
@ -304,6 +305,7 @@ struct GameInfoStruct native
native GIFont mStatscreenEnteringFont;
native GIFont mStatscreenFinishedFont;
native double gibfactor;
native bool intermissioncounter;
}
class Object native
@ -499,6 +501,7 @@ struct LevelLocals native
native static void StartSlideshow(Name whichone = 'none');
native static void WorldDone();
native static void RemoveAllBots(bool fromlist);
native void SetInterMusic(String nextmap);
}
struct StringTable native

View File

@ -247,6 +247,7 @@ struct PlayerInfo native play // this is what internally is known as player_t
native PlayerPawn mo;
native uint8 playerstate;
native readonly uint buttons;
native uint original_oldbuttons;
native readonly Class<PlayerPawn> cls;
native float DesiredFOV;
@ -349,6 +350,7 @@ usercmd_t original_cmd;
native String GetUserName() const;
native Color GetColor() const;
native Color GetDisplayColor() const;
native int GetColorSet() const;
native int GetPlayerClassNum() const;
native int GetSkin() const;

View File

@ -1,14 +1,14 @@
// Note that the status screen needs to run in 'play' scope!
class InterBackground native play
class InterBackground native play version("2.4")
{
native InterBackground Create(wbstartstruct wbst);
native bool LoadBackground(bool isenterpic);
native void updateAnimatedBack();
native void drawBackground(int CurState, bool drawsplat, bool snl_pointeron);
native static InterBackground Create(wbstartstruct wbst);
native virtual bool LoadBackground(bool isenterpic);
native virtual void updateAnimatedBack();
native virtual void drawBackground(int CurState, bool drawsplat, bool snl_pointeron);
}
struct PatchInfo play
struct PatchInfo play version("2.4")
{
Font mFont;
TextureID mPatch;
@ -37,12 +37,12 @@ struct PatchInfo play
// Will be made a class later, but for now needs to mirror the internal version.
class StatusScreen native play
class StatusScreen native play version("2.4")
{
enum EValues
{
// GLOBAL LOCATIONS
WI_TITLEY = 2,
TITLEY = 2,
// SINGPLE-PLAYER STUFF
SP_STATSX = 50,
@ -132,7 +132,7 @@ class StatusScreen native play
//
//====================================================================
protected int DrawCharPatch(Font fnt, int charcode, int x, int y, int translation = Font.CR_UNTRANSLATED, bool nomove = false)
int DrawCharPatch(Font fnt, int charcode, int x, int y, int translation = Font.CR_UNTRANSLATED, bool nomove = false)
{
int width = fnt.GetCharWidth(charcode);
screen.DrawChar(fnt, translation, x, y, charcode, nomove ? DTA_CleanNoMove : DTA_Clean, true);
@ -148,7 +148,7 @@ class StatusScreen native play
//
//====================================================================
protected int DrawName(int y, TextureID tex, String levelname)
int DrawName(int y, TextureID tex, String levelname)
{
// draw <LevelName>
if (tex.isValid())
@ -188,7 +188,7 @@ class StatusScreen native play
//
//====================================================================
protected int DrawPatchText(int y, PatchInfo pinfo, String stringname)
int DrawPatchText(int y, PatchInfo pinfo, String stringname)
{
String string = Stringtable.Localize(stringname);
int midx = screen.GetWidth() / 2;
@ -216,9 +216,9 @@ class StatusScreen native play
//
//====================================================================
protected int drawLF ()
int drawLF ()
{
int y = WI_TITLEY * CleanYfac;
int y = TITLEY * CleanYfac;
y = DrawName(y, wbs.LName0, lnametexts[0]);
@ -229,7 +229,7 @@ class StatusScreen native play
if (y < (NG_STATSY - finished.mFont.GetHeight()*3/4) * CleanYfac)
{
// don't draw 'finished' if the level name is too tall
y = DrawPatchText(y, finished, "$WI_FINISHED");
y = DrawPatchText(y, finished, "$FINISHED");
}
return y;
}
@ -244,11 +244,11 @@ class StatusScreen native play
//
//====================================================================
protected void drawEL ()
void drawEL ()
{
int y = WI_TITLEY * CleanYfac;
int y = TITLEY * CleanYfac;
y = DrawPatchText(y, entering, "$WI_ENTERING");
y = DrawPatchText(y, entering, "$ENTERING");
y += entering.mFont.GetHeight() * CleanYfac / 4;
DrawName(y, wbs.LName1, lnametexts[1]);
}
@ -263,7 +263,7 @@ class StatusScreen native play
// Returns new x position, that is, the left edge of the number.
//
//====================================================================
protected int drawNum (Font fnt, int x, int y, int n, int digits, bool leadingzeros = true, int translation = Font.CR_UNTRANSLATED)
int drawNum (Font fnt, int x, int y, int n, int digits, bool leadingzeros = true, int translation = Font.CR_UNTRANSLATED)
{
int fntwidth = fnt.StringWidth("3");
String text;
@ -315,7 +315,7 @@ class StatusScreen native play
//
//====================================================================
protected void drawPercent (Font fnt, int x, int y, int p, int b, bool show_total = true, int color = Font.CR_UNTRANSLATED)
void drawPercent (Font fnt, int x, int y, int p, int b, bool show_total = true, int color = Font.CR_UNTRANSLATED)
{
if (p < 0)
return;
@ -355,7 +355,7 @@ class StatusScreen native play
//
//====================================================================
protected void drawTime (int x, int y, int t, bool no_sucks=false)
void drawTime (int x, int y, int t, bool no_sucks=false)
{
bool sucky;
@ -405,7 +405,7 @@ class StatusScreen native play
//
//====================================================================
protected void End ()
void End ()
{
CurState = LeavingIntermission;
@ -422,7 +422,7 @@ class StatusScreen native play
//
//====================================================================
protected bool autoSkip()
bool autoSkip()
{
return wi_autoadvance > 0 && bcnt > (wi_autoadvance * Thinker.TICRATE);
}
@ -433,7 +433,7 @@ class StatusScreen native play
//
//====================================================================
protected void initNoState ()
protected virtual void initNoState ()
{
CurState = NoState;
acceleratestage = 0;
@ -446,7 +446,7 @@ class StatusScreen native play
//
//====================================================================
protected void updateNoState ()
protected virtual void updateNoState ()
{
if (acceleratestage)
{
@ -482,7 +482,7 @@ class StatusScreen native play
//
//====================================================================
protected void initShowNextLoc ()
protected virtual void initShowNextLoc ()
{
if (wbs.next == "")
{
@ -504,7 +504,7 @@ class StatusScreen native play
//
//====================================================================
protected void updateShowNextLoc ()
protected virtual void updateShowNextLoc ()
{
if (!--cnt || acceleratestage)
initNoState();
@ -518,7 +518,7 @@ class StatusScreen native play
//
//====================================================================
protected void drawShowNextLoc(void)
protected virtual void drawShowNextLoc(void)
{
bg.drawBackground(CurState, true, snl_pointeron);
@ -533,10 +533,203 @@ class StatusScreen native play
//
//====================================================================
void WI_drawNoState ()
protected virtual void drawNoState ()
{
snl_pointeron = true;
drawShowNextLoc();
}
//====================================================================
//
//
//
//====================================================================
protected int fragSum (int playernum)
{
int i;
int frags = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i]
&& i!=playernum)
{
frags += Plrs[playernum].frags[i];
}
}
// JDC hack - negative frags.
frags -= Plrs[playernum].frags[playernum];
return frags;
}
//====================================================================
//
//
//
//====================================================================
static void PlaySound(Sound snd)
{
S_Sound(snd, CHAN_VOICE | CHAN_UI, 1, ATTN_NONE);
}
// ====================================================================
// 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
//
// ====================================================================
protected void checkForAccelerate(void)
{
int i;
// check for button presses to skip delays
for (i = 0; i < MAXPLAYERS; i++)
{
PlayerInfo player = players[i];
if (playeringame[i])
{
if ((player.buttons ^ player.oldbuttons) &&
((player.buttons & player.oldbuttons) == player.oldbuttons) && player.Bot == NULL)
{
acceleratestage = 1;
playerready[i] = true;
}
player.oldbuttons = player.buttons;
}
}
}
// ====================================================================
// Ticker
// Purpose: Do various updates every gametic, for stats, animation,
// checking that intermission music is running, etc.
// Args: none
// Returns: void
//
// ====================================================================
virtual void StartMusic()
{
level.SetInterMusic(wbs.next);
}
//====================================================================
//
//
//
//====================================================================
virtual void Ticker(void)
{
// counter for general background animation
bcnt++;
if (bcnt == 1)
{
StartMusic();
}
checkForAccelerate();
bg.updateAnimatedBack();
switch (CurState)
{
case StatCount:
updateStats();
break;
case ShowNextLoc:
updateShowNextLoc();
break;
case NoState:
updateNoState();
break;
case LeavingIntermission:
// Hush, GCC.
break;
}
}
//====================================================================
//
//
//
//====================================================================
virtual void Drawer (void)
{
switch (CurState)
{
case StatCount:
drawStats();
break;
case ShowNextLoc:
drawShowNextLoc();
break;
case LeavingIntermission:
break;
default:
drawNoState();
break;
}
}
//====================================================================
//
//
//
//====================================================================
virtual void Start (wbstartstruct wbstartstruct)
{
noautostartmap = false;
wbs = wbstartstruct;
acceleratestage = 0;
cnt = bcnt = 0;
me = wbs.pnum;
for (int i = 0; i < MAXPLAYERS; i++) Plrs[i] = wbs.plyr[i];
entering.Init(gameinfo.mStatscreenEnteringFont);
finished.Init(gameinfo.mStatscreenFinishedFont);
mapname.Init(gameinfo.mStatscreenMapNameFont);
Kills = TexMan.CheckForTexture("WIOSTK", TexMan.Type_MiscPatch); // "kills"
Secret = TexMan.CheckForTexture("WIOSTS", TexMan.Type_MiscPatch); // "scrt"
P_secret = TexMan.CheckForTexture("WISCRT2", TexMan.Type_MiscPatch); // "secret"
Items = TexMan.CheckForTexture("WIOSTI", TexMan.Type_MiscPatch); // "items"
Timepic = TexMan.CheckForTexture("WITIME", TexMan.Type_MiscPatch); // "time"
Sucks = TexMan.CheckForTexture("WISUCKS", TexMan.Type_MiscPatch); // "sucks"
Par = TexMan.CheckForTexture("WIPAR", TexMan.Type_MiscPatch); // "par"
// Use the local level structure which can be overridden by hubs
lnametexts[0] = level.LevelName;
lnametexts[1] = wbs.nextname;
bg = InterBackground.Create(wbs);
initStats();
}
protected virtual void initStats() {}
protected virtual void updateStats() {}
protected virtual void drawStats() {}
native int, int, int GetPlayerWidths();
native Color GetRowColor(PlayerInfo player, bool highlight);
native void GetSortedPlayers(in out Array<int> sorted, bool teamplay);
}

View File

@ -0,0 +1,324 @@
class CoopStatusScreen : StatusScreen
{
int textcolor;
//====================================================================
//
//
//
//====================================================================
override void initStats ()
{
textcolor = (gameinfo.gametype & GAME_Raven) ? Font.CR_GREEN : Font.CR_UNTRANSLATED;
CurState = StatCount;
acceleratestage = 0;
ng_state = 1;
cnt_pause = Thinker.TICRATE;
for (int i = 0; i < MAXPLAYERS; i++)
{
playerready[i] = false;
cnt_kills[i] = cnt_items[i] = cnt_secret[i] = cnt_frags[i] = 0;
if (!playeringame[i])
continue;
dofrags += fragSum (i);
}
dofrags = !!dofrags;
}
//====================================================================
//
//
//
//====================================================================
override void updateStats ()
{
int i;
int fsum;
bool stillticking;
bool autoskip = autoSkip();
if ((acceleratestage || autoskip) && ng_state != 10)
{
acceleratestage = 0;
for (i=0 ; i<MAXPLAYERS ; 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] = fragSum (i);
}
PlaySound("intermission/nextstage");
ng_state = 10;
}
if (ng_state == 2)
{
if (!(bcnt&3))
PlaySound("intermission/tick");
stillticking = false;
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (!playeringame[i])
continue;
cnt_kills[i] += 2;
if (cnt_kills[i] > Plrs[i].skills)
cnt_kills[i] = Plrs[i].skills;
else
stillticking = true;
}
if (!stillticking)
{
PlaySound("intermission/nextstage");
ng_state++;
}
}
else if (ng_state == 4)
{
if (!(bcnt&3))
PlaySound("intermission/tick");
stillticking = false;
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (!playeringame[i])
continue;
cnt_items[i] += 2;
if (cnt_items[i] > Plrs[i].sitems)
cnt_items[i] = Plrs[i].sitems;
else
stillticking = true;
}
if (!stillticking)
{
PlaySound("intermission/nextstage");
ng_state++;
}
}
else if (ng_state == 6)
{
if (!(bcnt&3))
PlaySound("intermission/tick");
stillticking = false;
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (!playeringame[i])
continue;
cnt_secret[i] += 2;
if (cnt_secret[i] > Plrs[i].ssecret)
cnt_secret[i] = Plrs[i].ssecret;
else
stillticking = true;
}
if (!stillticking)
{
PlaySound("intermission/nextstage");
ng_state += 1 + 2*!dofrags;
}
}
else if (ng_state == 8)
{
if (!(bcnt&3))
PlaySound("intermission/tick");
stillticking = false;
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (!playeringame[i])
continue;
cnt_frags[i] += 1;
if (cnt_frags[i] >= (fsum = fragSum(i)))
cnt_frags[i] = fsum;
else
stillticking = true;
}
if (!stillticking)
{
PlaySound("intermission/cooptotal");
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)
{
PlaySound("intermission/pastcoopstats");
initShowNextLoc();
}
}
else if (ng_state & 1)
{
if (!--cnt_pause)
{
ng_state++;
cnt_pause = Thinker.TICRATE;
}
}
}
//====================================================================
//
//
//
//====================================================================
override void drawStats ()
{
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;
int color;
String text_bonus, text_secret, text_kills;
TextureID readyico = TexMan.CheckForTexture("READYICO", TexMan.Type_MiscPatch);
// draw animated background
bg.drawBackground(CurState, false, false);
y = drawLF();
[maxnamewidth, maxscorewidth, maxiconheight] = GetPlayerWidths();
// Use the readyico height if it's bigger.
Vector2 readysize = TexMan.GetScaledSize(readyico);
Vector2 readyoffset = TexMan.GetScaledOffset(readyico);
if (readysize.Y > maxiconheight)
{
maxiconheight = height;
}
height = SmallFont.GetHeight() * CleanYfac;
lineheight = MAX(height, maxiconheight * CleanYfac);
ypadding = (lineheight - height + 1) / 2;
y += CleanYfac;
text_bonus = Stringtable.Localize((gameinfo.gametype & GAME_Raven) ? "$SCORE_BONUS" : "$SCORE_ITEMS");
text_secret = Stringtable.Localize("$SCORE_SECRET");
text_kills = Stringtable.Localize("$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 = (screen.GetWidth() - secret_x) >> 1;
icon_x += x;
name_x += x;
kills_x += x;
bonus_x += x;
secret_x += x;
screen.DrawText(SmallFont, textcolor, name_x, y, Stringtable.Localize("$SCORE_NAME"), DTA_CleanNoMove, true);
screen.DrawText(SmallFont, textcolor, kills_x - SmallFont.StringWidth(text_kills)*CleanXfac, y, text_kills, DTA_CleanNoMove, true);
screen.DrawText(SmallFont, textcolor, bonus_x - bonus_len*CleanXfac, y, text_bonus, DTA_CleanNoMove, true);
screen.DrawText(SmallFont, textcolor, secret_x - secret_len*CleanXfac, y, text_secret, DTA_CleanNoMove, true);
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)
{
if (!playeringame[i])
continue;
PlayerInfo player = players[i];
screen.Dim(player.GetDisplayColor(), 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, true, x - (readysize.Y * CleanXfac), y, DTA_CleanNoMove, true);
Color thiscolor = GetRowColor(player, i == consoleplayer);
if (player.mo.ScoreIcon.isValid())
{
screen.DrawTexture(player.mo.ScoreIcon, true, icon_x, y, DTA_CleanNoMove, true);
}
screen.DrawText(SmallFont, thiscolor, name_x, y + ypadding, player.GetUserName(), DTA_CleanNoMove, true);
drawPercent(SmallFont, kills_x, y + ypadding, cnt_kills[i], wbs.maxkills, false, thiscolor);
missed_kills -= cnt_kills[i];
if (ng_state >= 4)
{
drawPercent(SmallFont, bonus_x, y + ypadding, cnt_items[i], wbs.maxitems, false, thiscolor);
missed_items -= cnt_items[i];
if (ng_state >= 6)
{
drawPercent(SmallFont, secret_x, y + ypadding, cnt_secret[i], wbs.maxsecret, false, thiscolor);
missed_secrets -= cnt_secret[i];
}
}
y += lineheight + CleanYfac;
}
// Draw "MISSED" line
y += 3 * CleanYfac;
screen.DrawText(SmallFont, Font.CR_DARKGRAY, name_x, y, Stringtable.Localize("$SCORE_MISSED"), DTA_CleanNoMove, true);
drawPercent(SmallFont, kills_x, y, missed_kills, wbs.maxkills, false, Font.CR_DARKGRAY);
if (ng_state >= 4)
{
drawPercent(SmallFont, bonus_x, y, missed_items, wbs.maxitems, false, Font.CR_DARKGRAY);
if (ng_state >= 6)
{
drawPercent(SmallFont, secret_x, y, missed_secrets, wbs.maxsecret, false, Font.CR_DARKGRAY);
}
}
// Draw "TOTAL" line
y += height + 3 * CleanYfac;
screen.DrawText(SmallFont, textcolor, name_x, y, Stringtable.Localize("$SCORE_TOTAL"), DTA_CleanNoMove, true);
drawNum(SmallFont, kills_x, y, wbs.maxkills, 0, false, textcolor);
if (ng_state >= 4)
{
drawNum(SmallFont, bonus_x, y, wbs.maxitems, 0, false, textcolor);
if (ng_state >= 6)
{
drawNum(SmallFont, secret_x, y, wbs.maxsecret, 0, false, textcolor);
}
}
}
}

View File

@ -0,0 +1,244 @@
class DeathmatchStatusScreen : StatusScreen
{
int textcolor;
//====================================================================
//
//
//
//====================================================================
override void initStats (void)
{
int i, j;
textcolor = (gameinfo.gametype & GAME_Raven) ? Font.CR_GREEN : Font.CR_UNTRANSLATED;
CurState = StatCount;
acceleratestage = 0;
for(i = 0; i < MAXPLAYERS; i++)
{
playerready[i] = false;
cnt_frags[i] = cnt_deaths[i] = player_deaths[i] = 0;
}
total_frags = 0;
total_deaths = 0;
ng_state = 1;
cnt_pause = Thinker.TICRATE;
for (i=0 ; i<MAXPLAYERS ; i++)
{
if (playeringame[i])
{
for (j = 0; j < MAXPLAYERS; j++)
{
if (playeringame[j])
player_deaths[i] += Plrs[j].frags[i];
}
total_deaths += player_deaths[i];
total_frags += Plrs[i].fragcount;
}
}
}
override void updateStats ()
{
int i;
bool stillticking;
bool doautoskip = autoSkip();
if ((acceleratestage || doautoskip) && ng_state != 6)
{
acceleratestage = 0;
for (i = 0; i<MAXPLAYERS; i++)
{
if (!playeringame[i]) continue;
cnt_frags[i] = Plrs[i].fragcount;
cnt_deaths[i] = player_deaths[i];
}
PlaySound("intermission/nextstage");
ng_state = 6;
}
if (ng_state == 2)
{
if (!(bcnt & 3))
PlaySound("intermission/tick");
stillticking = false;
for (i = 0; i<MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
cnt_frags[i] += 2;
if (cnt_frags[i] > Plrs[i].fragcount)
cnt_frags[i] = Plrs[i].fragcount;
else
stillticking = true;
}
if (!stillticking)
{
PlaySound("intermission/nextstage");
ng_state++;
}
}
else if (ng_state == 4)
{
if (!(bcnt & 3))
PlaySound("intermission/tick");
stillticking = false;
for (i = 0; i<MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
cnt_deaths[i] += 2;
if (cnt_deaths[i] > player_deaths[i])
cnt_deaths[i] = player_deaths[i];
else
stillticking = true;
}
if (!stillticking)
{
PlaySound("intermission/nextstage");
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) || doautoskip)
{
PlaySound("intermission/pastdmstats");
initShowNextLoc();
}
}
else if (ng_state & 1)
{
if (!--cnt_pause)
{
ng_state++;
cnt_pause = Thinker.TICRATE;
}
}
}
override void drawStats ()
{
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;
String text_deaths, text_frags;
TextureID readyico = TexMan.CheckForTexture("READYICO", TexMan.Type_MiscPatch);
// draw animated background
bg.drawBackground(CurState, false, false);
y = drawLF();
[maxnamewidth, maxscorewidth, maxiconheight] = GetPlayerWidths();
// Use the readyico height if it's bigger.
Vector2 readysize = TexMan.GetScaledSize(readyico);
Vector2 readyoffset = TexMan.GetScaledOffset(readyico);
height = readysize.Y - readyoffset.Y;
maxiconheight = MAX(height, maxiconheight);
height = SmallFont.GetHeight() * CleanYfac;
lineheight = MAX(height, maxiconheight * CleanYfac);
ypadding = (lineheight - height + 1) / 2;
y += CleanYfac;
text_deaths = Stringtable.Localize("$SCORE_DEATHS");
//text_color = Stringtable.Localize("$SCORE_COLOR");
text_frags = Stringtable.Localize("$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 = (Screen.GetWidth() - deaths_x) >> 1;
icon_x += x;
name_x += x;
frags_x += x;
deaths_x += x;
screen.DrawText(SmallFont, textcolor, name_x, y, Stringtable.Localize("$SCORE_NAME"), DTA_CleanNoMove, true);
screen.DrawText(SmallFont, textcolor, frags_x - SmallFont.StringWidth(text_frags) * CleanXfac, y, text_frags, DTA_CleanNoMove, true);
screen.DrawText(SmallFont, textcolor, deaths_x - deaths_len * CleanXfac, y, text_deaths, DTA_CleanNoMove, true);
y += height + 6 * CleanYfac;
// Sort all players
Array<int> sortedplayers;
GetSortedPlayers(sortedplayers, teamplay);
// Draw lines for each player
for (i = 0; i < sortedplayers.Size(); i++)
{
pnum = sortedplayers[i];
PlayerInfo player = players[pnum];
if (!playeringame[pnum])
continue;
screen.Dim(player.GetDisplayColor(), 0.8, 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, true, x - (readysize.X * CleanXfac), y, DTA_CleanNoMove, true);
let thiscolor = GetRowColor(player, pnum == consoleplayer);
if (player.mo.ScoreIcon.isValid())
{
screen.DrawTexture(player.mo.ScoreIcon, true, icon_x, y, DTA_CleanNoMove, true);
}
screen.DrawText(SmallFont, thiscolor, name_x, y + ypadding, player.GetUserName(), DTA_CleanNoMove, true);
drawNum(SmallFont, frags_x, y + ypadding, cnt_frags[pnum], 0, false, thiscolor);
if (ng_state >= 2)
{
drawNum(SmallFont, deaths_x, y + ypadding, cnt_deaths[pnum], 0, false, thiscolor);
}
y += lineheight + CleanYfac;
}
// Draw "TOTAL" line
y += height + 3 * CleanYfac;
screen.DrawText(SmallFont, textcolor, name_x, y, Stringtable.Localize("$SCORE_TOTAL"), DTA_CleanNoMove, true);
drawNum(SmallFont, frags_x, y, total_frags, 0, false, textcolor);
if (ng_state >= 4)
{
drawNum(SmallFont, deaths_x, y, total_deaths, 0, false, textcolor);
}
// Draw game time
y += height + CleanYfac;
int seconds = Plrs[me].stime * Thinker.TICRATE;
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
seconds = seconds % 60;
String leveltime = Stringtable.Localize("$SCORE_LVLTIME") .. ": " .. String.Format("%02i:%02i:%02i", hours, minutes, seconds);
screen.DrawText(SmallFont, textcolor, x, y, leveltime, DTA_CleanNoMove, true);
}
}

View File

@ -0,0 +1,206 @@
class DoomStatusScreen : StatusScreen
{
int intermissioncounter;
override void initStats ()
{
intermissioncounter = gameinfo.intermissioncounter;
CurState = StatCount;
acceleratestage = 0;
sp_state = 1;
cnt_kills[0] = cnt_items[0] = cnt_secret[0] = -1;
cnt_time = cnt_par = -1;
cnt_pause = Thinker.TICRATE;
cnt_total_time = -1;
}
override void updateStats ()
{
if (acceleratestage && sp_state != 10)
{
acceleratestage = 0;
sp_state = 10;
PlaySound("intermission/nextstage");
cnt_kills[0] = Plrs[me].skills;
cnt_items[0] = Plrs[me].sitems;
cnt_secret[0] = Plrs[me].ssecret;
cnt_time = Plrs[me].stime / Thinker.TICRATE;
cnt_par = wbs.partime / Thinker.TICRATE;
cnt_total_time = wbs.totaltime / Thinker.TICRATE;
}
if (sp_state == 2)
{
if (intermissioncounter)
{
cnt_kills[0] += 2;
if (!(bcnt&3))
PlaySound("intermission/tick");
}
if (!intermissioncounter || cnt_kills[0] >= Plrs[me].skills)
{
cnt_kills[0] = Plrs[me].skills;
PlaySound("intermission/nextstage");
sp_state++;
}
}
else if (sp_state == 4)
{
if (intermissioncounter)
{
cnt_items[0] += 2;
if (!(bcnt&3))
PlaySound("intermission/tick");
}
if (!intermissioncounter || cnt_items[0] >= Plrs[me].sitems)
{
cnt_items[0] = Plrs[me].sitems;
PlaySound("intermission/nextstage");
sp_state++;
}
}
else if (sp_state == 6)
{
if (intermissioncounter)
{
cnt_secret[0] += 2;
if (!(bcnt&3))
PlaySound("intermission/tick");
}
if (!intermissioncounter || cnt_secret[0] >= Plrs[me].ssecret)
{
cnt_secret[0] = Plrs[me].ssecret;
PlaySound("intermission/nextstage");
sp_state++;
}
}
else if (sp_state == 8)
{
if (intermissioncounter)
{
if (!(bcnt&3))
PlaySound("intermission/tick");
cnt_time += 3;
cnt_par += 3;
cnt_total_time += 3;
}
int sec = Plrs[me].stime / Thinker.TICRATE;
if (!intermissioncounter || cnt_time >= sec)
cnt_time = sec;
int tsec = wbs.totaltime / Thinker.TICRATE;
if (!intermissioncounter || cnt_total_time >= tsec)
cnt_total_time = tsec;
if (!intermissioncounter || cnt_par >= wbs.partime / Thinker.TICRATE)
{
cnt_par = wbs.partime / Thinker.TICRATE;
if (cnt_time >= sec)
{
cnt_total_time = tsec;
PlaySound("intermission/nextstage");
sp_state++;
}
}
}
else if (sp_state == 10)
{
if (acceleratestage)
{
PlaySound("intermission/paststats");
initShowNextLoc();
}
}
else if (sp_state & 1)
{
if (!--cnt_pause)
{
sp_state++;
cnt_pause = Thinker.TICRATE;
}
}
}
override void drawStats (void)
{
// line height
int lh = IntermissionFont.GetHeight() * 3 / 2;
// draw animated background
bg.drawBackground(CurState, false, false);
drawLF();
screen.DrawTexture (Kills, true, SP_STATSX, SP_STATSY, DTA_Clean, true);
drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY, cnt_kills[0], wbs.maxkills);
screen.DrawTexture (Items, true, SP_STATSX, SP_STATSY+lh, DTA_Clean, true);
drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+lh, cnt_items[0], wbs.maxitems);
screen.DrawTexture (P_secret, true, SP_STATSX, SP_STATSY+2*lh, DTA_Clean, true);
drawPercent (IntermissionFont, 320 - SP_STATSX, SP_STATSY+2*lh, cnt_secret[0], wbs.maxsecret);
screen.DrawTexture (Timepic, true, SP_TIMEX, SP_TIMEY, DTA_Clean, true);
drawTime (160 - SP_TIMEX, SP_TIMEY, cnt_time);
if (wi_showtotaltime)
{
drawTime (160 - SP_TIMEX, SP_TIMEY + lh, cnt_total_time, true); // no 'sucks' for total time ever!
}
if (wbs.partime)
{
screen.DrawTexture (Par, 160 + SP_TIMEX, SP_TIMEY, DTA_Clean, true);
drawTime (320 - SP_TIMEX, SP_TIMEY, cnt_par);
}
}
}
class RavenStatusScreen : DoomStatusScreen
{
override void drawStats (void)
{
// line height
int lh = IntermissionFont.GetHeight() * 3 / 2;
// draw animated background
bg.drawBackground(CurState, false, false);
drawLF();
screen.DrawText (BigFont, Font.CR_UNTRANSLATED, 50, 65, Stringtable.Localize("$TXT_IMKILLS"), DTA_Clean, true, DTA_Shadow, true);
screen.DrawText (BigFont, Font.CR_UNTRANSLATED, 50, 90, Stringtable.Localize("$TXT_IMITEMS"), DTA_Clean, true, DTA_Shadow, true);
screen.DrawText (BigFont, Font.CR_UNTRANSLATED, 50, 115, Stringtable.Localize("$TXT_IMSECRETS"), DTA_Clean, true, DTA_Shadow, true);
int countpos = gameinfo.gametype==GAME_Strife? 285:270;
if (sp_state >= 2)
{
drawPercent (IntermissionFont, countpos, 65, cnt_kills[0], wbs.maxkills);
}
if (sp_state >= 4)
{
drawPercent (IntermissionFont, countpos, 90, cnt_items[0], wbs.maxitems);
}
if (sp_state >= 6)
{
drawPercent (IntermissionFont, countpos, 115, cnt_secret[0], wbs.maxsecret);
}
if (sp_state >= 8)
{
screen.DrawText (BigFont, Font.CR_UNTRANSLATED, 85, 160, Stringtable.Localize("$TXT_IMTIME"), DTA_Clean, true, DTA_Shadow, true);
drawTime (249, 160, cnt_time);
if (wi_showtotaltime)
{
drawTime (249, 180, cnt_total_time);
}
}
}
}

View File

@ -18,9 +18,11 @@ struct WBStartStruct native version("2.4")
{
native int finished_ep;
native int next_ep;
native @WBPlayerStruct plyr[MAXPLAYERS];
native String current; // [RH] Name of map just finished
native String next; // next level, [RH] actual map name
native String nextname; // next level, printable name
native TextureID LName0;
native TextureID LName1;