gzdoom/wadsrc/static/zscript/statscreen/statscreen.txt

543 lines
13 KiB
Text
Raw Normal View History

// Note that the status screen needs to run in 'play' scope!
class InterBackground native play
{
native InterBackground Create(wbstartstruct wbst);
native bool LoadBackground(bool isenterpic);
native void updateAnimatedBack();
native void drawBackground(int CurState, bool drawsplat, bool snl_pointeron);
}
struct PatchInfo play
{
Font mFont;
TextureID mPatch;
int mColor;
void Init(GIFont gifont)
{
if (gifont.color == 'Null')
{
mPatch = TexMan.CheckForTexture(gifont.fontname, TexMan.Type_MiscPatch);
mColor = mPatch.isValid() ? Font.CR_UNTRANSLATED : Font.CR_UNDEFINED;
mFont = NULL;
}
else
{
mFont = Font.GetFont(gifont.fontname);
mColor = Font.FindFontColor(gifont.color);
mPatch.SetInvalid();
}
if (mFont == NULL)
{
mFont = BigFont;
}
}
};
// Will be made a class later, but for now needs to mirror the internal version.
class StatusScreen native play
{
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,
};
enum EState
{
NoState = -1,
StatCount,
ShowNextLoc,
LeavingIntermission
};
// States for single-player
enum ESPState
{
SP_KILLS = 0,
SP_ITEMS = 2,
SP_SECRET = 4,
SP_FRAGS = 6,
SP_TIME = 8,
};
const SHOWNEXTLOCDELAY = 4; // in seconds
InterBackground bg;
native int acceleratestage; // used to accelerate or skip a stage
native bool playerready[MAXPLAYERS];
native int me; // wbs.pnum
native int bcnt;
native int CurState; // specifies current CurState
native wbstartstruct wbs; // contains information passed into intermission
native wbplayerstruct Plrs[MAXPLAYERS]; // wbs.plyr[]
native int cnt; // used for general timing
native int cnt_kills[MAXPLAYERS];
native int cnt_items[MAXPLAYERS];
native int cnt_secret[MAXPLAYERS];
native int cnt_frags[MAXPLAYERS];
native int cnt_deaths[MAXPLAYERS];
native int cnt_time;
native int cnt_total_time;
native int cnt_par;
native int cnt_pause;
native int total_frags;
native int total_deaths;
native bool noautostartmap;
native int dofrags;
native int ng_state;
native float shadowalpha;
//
// GRAPHICS
//
native PatchInfo mapname;
native PatchInfo finished;
native PatchInfo entering;
native TextureID p_secret;
native TextureID kills;
native TextureID secret;
native TextureID items;
native TextureID timepic;
native TextureID par;
native TextureID sucks;
// [RH] Info to dynamically generate the level name graphics
native String lnametexts[2];
native bool snl_pointeron;
native int player_deaths[MAXPLAYERS];
native int sp_state;
//====================================================================
//
// Draws a single character with a shadow
//
//====================================================================
protected 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);
return x - width;
}
//====================================================================
//
// 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
//
//====================================================================
protected int DrawName(int y, TextureID tex, String levelname)
{
// draw <LevelName>
if (tex.isValid())
{
int w,h;
[w, h] = TexMan.GetSize(tex);
let size = TexMan.GetScaledSize(tex);
screen.DrawTexture(tex, true, (screen.GetWidth() - size.X * CleanXfac) /2, y, DTA_CleanNoMove, true);
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.
size.Y = TexMan.CheckRealHeight(tex) * size.Y / h;
}
return y + (h + BigFont.GetHeight()/4) * CleanYfac;
}
else if (levelname.Length() > 0)
{
int h = 0;
int lumph = mapname.mFont.GetHeight() * CleanYfac;
BrokenLines lines = mapname.mFont.BreakLines(levelname, screen.GetWidth() / CleanXfac);
int count = lines.Count();
for (int i = 0; i < count; i++)
{
screen.DrawText(mapname.mFont, mapname.mColor, (screen.GetWidth() - lines.StringWidth(i) * CleanXfac) / 2, y + h, lines.StringAt(i), DTA_CleanNoMove, true);
h += lumph;
}
return y + h + lumph/4;
}
return 0;
}
//====================================================================
//
// Draws a text, either as patch or as string from the string table
//
//====================================================================
protected int DrawPatchText(int y, PatchInfo pinfo, String stringname)
{
String string = Stringtable.Localize(stringname);
int midx = screen.GetWidth() / 2;
if (pinfo.mPatch.isValid())
{
let size = TexMan.GetScaledSize(pinfo.mPatch);
screen.DrawTexture(pinfo.mPatch, true, midx - size.X * CleanXfac/2, y, DTA_CleanNoMove, true);
return y + (size.Y * CleanYfac);
}
else
{
screen.DrawText(pinfo.mFont, pinfo.mColor, midx - pinfo.mFont.StringWidth(string) * CleanXfac/2, y, string, DTA_CleanNoMove, true);
return y + pinfo.mFont.GetHeight() * CleanYfac;
}
}
//====================================================================
//
// Draws "<Levelname> Finished!"
//
// Either uses the specified patch or the big font
// A level name patch can be specified for all games now, not just Doom.
//
//====================================================================
protected int drawLF ()
{
int y = WI_TITLEY * CleanYfac;
y = 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 = DrawPatchText(y, finished, "$WI_FINISHED");
}
return y;
}
//====================================================================
//
// Draws "Entering <LevelName>"
//
// Either uses the specified patch or the big font
// A level name patch can be specified for all games now, not just Doom.
//
//====================================================================
protected void drawEL ()
{
int y = WI_TITLEY * CleanYfac;
y = DrawPatchText(y, entering, "$WI_ENTERING");
y += entering.mFont.GetHeight() * CleanYfac / 4;
DrawName(y, wbs.LName1, lnametexts[1]);
}
//====================================================================
//
// 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.
//
//====================================================================
protected 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;
int len;
bool nomove = fnt != IntermissionFont;
if (nomove)
{
fntwidth *= CleanXfac;
}
text = String.Format("%d", n);
len = text.Length();
if (leadingzeros)
{
int filldigits = digits - len;
for(int i = 0; i < filldigits; i++)
{
text = "0" .. text;
}
len = text.Length();
}
for(int text_p = len-1; text_p >= 0; text_p--)
{
// Digits are centered in a box the width of the '3' character.
// Other characters (specifically, '-') are right-aligned in their cell.
int c = text.CharCodeAt(text_p);
if (c >= "0" && c <= "9")
{
x -= fntwidth;
DrawCharPatch(fnt, c, x + (fntwidth - fnt.GetCharWidth(c)) / 2, y, translation, nomove);
}
else
{
DrawCharPatch(fnt, c, x - fnt.GetCharWidth(c), y, translation, nomove);
x -= fntwidth;
}
}
if (len < digits)
{
x -= fntwidth * (digits - len);
}
return x;
}
//====================================================================
//
//
//
//====================================================================
protected 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;
if (wi_percents)
{
if (fnt != IntermissionFont)
{
x -= fnt.StringWidth("%") * CleanXfac;
}
else
{
x -= fnt.StringWidth("%");
}
screen.DrawText(fnt, color, x, y, "%", fnt != IntermissionFont ? DTA_CleanNoMove : DTA_Clean, true);
if (fnt != IntermissionFont)
{
x -= 2*CleanXfac;
}
drawNum(fnt, x, y, b == 0 ? 100 : p * 100 / b, -1, false, color);
}
else
{
if (show_total)
{
x = drawNum(fnt, x, y, b, 2, false);
x -= fnt.StringWidth("/");
screen.DrawText (IntermissionFont, color, x, y, "/", DTA_Clean, true);
}
drawNum (fnt, x, y, p, -1, false, color);
}
}
//====================================================================
//
// Display level completion time and par, or "sucks" message if overflow.
//
//====================================================================
protected void 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.isValid())
{
let size = TexMan.GetScaledSize(Sucks);
screen.DrawTexture (Sucks, true, x - size.X, y - size.Y - 2, DTA_Clean, true);
}
else
{
screen.DrawText (BigFont, Font.CR_UNTRANSLATED, x - BigFont.StringWidth("SUCKS"), y - IntermissionFont.GetHeight() - 2, "SUCKS", DTA_Clean, true);
}
}
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 = drawNum (IntermissionFont, x, y, seconds, 2) - 1;
DrawCharPatch (IntermissionFont, ":", x -= colon_spacing, y);
x = drawNum (IntermissionFont, x, y, minutes, 2, hours!=0);
if (hours)
{
DrawCharPatch (IntermissionFont, ":", x -= colon_spacing, y);
drawNum (IntermissionFont, x, y, hours, 2);
}
}
//====================================================================
//
//
//
//====================================================================
protected void End ()
{
CurState = LeavingIntermission;
//Added by mc
if (deathmatch)
{
level.RemoveAllBots (consoleplayer != Net_Arbitrator);
}
}
//====================================================================
//
//
//
//====================================================================
protected bool autoSkip()
{
return wi_autoadvance > 0 && bcnt > (wi_autoadvance * Thinker.TICRATE);
}
//====================================================================
//
//
//
//====================================================================
protected void initNoState ()
{
CurState = NoState;
acceleratestage = 0;
cnt = 10;
}
//====================================================================
//
//
//
//====================================================================
protected void updateNoState ()
{
if (acceleratestage)
{
cnt = 0;
}
else
{
bool noauto = noautostartmap;
for (int i = 0; !noauto && i < MAXPLAYERS; ++i)
{
if (playeringame[i])
{
noauto |= players[i].GetNoAutostartMap();
}
}
if (!noauto || autoSkip())
{
cnt--;
}
}
if (cnt == 0)
{
End();
level.WorldDone();
}
}
//====================================================================
//
//
//
//====================================================================
protected void initShowNextLoc ()
{
if (wbs.next == "")
{
// Last map in episode - there is no next location!
End();
level.WorldDone();
return;
}
CurState = ShowNextLoc;
acceleratestage = 0;
cnt = SHOWNEXTLOCDELAY * Thinker.TICRATE;
bg.LoadBackground(true);
}
//====================================================================
//
//
//
//====================================================================
protected void updateShowNextLoc ()
{
if (!--cnt || acceleratestage)
initNoState();
else
snl_pointeron = (cnt & 31) < 20;
}
//====================================================================
//
//
//
//====================================================================
protected void drawShowNextLoc(void)
{
bg.drawBackground(CurState, true, snl_pointeron);
// draws which level you are entering..
drawEL ();
}
//====================================================================
//
//
//
//====================================================================
void WI_drawNoState ()
{
snl_pointeron = true;
drawShowNextLoc();
}
}