This commit is contained in:
Rachael Alexanderson 2017-03-25 00:26:06 -04:00
commit 733cf1acc5
18 changed files with 676 additions and 416 deletions

View file

@ -54,6 +54,7 @@
#include "r_utility.h"
#include "cmdlib.h"
#include "g_levellocals.h"
#include "virtual.h"
#include <time.h>
@ -1079,6 +1080,48 @@ bool ST_IsLatencyVisible()
&& (hud_showlag <= 2);
}
//---------------------------------------------------------------------------
//
// draw the overlay
//
//---------------------------------------------------------------------------
static void DrawPowerups(player_t *CPlayer)
{
// Each icon gets a 32x32 block to draw itself in.
int x, y;
AInventory *item;
const int yshift = SmallFont->GetHeight();
const int POWERUPICONSIZE = 32;
x = hudwidth -20;
y = POWERUPICONSIZE * 5/4
+ (ST_IsTimeVisible() ? yshift : 0)
+ (ST_IsLatencyVisible() ? yshift : 0);
for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
{
IFVIRTUALPTR(item, AInventory, GetPowerupIcon)
{
VMValue param[] = { item };
int rv;
VMReturn ret(&rv);
GlobalVMStack.Call(func, param, 1, &ret, 1);
auto tex = FSetTextureID(rv);
if (!tex.isValid()) continue;
auto texture = TexMan(tex);
screen->DrawTexture(texture, x, y, DTA_KeepRatio, true, DTA_VirtualWidth, hudwidth, DTA_VirtualHeight, hudheight, DTA_CenterBottomOffset, true, TAG_DONE);
x -= POWERUPICONSIZE;
if (x < -hudwidth / 2)
{
x = -20;
y += POWERUPICONSIZE * 3 / 2;
}
}
}
}
//---------------------------------------------------------------------------
//
@ -1158,6 +1201,7 @@ void DrawHUD()
DrawTime();
DrawLatency();
DrawPowerups(CPlayer);
}
else
{

View file

@ -443,6 +443,7 @@ public:
double drawClip[4] = { 0,0,0,0 }; // defines a clipping rectangle (not used yet)
bool fullscreenOffsets = false; // current screen is displayed with fullscreen behavior.
DVector2 cleanScale; // factor for scaled fullscreen display.
FMugShot mugshot;
private:
bool RepositionCoords (int &x, int &y, int xo, int yo, const int w, const int h) const;

View file

@ -1317,7 +1317,6 @@ public:
adjustRelCenter(x.RelCenter(), y.RelCenter(), dx, dy, rx, ry, xScale, yScale);
// We can't use DTA_HUDRules since it forces a width and height.
// Translation: No high res.
bool xright = *x < 0 && !x.RelCenter();
bool ybot = *y < 0 && !y.RelCenter();

View file

@ -431,6 +431,7 @@ void DBaseStatusBar::CallTick()
GlobalVMStack.Call(func, params, countof(params), nullptr, 0);
}
else Tick();
mugshot.Tick(CPlayer);
}
//---------------------------------------------------------------------------
@ -1023,6 +1024,7 @@ void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone, b
VMValue params[] = { (DObject*)this, &statestring, waitTillDone, reset };
GlobalVMStack.Call(func, params, countof(params), nullptr, 0);
}
mugshot.SetState(stateName, waitTillDone, reset);
}
//---------------------------------------------------------------------------
@ -1052,7 +1054,18 @@ void DBaseStatusBar::DrawTopStuff (EHudState state)
DTA_CleanNoMove, true, TAG_DONE);
}
DrawPowerups ();
if (state != HUD_AltHud)
{
auto saved = fullscreenOffsets;
fullscreenOffsets = true;
IFVIRTUAL(DBaseStatusBar, DrawPowerups)
{
VMValue params[] = { (DObject*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0);
}
fullscreenOffsets = saved;
}
if (automapactive && !viewactive)
{
DrawMessages (HUDMSGLayer_OverMap, (state == HUD_StatusBar) ? gST_Y : SCREENHEIGHT);
@ -1068,46 +1081,6 @@ void DBaseStatusBar::DrawTopStuff (EHudState state)
}
}
//---------------------------------------------------------------------------
//
// DrawPowerups
//
//---------------------------------------------------------------------------
void DBaseStatusBar::DrawPowerups ()
{
// Each icon gets a 32x32 block to draw itself in.
int x, y;
AInventory *item;
const int yshift = SmallFont->GetHeight();
x = -20;
y = 17
+ (ST_IsTimeVisible() ? yshift : 0)
+ (ST_IsLatencyVisible() ? yshift : 0);
for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
{
IFVIRTUALPTR(item, AInventory, DrawPowerup)
{
VMValue params[3] = { item, x, y };
VMReturn ret;
int retv;
ret.IntAt(&retv);
GlobalVMStack.Call(func, params, 3, &ret, 1);
if (retv)
{
x -= POWERUPICONSIZE;
if (x < -POWERUPICONSIZE * 5)
{
x = -20;
y += POWERUPICONSIZE * 2;
}
}
}
}
}
//---------------------------------------------------------------------------
//
// BlendView
@ -1225,6 +1198,7 @@ void DBaseStatusBar::NewGame ()
VMValue params[] = { (DObject*)this };
GlobalVMStack.Call(func, params, countof(params), nullptr, 0);
}
mugshot.Reset();
}
void DBaseStatusBar::ShowPop(int pop)
@ -1426,7 +1400,6 @@ void DBaseStatusBar::DrawGraphic(FTextureID texture, bool animate, double x, dou
// Todo: Allow other scaling values, too.
if (Scaled)
{
y += RelTop - VerticalResolution;
screen->VirtualToRealCoords(x, y, width, height, HorizontalResolution, VerticalResolution, true, true);
}
}
@ -1517,8 +1490,135 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d
x -= static_cast<int> ((spacing)* cstring.Len()) / 2;
break;
}
const uint8_t* str = (const uint8_t*)cstring.GetChars();
const EColorRange boldTranslation = EColorRange(translation ? translation - 1 : NumTextColors - 1);
int fontcolor = translation;
double orgx = 0, orgy = 0;
if (fullscreenOffsets)
{
if (hud_scale)
{
shadowX *= (int)cleanScale.X;
shadowY *= (int)cleanScale.Y;
}
switch (screenalign & HMASK)
{
default: orgx = 0; break;
case HCENTER: orgx = screen->GetWidth() / 2; break;
case RIGHT: orgx = screen->GetWidth(); break;
}
switch (screenalign & VMASK)
{
default: orgy = 0; break;
case VCENTER: orgy = screen->GetHeight() / 2; break;
case BOTTOM: orgy = screen->GetHeight(); break;
}
if (screenalign == (RIGHT | TOP) && vid_fps) orgy += 10;
}
int ch;
while (ch = *str++, ch != '\0')
{
if (ch == ' ')
{
x += monospaced ? spacing : font->GetSpaceWidth() + spacing;
continue;
}
else if (ch == TEXTCOLOR_ESCAPE)
{
EColorRange newColor = V_ParseFontColor(str, translation, boldTranslation);
if (newColor != CR_UNDEFINED)
fontcolor = newColor;
continue;
}
int width;
FTexture* c = font->GetChar((unsigned char)ch, &width);
if (c == NULL) //missing character.
{
continue;
}
if (!monospaced) //If we are monospaced lets use the offset
x += (c->LeftOffset + 1); //ignore x offsets since we adapt to character size
double rx, ry, rw, rh;
rx = x + drawOffset.X;
ry = y + drawOffset.Y;
rw = c->GetScaledWidthDouble();
rh = c->GetScaledHeightDouble();
if (monospaced)
{
// align the character in the monospaced cell according to the general alignment to ensure that it gets positioned properly
// (i.e. right aligned text aligns to the right edge of the character and not the empty part of the cell.)
switch (align)
{
default:
break;
case ALIGN_CENTER:
rx -= (spacing) / 2;
break;
case ALIGN_RIGHT:
rx -= spacing;
break;
}
}
if (!fullscreenOffsets)
{
rx += ST_X;
ry += ST_Y;
// Todo: Allow other scaling values, too.
if (Scaled)
{
screen->VirtualToRealCoords(rx, ry, rw, rh, HorizontalResolution, VerticalResolution, true);
}
}
else
{
if (hud_scale)
{
rx *= cleanScale.X;
ry *= cleanScale.Y;
rw *= cleanScale.X;
rh *= cleanScale.Y;
}
rx += orgx;
ry += orgy;
}
// This is not really such a great way to draw shadows because they can overlap with previously drawn characters.
// This may have to be changed to draw the shadow text up front separately.
if (shadowX != 0 || shadowY != 0)
{
screen->DrawChar(font, CR_UNTRANSLATED, rx + shadowX, ry + shadowY, ch,
DTA_DestWidthF, rw,
DTA_DestHeightF, rh,
DTA_Alpha, (Alpha * HR_SHADOW),
DTA_FillColor, 0,
TAG_DONE);
}
screen->DrawChar(font, fontcolor, rx, ry, ch,
DTA_DestWidthF, rw,
DTA_DestHeightF, rh,
DTA_Alpha, Alpha,
TAG_DONE);
if (!monospaced)
x += width + spacing - (c->LeftOffset + 1);
else
x += spacing;
}
}
DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawString)
{
PARAM_SELF_PROLOGUE(DBaseStatusBar);
@ -1527,7 +1627,7 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, DrawString)
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(alpha);
PARAM_BOOL(trans);
PARAM_INT(trans);
PARAM_INT(ialign);
PARAM_INT(salign);
PARAM_INT_DEF(spacing);
@ -1636,3 +1736,64 @@ DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetGlobalACSArrayString)
PARAM_INT(index);
ACTION_RETURN_STRING(FBehavior::StaticLookupString(ACS_GlobalArrays[arrayno][index]));
}
DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetGlobalACSValue)
{
PARAM_PROLOGUE;
PARAM_INT(index);
ACTION_RETURN_INT(ACS_GlobalVars[index]);
}
DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetGlobalACSArrayValue)
{
PARAM_PROLOGUE;
PARAM_INT(arrayno);
PARAM_INT(index);
ACTION_RETURN_INT(ACS_GlobalArrays[arrayno][index]);
}
enum ENumFlags
{
FNF_FILLZEROS,
FNF_WHENNOTZERO,
};
DEFINE_ACTION_FUNCTION(DBaseStatusBar, FormatNumber)
{
PARAM_PROLOGUE;
PARAM_INT(number);
PARAM_INT(minsize);
PARAM_INT(maxsize);
PARAM_INT(flags);
PARAM_STRING_DEF(prefix);
static int maxvals[] = { 1, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999 };
if (number == 0 && (flags & FNF_WHENNOTZERO)) ACTION_RETURN_STRING("");
if (maxsize > 0 && maxsize < 10)
{
number = clamp(number, -maxvals[maxsize - 1], maxvals[maxsize]);
}
FString fmt;
if (minsize <= 1) fmt.Format("%s%d", prefix.GetChars(), number);
else if (flags & FNF_FILLZEROS) fmt.Format("%s%0*d", prefix.GetChars(), minsize, number);
else fmt.Format("%s%*d", prefix.GetChars(), minsize, number);
ACTION_RETURN_STRING(fmt);
}
DEFINE_ACTION_FUNCTION(DBaseStatusBar, ReceivedWeapon)
{
PARAM_SELF_PROLOGUE(DBaseStatusBar);
self->mugshot.Grin();
return 0;
}
DEFINE_ACTION_FUNCTION(DBaseStatusBar, GetMugshot)
{
PARAM_SELF_PROLOGUE(DBaseStatusBar);
PARAM_POINTER(player, player_t);
PARAM_STRING(def_face);
PARAM_INT(accuracy);
PARAM_INT_DEF(stateflags);
auto tex = self->mugshot.GetFace(player, def_face, accuracy, (FMugShot::StateFlags)stateflags);
ACTION_RETURN_INT(tex ? tex->id.GetIndex() : -1);
}

View file

@ -490,7 +490,7 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
mSpriteU[1] = mSpriteV[1] = 1.f;
FTexture *basetex = (tx->bWarped && gl.legacyMode)? tx : tx->GetRedirect(false);
// allow the redirect only if the textute is not expanded or the scale matches.
// allow the redirect only if the texture is not expanded or the scale matches.
if (!expanded || (tx->Scale.X == basetex->Scale.X && tx->Scale.Y == basetex->Scale.Y))
{
mBaseLayer = ValidateSysTexture(basetex, expanded);

View file

@ -287,6 +287,23 @@ bool PolyCull::GetAnglesForLine(double x1, double y1, double x2, double y2, angl
return !IsSegmentCulled(angle1, angle2);
}
void PolyCull::MarkViewFrustum()
{
// Clips things outside the viewing frustum.
auto &viewpoint = PolyRenderer::Instance()->Viewpoint;
auto &viewwindow = PolyRenderer::Instance()->Viewwindow;
double tilt = fabs(viewpoint.Angles.Pitch.Degrees);
if (tilt > 46.0) // If the pitch is larger than this you can look all around
return;
double floatangle = 2.0 + (45.0 + ((tilt / 1.9)))*viewpoint.FieldOfView.Degrees*48.0 / AspectMultiplier(viewwindow.WidescreenRatio) / 90.0;
angle_t a1 = DAngle(floatangle).BAMs();
if (a1 < ANGLE_180)
{
MarkSegmentCulled(AngleToPseudo(viewpoint.Angles.Yaw.BAMs() + a1), AngleToPseudo(viewpoint.Angles.Yaw.BAMs() - a1));
}
}
//-----------------------------------------------------------------------------
//
// ! Returns the pseudoangle between the line p1 to (infinity, p1.y) and the
@ -320,3 +337,16 @@ angle_t PolyCull::PointToPseudoAngle(double x, double y)
return xs_Fix<30>::ToFix(result);
}
}
angle_t PolyCull::AngleToPseudo(angle_t ang)
{
double vecx = cos(ang * M_PI / ANGLE_180);
double vecy = sin(ang * M_PI / ANGLE_180);
double result = vecy / (fabs(vecx) + fabs(vecy));
if (vecx < 0)
{
result = 2.f - result;
}
return xs_Fix<30>::ToFix(result);
}

View file

@ -35,6 +35,7 @@ public:
void MarkSegmentCulled(angle_t angle1, angle_t angle2);
bool IsSegmentCulled(angle_t angle1, angle_t angle2) const;
void InvertSegments();
void MarkViewFrustum();
std::vector<subsector_t *> PvsSectors;
double MaxCeilingHeight = 0.0;
@ -64,4 +65,5 @@ private:
Vec4f PortalClipPlane;
static angle_t PointToPseudoAngle(double x, double y);
static angle_t AngleToPseudo(angle_t ang);
};

View file

@ -73,6 +73,7 @@ void RenderPolyScene::Render(int portalDepth)
ClearBuffers();
if (!PortalSegmentsAdded)
Cull.ClearSolidSegments();
Cull.MarkViewFrustum();
Cull.CullScene(WorldToClip, PortalPlane);
Cull.ClearSolidSegments();
RenderSectors();
@ -124,6 +125,8 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub)
}
}
RenderMemory &memory = PolyRenderer::Instance()->FrameMemory;
bool mainBSP = ((unsigned int)(sub->Index()) < level.subsectors.Size());
if (mainBSP)
{
@ -131,7 +134,7 @@ void RenderPolyScene::RenderSubsector(subsector_t *sub)
for (int i = ParticlesInSubsec[subsectorIndex]; i != NO_PARTICLE; i = Particles[i].snext)
{
particle_t *particle = Particles + i;
TranslucentObjects.push_back({ particle, sub, subsectorDepth });
TranslucentObjects.push_back(memory.NewObject<PolyTranslucentObject>(particle, sub, subsectorDepth));
}
}
@ -146,7 +149,7 @@ void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, const DVe
subsector_t *sub = &level.subsectors[0];
auto it = SubsectorDepths.find(sub);
if (it != SubsectorDepths.end())
TranslucentObjects.push_back({ thing, sub, it->second, sortDistance, 0.0f, 1.0f });
TranslucentObjects.push_back(PolyRenderer::Instance()->FrameMemory.NewObject<PolyTranslucentObject>(thing, sub, it->second, sortDistance, 0.0f, 1.0f));
}
else
{
@ -187,7 +190,7 @@ void RenderPolyScene::RenderSprite(AActor *thing, double sortDistance, DVector2
auto it = SubsectorDepths.find(sub);
if (it != SubsectorDepths.end())
TranslucentObjects.push_back({ thing, sub, it->second, sortDistance, (float)t1, (float)t2 });
TranslucentObjects.push_back(PolyRenderer::Instance()->FrameMemory.NewObject<PolyTranslucentObject>(thing, sub, it->second, sortDistance, (float)t1, (float)t2));
}
void RenderPolyScene::RenderLine(subsector_t *sub, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth)
@ -347,29 +350,29 @@ void RenderPolyScene::RenderTranslucent(int portalDepth)
}
}
std::stable_sort(TranslucentObjects.begin(), TranslucentObjects.end());
std::stable_sort(TranslucentObjects.begin(), TranslucentObjects.end(), [](auto a, auto b) { return *a < *b; });
for (auto it = TranslucentObjects.rbegin(); it != TranslucentObjects.rend(); ++it)
{
auto &obj = *it;
if (obj.particle)
PolyTranslucentObject *obj = *it;
if (obj->particle)
{
RenderPolyParticle spr;
spr.Render(WorldToClip, PortalPlane, obj.particle, obj.sub, obj.subsectorDepth, StencilValue + 1);
spr.Render(WorldToClip, PortalPlane, obj->particle, obj->sub, obj->subsectorDepth, StencilValue + 1);
}
else if (!obj.thing)
else if (!obj->thing)
{
obj.wall.Render(WorldToClip, PortalPlane, Cull);
obj->wall.Render(WorldToClip, PortalPlane, Cull);
}
else if ((obj.thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
else if ((obj->thing->renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
{
RenderPolyWallSprite wallspr;
wallspr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1);
wallspr.Render(WorldToClip, PortalPlane, obj->thing, obj->sub, obj->subsectorDepth, StencilValue + 1);
}
else
{
RenderPolySprite spr;
spr.Render(WorldToClip, PortalPlane, obj.thing, obj.sub, obj.subsectorDepth, StencilValue + 1, obj.SpriteLeft, obj.SpriteRight);
spr.Render(WorldToClip, PortalPlane, obj->thing, obj->sub, obj->subsectorDepth, StencilValue + 1, obj->SpriteLeft, obj->SpriteRight);
}
}
}

View file

@ -97,7 +97,7 @@ private:
uint32_t NextSubsectorDepth = 0;
std::set<sector_t *> SeenSectors;
std::unordered_map<subsector_t *, uint32_t> SubsectorDepths;
std::vector<PolyTranslucentObject> TranslucentObjects;
std::vector<PolyTranslucentObject *> TranslucentObjects;
std::vector<std::unique_ptr<PolyDrawSectorPortal>> SectorPortals;
std::vector<std::unique_ptr<PolyDrawLinePortal>> LinePortals;

View file

@ -37,7 +37,7 @@
EXTERN_CVAR(Bool, r_drawmirrors)
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals)
{
PolyDrawLinePortal *polyportal = nullptr;
if (line->backsector == nullptr && line->linedef && line->sidedef == line->linedef->sidedef[0] && (line->linedef->special == Line_Mirror && r_drawmirrors))
@ -153,7 +153,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP
FTexture *midtex = TexMan(line->sidedef->GetTexture(side_t::mid), true);
if (midtex && midtex->UseType != FTexture::TEX_Null)
translucentWallsOutput.push_back({ wall });
translucentWallsOutput.push_back(PolyRenderer::Instance()->FrameMemory.NewObject<PolyTranslucentObject>(wall));
if (polyportal)
{
@ -165,7 +165,7 @@ bool RenderPolyWall::RenderLine(const TriMatrix &worldToClip, const Vec4f &clipP
return polyportal != nullptr;
}
void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject> &translucentWallsOutput)
void RenderPolyWall::Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput)
{
double frontceilz1 = fakeFloor->top.plane->ZatPoint(line->v1);
double frontfloorz1 = fakeFloor->bottom.plane->ZatPoint(line->v1);

View file

@ -32,8 +32,8 @@ class Vec4f;
class RenderPolyWall
{
public:
static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject> &translucentWallsOutput);
static bool RenderLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, std::vector<PolyTranslucentObject*> &translucentWallsOutput, std::vector<std::unique_ptr<PolyDrawLinePortal>> &linePortals);
static void Render3DFloorLine(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull, seg_t *line, sector_t *frontsector, uint32_t subsectorDepth, uint32_t stencilValue, F3DFloor *fakeFloor, std::vector<PolyTranslucentObject*> &translucentWallsOutput);
void SetCoords(const DVector2 &v1, const DVector2 &v2, double ceil1, double floor1, double ceil2, double floor2);
void Render(const TriMatrix &worldToClip, const Vec4f &clipPlane, PolyCull &cull);

View file

@ -144,16 +144,6 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture)
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, DrawHUDTexture)
{
PARAM_PROLOGUE;
PARAM_INT(texid);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
screen->DrawTexture(TexMan(FSetTextureID(texid)), x, y, DTA_HUDRules, HUD_Normal, TAG_END);
return 0;
}
void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms)
{
#ifndef NO_SWRENDER
@ -220,6 +210,8 @@ bool DCanvas::SetTextureParms(DrawParms *parms, FTexture *img, double xx, double
case DTA_HUDRules:
case DTA_HUDRulesC:
{
// Note that this has been deprecated because it cannot intelligently decide what scale
// actually needs to be used in conjunction with the active status bar.
bool xright = parms->x < 0;
bool ybot = parms->y < 0;

View file

@ -61,6 +61,35 @@ INDEXFONT_DOOM
9 STYSNUM9
}
INDEXFONT_STRIFE_YELLOW
{
% INVFONY%
0 INVFONY0
1 INVFONY1
2 INVFONY2
3 INVFONY3
4 INVFONY4
5 INVFONY5
6 INVFONY6
7 INVFONY7
8 INVFONY8
9 INVFONY9
}
INDEXFONT_STRIFE_GREEN
{
% INVFONG%
0 INVFONG0
1 INVFONG1
2 INVFONG2
3 INVFONG3
4 INVFONG4
5 INVFONG5
6 INVFONG6
7 INVFONG7
8 INVFONG8
9 INVFONG9
}
// Doom and Chex intermissions use special text glyphs. The Raven and Strife
// games just use the standard big font.

View file

@ -159,13 +159,18 @@ struct Screen native
native static void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1);
native static void Dim(Color col, double amount, int x, int y, int w, int h);
native static void DrawHUDTexture(TextureID tex, double x, double y);
native static vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...);
native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...);
native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
native static void DrawFrame(int x, int y, int w, int h);
native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true);
native static double GetAspectRatio();
// This is a leftover of the abandoned Inventory.DrawPowerup method.
deprecated("2.5") static ui void DrawHUDTexture(TextureID tex, double x, double y)
{
statusBar.DrawTexture(tex, (x, y), true, 1., BaseStatusBar.ALIGN_TOP|BaseStatusBar.ALIGN_RIGHT, (32, 32), BaseStatusBar.ALIGN_CENTER_BOTTOM);
}
}
struct Font native

View file

@ -820,13 +820,28 @@ class Inventory : Actor native
//
// AInventory :: DrawPowerup
//
// Gives self item a chance to draw a special status indicator on the screen.
// Returns false if it didn't draw anything.
// This has been deprecated because it is not how this should be done
// Use GetPowerupIcon instead!
//
//===========================================================================
virtual ui version("2.4") bool DrawPowerup(int x, int y) { return false; }
//===========================================================================
//
// AInventory :: GetPowerupIcon
//
// Returns the icon that should be drawn for an active powerup.
//
//===========================================================================
virtual clearscope version("2.5") TextureID GetPowerupIcon() const
{
TextureID id;
id.SetInvalid();
return id;
}
//===========================================================================
//
// AInventory :: AbsorbDamage

View file

@ -273,17 +273,9 @@ class Powerup : Inventory
//
//===========================================================================
override bool DrawPowerup (int x, int y)
override TextureID GetPowerupIcon()
{
if (!Icon.isValid())
{
return false;
}
if (!isBlinking())
{
screen.DrawHUDTexture(Icon, x, y);
}
return true;
return Icon;
}
//===========================================================================
@ -292,7 +284,7 @@ class Powerup : Inventory
//
//===========================================================================
virtual bool isBlinking() const
virtual clearscope bool isBlinking() const
{
return (EffectTics <= BLINKTHRESHOLD && (EffectTics & 8) && !bNoScreenBlink);
}
@ -941,7 +933,7 @@ class PowerFlight : Powerup
+INVENTORY.HUBPOWER
}
ui bool HitCenterFrame;
clearscope bool HitCenterFrame;
//===========================================================================
//
@ -1011,51 +1003,47 @@ class PowerFlight : Powerup
//
//===========================================================================
override bool DrawPowerup (int x, int y)
override TextureID GetPowerupIcon ()
{
// If this item got a valid icon use that instead of the default spinning wings.
if (Icon.isValid())
{
return Super.DrawPowerup(x, y);
return Icon;
}
if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16))
{
TextureID picnum = TexMan.CheckForTexture ("SPFLY0", TexMan.Type_MiscPatch);
int frame = (level.time/3) & 15;
if (!picnum.isValid())
{
return false;
return picnum;
}
if (Owner.bNoGravity)
{
if (HitCenterFrame && (frame != 15 && frame != 0))
{
screen.DrawHUDTexture (picnum + 15, x, y);
return picnum + 15;
}
else
{
screen.DrawHUDTexture (picnum + frame, x, y);
HitCenterFrame = false;
return picnum + frame;
}
}
else
{
if (!HitCenterFrame && (frame != 15 && frame != 0))
{
screen.DrawHUDTexture (picnum + frame, x, y);
HitCenterFrame = false;
return picnum + frame;
}
else
{
screen.DrawHUDTexture (picnum+15, x, y);
HitCenterFrame = true;
return picnum+15;
}
}
}
return true;
}
}

View file

@ -1,4 +1,21 @@
struct MugShot
{
enum StateFlags
{
STANDARD = 0x0,
XDEATHFACE = 0x1,
ANIMATEDGODMODE = 0x2,
DISABLEGRIN = 0x4,
DISABLEOUCH = 0x8,
DISABLEPAIN = 0x10,
DISABLERAMPAGE = 0x20,
CUSTOM = 0x40,
}
}
class BaseStatusBar native ui
{
enum EPop
@ -46,19 +63,24 @@ class BaseStatusBar native ui
DI_SKIPREADY = 0x8,
DI_ALTICONFIRST = 0x10,
DI_TRANSLATABLE = 0x20,
DI_FORCESCALE = 0x40
DI_FORCESCALE = 0x40,
DI_DIM = 0x80,
};
enum IconType
{
PLAYERICON = 1000,
AMMO1,
AMMO2,
ARMOR,
WEAPONICON,
SIGIL,
WEAPONSLOT,
SELECTEDINVENTORYICON,
ITYPE_PLAYERICON = 1000,
ITYPE_AMMO1,
ITYPE_AMMO2,
ITYPE_ARMOR,
ITYPE_WEAPON,
ITYPE_SIGIL,
ITYPE_WEAPONSLOT,
ITYPE_SELECTEDINVENTORY,
}
enum HexArmorType
{
HEXENARMOR_ARMOR,
HEXENARMOR_SHIELD,
HEXENARMOR_HELM,
@ -67,35 +89,36 @@ class BaseStatusBar native ui
enum EAlign
{
TOP = 0,
VCENTER = 1,
BOTTOM = 2,
VOFFSET = 3,
VMASK = 3,
ALIGN_TOP = 0,
ALIGN_VCENTER = 1,
ALIGN_BOTTOM = 2,
ALIGN_VOFFSET = 3,
ALIGN_VMASK = 3,
LEFT = 0,
HCENTER = 4,
RIGHT = 8,
HOFFSET = 12,
HMASK = 12,
ALIGN_LEFT = 0,
ALIGN_HCENTER = 4,
ALIGN_RIGHT = 8,
ALIGN_HOFFSET = 12,
ALIGN_HMASK = 12,
CENTER = VCENTER|HCENTER,
CENTER_BOTTOM = BOTTOM|HCENTER
ALIGN_CENTER = ALIGN_VCENTER|ALIGN_HCENTER,
ALIGN_CENTER_BOTTOM = ALIGN_BOTTOM|ALIGN_HCENTER,
ALIGN_OFFSETS = ALIGN_HOFFSET|ALIGN_VOFFSET
};
enum ETextAlign
{
ALIGN_LEFT = 0,
ALIGN_CENTER = 1,
ALIGN_RIGHT = 2
TEXT_LEFT = 0,
TEXT_CENTER = 1,
TEXT_RIGHT = 2
};
enum SBGameModes
{
SINGLEPLAYER = 0x1,
COOPERATIVE = 0x2,
DEATHMATCH = 0x4,
TEAMGAME = 0x8
GAMEMODE_SINGLEPLAYER = 0x1,
GAMEMODE_COOPERATIVE = 0x2,
GAMEMODE_DEATHMATCH = 0x4,
GAMEMODE_TEAMGAME = 0x8
};
enum AmmoModes
@ -112,8 +135,15 @@ class BaseStatusBar native ui
HUD_HorizCenter
}
enum ENumFlags
{
FNF_FILLZEROS,
FNF_WHENNOTZERO,
}
const XHAIRSHRINKSIZE =(1./18);
const XHAIRPICKUPSIZE = (2+XHAIRSHRINKSIZE);
const POWERUPICONSIZE = 32;
native int ST_X, ST_Y;
@ -143,22 +173,25 @@ class BaseStatusBar native ui
native virtual void Tick ();
native virtual void Draw (int state, double TicFrac);
native virtual void ScreenSizeChanged ();
native virtual clearscope void ReceivedWeapon (Weapon weapn);
virtual void FlashItem (class<Inventory> itemtype) {}
virtual void AttachToPlayer (PlayerInfo player) { CPlayer = player; }
virtual void FlashCrosshair () { CrosshairSize = XHAIRPICKUPSIZE; }
virtual void NewGame () {}
virtual void ShowPop (int popnum) { ShowLog = (popnum == POP_Log && !ShowLog); }
virtual clearscope void ReceivedWeapon (Weapon weapn) {}
virtual bool MustDrawLog(int state) { return true; }
virtual void SetMugShotState (String state_name, bool wait_till_done=false, bool reset=false) {}
native void RefreshBackground () const;
native TextureID GetMugshot(PlayerInfo player, String default_face, int accuracy, int stateflags=MugShot.STANDARD);
// These functions are kept native solely for performance reasons. They get called repeatedly and can drag down performance easily if they get too slow.
native Inventory ValidateInvFirst (int numVisible) const;
native static TextureID, bool GetInventoryIcon(Inventory item, int flags);
native void DrawGraphic(TextureID texture, bool animate, Vector2 pos, double Alpha, bool translatable, bool dim, int imgAlign, int screenalign, bool alphamap, Vector2 box);
native void DrawString(Font font, String string, Vector2 pos , double Alpha, int translation, int align, int screenalign, int spacing=0, bool monospaced = false, int shadowX=0, int shadowY=0, int wrapwidth = -1, int linespacing = 4);
native static String FormatNumber(int number, int minsize, int maxsize, int format, String prefix = "");
//============================================================================
@ -247,6 +280,70 @@ class BaseStatusBar native ui
// These cannot be done in ZScript.
native String GetGlobalACSString(int index);
native String GetGlobalACSArrayString(int arrayno, int index);
native int GetGlobalACSValue(int index);
native int GetGlobalACSArrayValue(int arrayno, int index);
//============================================================================
//
// Convenience functions to retrieve some numbers
//
//============================================================================
int GetArmorAmount()
{
let armor = CPlayer.mo.FindInventory("BasicArmor");
return armor? armor.Amount : 0;
}
int GetMaxAmount(class<Inventory> item)
{
let it = CPlayer.mo.FindInventory(item);
return it? it.MaxAmount : GetDefaultByType(item).MaxAmount;
}
int GetArmorSavePercent()
{
double add = 0;
let harmor = HexenArmor(CPlayer.mo.FindInventory("HexenArmor"));
if(harmor != NULL)
{
add = harmor.Slots[0] + harmor.Slots[1] + harmor.Slots[2] + harmor.Slots[3] + harmor.Slots[4];
}
//Hexen counts basic armor also so we should too.
let armor = BasicArmor(CPlayer.mo.FindInventory("BasicArmor"));
if(armor != NULL)
{
add += armor.SavePercent * 100;
}
return int(add);
}
// Note that this retrieves the value in tics, not seconds like the equivalent SBARINFO function.
// The idea is to let the caller decide what to do with it instead of destroying accuracy here.
int GetAirTime()
{
if(CPlayer.mo.waterlevel < 3)
return level.airsupply;
else
return max(CPlayer.air_finished - level.time, 0);
}
int GetSelectedInventoryAmount()
{
if(CPlayer.mo.InvSel != NULL) return CPlayer.mo.InvSel.Amount;
return 0;
}
int GetKeyCount()
{
int num = 0;
for(Inventory item = CPlayer.mo.Inv;item != NULL;item = item.Inv)
{
if(item is "Key") num++;
}
return num;
}
//============================================================================
//
// various checker functions, based on SBARINFOs condition nodes.
@ -261,10 +358,10 @@ class BaseStatusBar native ui
bool CheckGameMode(int ValidModes)
{
return (!multiplayer && (ValidModes & SINGLEPLAYER)) ||
(deathmatch && (ValidModes & DEATHMATCH)) ||
(multiplayer && !deathmatch && (ValidModes & COOPERATIVE)) ||
(teamplay && (ValidModes & TEAMGAME));
return (!multiplayer && (ValidModes & GAMEMODE_SINGLEPLAYER)) ||
(deathmatch && (ValidModes & GAMEMODE_DEATHMATCH)) ||
(multiplayer && !deathmatch && (ValidModes & GAMEMODE_COOPERATIVE)) ||
(teamplay && (ValidModes & GAMEMODE_TEAMGAME));
}
//============================================================================
@ -416,6 +513,35 @@ class BaseStatusBar native ui
}
//---------------------------------------------------------------------------
//
// DrawPowerups
//
//---------------------------------------------------------------------------
virtual void DrawPowerups ()
{
// The AltHUD specific adjustments have been removed here, because the AltHUD uses its own variant of this function
// that can obey AltHUD rules - which this cannot.
Vector2 pos = (-20, POWERUPICONSIZE * 5 / 4);
double maxpos = screen.GetWidth() / 2;
for (let item = CPlayer.mo.Inv; item != NULL; item = item.Inv)
{
let icon = item.GetPowerupIcon();
if (icon.IsValid())
{
// Each icon gets a 32x32 block.
DrawTexture(icon, pos, true, 1.0, ALIGN_TOP|ALIGN_RIGHT, (POWERUPICONSIZE, POWERUPICONSIZE), ALIGN_CENTER_BOTTOM);
pos.x -= POWERUPICONSIZE;
if (pos.x < -maxpos)
{
pos.x = -20;
pos.y += POWERUPICONSIZE * 3 / 2;
}
}
}
}
//============================================================================
//
// draw stuff
@ -436,7 +562,7 @@ class BaseStatusBar native ui
//
//============================================================================
void DrawTexture(TextureID texture, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0, Vector2 scale = (1., 1.) )
void DrawTexture(TextureID texture, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0, Vector2 scale = (1., 1.) )
{
if (!texture.IsValid()) return; // nothing to draw
@ -467,13 +593,12 @@ class BaseStatusBar native ui
else scale1 = min(scale1, scale2);
boxsize = texsize * scale1;
screenAlign = TOP|LEFT; // anything else makes no sense here.
}
else
{
boxsize = texsize;
}
DrawGraphic(texture, animated, pos, Alpha, !!(flags & DI_TRANSLATABLE), false, itemAlign, screenAlign, false, boxsize);
DrawGraphic(texture, animated, pos, Alpha, !!(flags & DI_TRANSLATABLE), !!(flags & DI_DIM), itemAlign, screenAlign, false, boxsize);
}
//============================================================================
@ -482,7 +607,7 @@ class BaseStatusBar native ui
//
//============================================================================
void DrawImage(String imagename, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0, Vector2 scale = (1., 1.) )
void DrawImage(String imagename, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0, Vector2 scale = (1., 1.) )
{
let tex = TexMan.CheckForTexture(imagename, TexMan.TYPE_MiscPatch);
DrawTexture(tex, pos, animated, screenalign, alpha, boxsize, itemAlign, flags, scale);
@ -494,36 +619,36 @@ class BaseStatusBar native ui
//
//============================================================================
void DrawIcon(int icontype, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0)
void DrawIcon(int icontype, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0)
{
TextureID texture;
Vector2 applyscale = (1, 1);
Inventory atype1, atype2;
switch (icontype)
{
case PLAYERICON:
case ITYPE_PLAYERICON:
texture = CPlayer.mo.ScoreIcon;
break;
case AMMO1:
case AMMO2:
case ITYPE_AMMO1:
case ITYPE_AMMO2:
[atype1, atype2] = GetCurrentAmmo();
[texture, applyscale] = GetIcon(icontype == AMMO1? atype1 : atype2, flags, true);
[texture, applyscale] = GetIcon(icontype == ITYPE_AMMO1? atype1 : atype2, flags, true);
break;
case ARMOR:
case ITYPE_ARMOR:
[texture, applyscale] = GetIcon(CPlayer.mo.FindInventory("BasicArmor"), flags, false);
break;
case WEAPONICON:
case ITYPE_WEAPON:
[texture, applyscale] = GetIcon(CPlayer.ReadyWeapon, flags, false);
break;
case SIGIL:
case ITYPE_SIGIL:
[texture, applyscale] = GetIcon(CPlayer.mo.FindInventory("Sigil"), flags, false);
break;
case SELECTEDINVENTORYICON:
case ITYPE_SELECTEDINVENTORY:
if (CPlayer.mo.InvSel != NULL)
texture = CPlayer.mo.InvSel.Icon;
break;
@ -537,7 +662,7 @@ class BaseStatusBar native ui
//
//============================================================================
void DrawHexenArmor(int armortype, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0)
void DrawHexenArmor(int armortype, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0)
{
let harmor = HexenArmor(statusBar.CPlayer.mo.FindInventory("HexenArmor"));
if (harmor != NULL)
@ -561,7 +686,7 @@ class BaseStatusBar native ui
//
//============================================================================
void DrawInventoryIcon(class<Inventory> item, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = TOP|LEFT, Vector2 boxsize = (-1, -1), int itemAlign = TOP|LEFT, int flags = 0)
void DrawInventoryIcon(class<Inventory> item, String image, Vector2 pos, bool animated = false, double alpha = 1.0, int screenalign = ALIGN_TOP|ALIGN_LEFT, Vector2 boxsize = (-1, -1), int itemAlign = ALIGN_TOP|ALIGN_LEFT, int flags = 0)
{
let texture = GetDefaultByType(item).Icon;
if (texture.IsValid())
@ -569,4 +694,85 @@ class BaseStatusBar native ui
DrawTexture(texture, pos, animated, screenalign, alpha, boxsize, itemAlign, flags);
}
}
}
//============================================================================
//
// a generic value interpolator for status bar elements that can change
// gradually to their new value.
//
//============================================================================
class LinearValueInterpolator : Object
{
int mCurrentValue;
int mMaxChange;
static LinearValueInterpolator Create(int startval, int maxchange)
{
let v = new("LinearValueInterpolator");
v.mCurrentValue = startval;
v.mMaxChange = maxchange;
return v;
}
// This must be called peroiodically in the status bar's Tick function.
// Do not call this in the Draw function because that may skip some frames!
void Update(int destvalue)
{
if (mCurrentValue > destvalue)
{
mCurrentValue = max(destvalue, mCurrentValue - mMaxChange);
}
else
{
mCurrentValue = min(destvalue, mCurrentValue + mMaxChange);
}
}
// This must be called in the draw function to retrieve the value for output.
int GetValue()
{
return mCurrentValue;
}
}
class DynamicValueInterpolator : Object
{
int mCurrentValue;
int mMinChange;
double mChangeFactor;
static DynamicValueInterpolator Create(int startval, double changefactor, int minchange)
{
let v = new("DynamicValueInterpolator");
v.mCurrentValue = startval;
v.mMinChange = minchange;
v.mChangeFactor = changefactor;
return v;
}
// This must be called peroiodically in the status bar's Tick function.
// Do not call this in the Draw function because that may skip some frames!
void Update(int destvalue)
{
int diff = int(max(abs(destvalue - mCurrentValue) * mChangeFactor, mMinChange));
if (mCurrentValue > destvalue)
{
mCurrentValue = max(destvalue, mCurrentValue - diff);
}
else
{
mCurrentValue = min(destvalue, mCurrentValue + diff);
}
}
// This must be called in the draw function to retrieve the value for output.
int GetValue()
{
return mCurrentValue;
}
}

View file

@ -48,7 +48,6 @@ class StrifeStatusBar : BaseStatusBar
imgARM1,
imgARM2,
imgNEGATIVE,
imgINumbers = imgFONG0,
};
TextureID Images[imgNEGATIVE + 1];
@ -79,18 +78,21 @@ class StrifeStatusBar : BaseStatusBar
if (state == HUD_StatusBar)
{
fullscreenoffsets = false;
DrawMainBar (TicFrac);
}
else
{
if (state == HUD_Fullscreen)
{
fullscreenoffsets = true;
DrawFullScreenStuff ();
}
// Draw pop screen (log, keys, and status)
if (CurrentPop != POP_None && PopHeight < 0)
{
fullscreenoffsets = false;
DrawPopScreen (screen.GetHeight(), TicFrac);
}
}
@ -302,11 +304,11 @@ class StrifeStatusBar : BaseStatusBar
DrawPopScreen (Scaled ? (ST_Y - 8) * screen.GetHeight() / 200 : ST_Y - 8, TicFrac);
}
DrawImage (Images[imgINVBACK], 0, 0);
DrawImage (Images[imgINVTOP], 0, -8);
DrawTexture(Images[imgINVBACK], (0, 0), true, 1.0, itemAlign:ALIGN_OFFSETS);
DrawTexture(Images[imgINVTOP], (0, -8), true, 1.0, itemAlign:ALIGN_OFFSETS);
// Health
DrINumber (CPlayer.health, 79, -6, imgFONG0);
DrawString("Indexfont_Strife_Green", FormatNumber(CPlayer.health, 3, 5, 0), (86, -6), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
int points;
if (CPlayer.cheats & CF_GODMODE)
{
@ -323,8 +325,8 @@ class StrifeStatusBar : BaseStatusBar
item = CPlayer.mo.FindInventory('BasicArmor');
if (item != NULL && item.Amount > 0)
{
DrawImage (item.Icon, 2, 9);
DrINumber (item.Amount, 27, 23, imgFONY0);
DrawTexture(item.Icon, (2, 9), true, 1.0, itemAlign:ALIGN_OFFSETS);
DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (34, 23), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
}
// Ammo
@ -334,15 +336,15 @@ class StrifeStatusBar : BaseStatusBar
[ammo1, ammo2, ammocount1, ammocount2] = GetCurrentAmmo ();
if (ammo1 != NULL)
{
DrINumber (ammo1.Amount, 311, -6, imgFONG0);
DrawImage (ammo1.Icon, 290, 13);
DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 5, 0), (318, -6), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
DrawTexture (ammo1.Icon, (290, 13), true, 1.0, itemAlign:ALIGN_OFFSETS);
}
// Sigil
item = CPlayer.mo.FindInventory('Sigil');
if (item != NULL)
{
DrawImage (item.Icon, 253, 7);
DrawTexture (item.Icon, (253, 7), true, 1.0, itemAlign:ALIGN_OFFSETS);
}
// Inventory
@ -353,33 +355,30 @@ class StrifeStatusBar : BaseStatusBar
{
if (item == CPlayer.mo.InvSel)
{
screen.DrawTexture (Images[CursorImage], true,
42 + 35*i + ST_X, 12 + ST_Y,
DTA_Bottom320x200, Scaled,
DTA_Alpha, 1. - ItemFlash);
DrawTexture (item.Icon, (42 + 35*i, 12), true, 1. - ItemFlash, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0);
}
if (item.Icon.isValid())
{
DrawDimImage (item.Icon, 48 + 35*i, 14, item.Amount <= 0);
DrawTexture (item.Icon, (48 + 35*i, 14), true, 1.0, itemAlign:ALIGN_OFFSETS, item.Amount <= 0? DI_DIM : 0);
}
DrINumber (item.Amount, 74 + 35*i, 23, imgFONY0);
DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (81 + 35*i, 23), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, 0, 7, true, 1, 1);
i++;
}
}
protected void DrawFullScreenStuff ()
{
fullscreenoffsets = true;
// Draw health
DrINumberOuter (CPlayer.health, 4, -10, false, 7);
DrawTexture(Images[imgMEDI], (14, -17), false, 1.0, BOTTOM|LEFT, itemalign: BOTTOM|HCENTER);
DrawString("Indexfont_Strife_Green", FormatNumber(CPlayer.health, 3, 0, 0), (4, -10), 1., (CPlayer.health < CPlayer.mo.RunHealth)? Font.CR_BRICK : Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_LEFT|ALIGN_BOTTOM, 7, true, 1, 1);
DrawTexture(Images[imgMEDI], (14, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_LEFT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);
// Draw armor
let armor = CPlayer.mo.FindInventory('BasicArmor');
if (armor != NULL && armor.Amount != 0)
{
DrINumberOuter (armor.Amount, 35, -10, false, 7);
DrawTexture(armor.Icon, (45, -17), false, 1.0, BOTTOM|LEFT, itemalign: BOTTOM|HCENTER);
DrawString("Indexfont_Strife_Yellow", FormatNumber(armor.Amount, 3, 0, 0), (35, -10), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_LEFT|ALIGN_BOTTOM, 7, true, 1, 1);
DrawTexture(armor.Icon, (45, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_LEFT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);
}
// Draw ammo
@ -390,19 +389,19 @@ class StrifeStatusBar : BaseStatusBar
if (ammo1 != NULL)
{
// Draw primary ammo in the bottom-right corner
DrINumberOuter (ammo1.Amount, -23, -10, false, 7);
DrawTexture(ammo1.Icon, (-14, -17), false, 1.0, BOTTOM|RIGHT, itemalign: BOTTOM|HCENTER);
DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 0, 0), (-23, -10), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_BOTTOM, 7, true, 1, 1);
DrawTexture(ammo1.Icon, (-14, -17), false, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);
if (ammo2 != NULL && ammo1!=ammo2)
{
// Draw secondary ammo just above the primary ammo
DrINumberOuter (ammo2.Amount, -23, -48, false, 7);
DrawTexture(ammo1.Icon, (-14, -55), false, 1.0, BOTTOM|RIGHT, itemalign: BOTTOM|HCENTER);
DrawString("Indexfont_Strife_Green", FormatNumber(ammo1.Amount, 3, 0, 0), (-23, -48), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_BOTTOM, 7, true, 1, 1);
DrawTexture(ammo1.Icon, (-14, -55), false, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, itemalign: ALIGN_BOTTOM|ALIGN_HCENTER);
}
}
if (deathmatch)
{ // Draw frags (in DM)
DrBNumberOuterFont (CPlayer.fragcount, -44, 1);
DrawString("BigFont", FormatNumber(CPlayer.FragCount, 3, 0, 0), (-44, 1), 1., Font.CR_UNTRANSLATED, TEXT_LEFT, ALIGN_RIGHT|ALIGN_TOP, 0, false, 2, 2);
}
// Draw inventory
@ -412,18 +411,10 @@ class StrifeStatusBar : BaseStatusBar
{
if (ItemFlash > 0)
{
vector2 size = TexMan.GetScaledSize(Images[CursorImage]);
screen.DrawTexture (Images[CursorImage], true, -28, -15,
DTA_HUDRules, HUD_Normal,
DTA_LeftOffsetF, size.X,
DTA_TopOffsetF, size.Y,
DTA_Alpha, ItemFlash);
DrawTexture(Images[CursorImage], (-28, -15), true, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, ItemAlign:ALIGN_BOTTOM|ALIGN_RIGHT);
}
DrINumberOuter (CPlayer.mo.InvSel.Amount, -51, -10, false, 7);
screen.DrawTexture (CPlayer.mo.InvSel.Icon, true, -42, -17,
DTA_HUDRules, HUD_Normal,
DTA_CenterBottomOffset, true,
DTA_ColorOverlay, CPlayer.mo.InvSel.Amount > 0 ? 0 : Color(170, 0, 0, 0));
DrawString("Indexfont_Strife_Yellow", FormatNumber(CPlayer.mo.InvSel.Amount, 3, 5, 0), (-23, -10), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, ALIGN_BOTTOM|ALIGN_RIGHT, 7, true, 1, 1);
DrawTexture(CPlayer.mo.InvSel.Icon, (-42, -17), true, 1.0, ALIGN_BOTTOM|ALIGN_RIGHT, ItemAlign:ALIGN_BOTTOM|ALIGN_HCENTER, CPlayer.mo.InvSel.Amount > 0 ? 0 : DI_DIM);
}
}
else
@ -431,23 +422,20 @@ class StrifeStatusBar : BaseStatusBar
CPlayer.mo.InvFirst = ValidateInvFirst (6);
int i = 0;
Inventory item;
Vector2 box = TexMan.GetScaledSize(Images[CursorImage]) - (4, 4); // Fit oversized icons into the box.
if (CPlayer.mo.InvFirst != NULL)
{
for (item = CPlayer.mo.InvFirst; item != NULL && i < 6; item = item.NextInv())
{
if (item == CPlayer.mo.InvSel)
{
screen.DrawTexture (Images[CursorImage], true, -100+i*35, -21,
DTA_HUDRules, HUD_HorizCenter,
DTA_Alpha, 0.75);
DrawTexture(Images[CursorImage], (-90+i*35, -3), true, 0.75, ALIGN_CENTER_BOTTOM, ItemAlign:ALIGN_CENTER_BOTTOM);
}
if (item.Icon.isValid())
{
screen.DrawTexture (item.Icon, true, -94 + i*35, -19,
DTA_HUDRules, HUD_HorizCenter,
DTA_ColorOverlay, CPlayer.mo.InvSel.Amount > 0 ? 0 : Color(170, 0, 0, 0));
DrawTexture(item.Icon, (-90+i*35, -5), true, 0.75, ALIGN_CENTER_BOTTOM, box, ALIGN_CENTER_BOTTOM, CPlayer.mo.InvSel.Amount > 0 ? 0 : DI_DIM);
}
DrINumberOuter (item.Amount, -89 + i*35, -10, true, 7);
DrawString("Indexfont_Strife_Yellow", FormatNumber(item.Amount, 3, 5, 0), (-65 + i*35, -8), 1.0, Font.CR_UNTRANSLATED, TEXT_RIGHT, ALIGN_CENTER_BOTTOM, 7, true, 1, 1);
++i;
}
}
@ -480,14 +468,8 @@ class StrifeStatusBar : BaseStatusBar
{
case POP_Log:
{
int seconds = Thinker.Tics2Seconds(level.time);
// Draw the latest log message.
buff = String.Format("%02d:%02d:%02d",
seconds / 3600,
(seconds % 3600) / 60,
(seconds) % 60);
screen.DrawText(SmallFont2, Font.CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, buff,
screen.DrawText(SmallFont2, Font.CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, Level.TimeFormatted(),
DTA_CleanNoMove, true);
if (CPlayer.LogText.Length() > 0)
@ -640,25 +622,6 @@ class StrifeStatusBar : BaseStatusBar
}
}
void DrINumber (int val, int x, int y, int imgBase) const
{
x -= 7;
if (val == 0)
{
DrawImage (Images[imgBase], x, y);
}
else
{
while (val != 0)
{
DrawImage (Images[imgBase+val%10], x, y);
val /= 10;
x -= 7;
}
}
}
void DrINumber2 (int val, int x, int y, int width, int imgBase) const
{
x -= width;
@ -677,183 +640,5 @@ class StrifeStatusBar : BaseStatusBar
}
}
}
//---------------------------------------------------------------------------
//
// PROC DrINumberOuter
//
// Draws a number outside the status bar, possibly scaled.
//
//---------------------------------------------------------------------------
void DrINumberOuter(int val, int x, int y, bool center, int w) const
{
bool negative = false;
x += w * 2;
if (val < 0)
{
negative = true;
val = -val;
}
else if (val == 0)
{
screen.DrawTexture(Images[imgINumbers], true, x + 1, y + 1,
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal);
screen.DrawTexture(Images[imgINumbers], true, x, y,
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal);
return;
}
int oval = val;
int ox = x;
// First the shadow
while (val != 0)
{
screen.DrawTexture(Images[imgINumbers + val % 10], true, x + 1, y + 1,
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal);
x -= w;
val /= 10;
}
if (negative)
{
screen.DrawTexture(Images[imgNEGATIVE], true, x + 1, y + 1,
DTA_FillColor, 0, DTA_Alpha, HR_SHADOW,
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal);
}
// Then the real deal
val = oval;
x = ox;
while (val != 0)
{
screen.DrawTexture(Images[imgINumbers + val % 10], true, x, y,
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal);
x -= w;
val /= 10;
}
if (negative)
{
screen.DrawTexture(Images[imgNEGATIVE], true, x, y,
DTA_HUDRules, center ? HUD_HorizCenter : HUD_Normal);
}
}
//---------------------------------------------------------------------------
//
// PROC DrBNumberOuter
//
// Draws a three digit number using the real big font outside the status bar.
//
//---------------------------------------------------------------------------
void DrBNumberOuterFont(int val, int x, int y, int size = 3) const
{
int v;
bool negative = false;
TextureID pic;
int w = BigFont.GetCharWidth("0");
int ww = w;
if (w > 1)
{
w--;
}
int xpos = x + w / 2 + (size - 1)*w;
if (val == 0)
{
screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2, "0",
DTA_HUDRules, HUD_Normal,
DTA_Alpha, HR_SHADOW,
DTA_FillColor, 0);
screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2, y, "0",
DTA_HUDRules, HUD_Normal);
return;
}
else if (val < 0)
{
negative = true;
val = -val;
}
int oval = val;
int oxpos = xpos;
// First the shadow
while (val != 0)
{
v = BigFont.GetCharWidth(int("0") + val % 10);
screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2,
DTA_HUDRules, HUD_Normal,
DTA_Alpha, HR_SHADOW,
DTA_FillColor, 0);
val /= 10;
xpos -= w;
}
if (negative)
{
v = BigFont.GetCharWidth("-");
screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2 + 2, y + 2, "-",
DTA_HUDRules, HUD_Normal,
DTA_Alpha, HR_SHADOW,
DTA_FillColor, 0);
}
// Then the foreground number
val = oval;
xpos = oxpos;
while (val != 0)
{
v = BigFont.GetCharWidth(int("0") + val % 10);
screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2, y, "0", DTA_HUDRules, HUD_Normal);
val /= 10;
xpos -= w;
}
if (negative)
{
v = BigFont.GetCharWidth("-");
screen.DrawChar(BigFont, Font.CR_UNTRANSLATED, xpos - v / 2, y, "-", DTA_HUDRules, HUD_Normal);
}
}
//---------------------------------------------------------------------------
//
// PROC DrawImage
//
// Draws an image with the status bar's upper-left corner as the origin.
//
//---------------------------------------------------------------------------
void DrawImage(TextureID img, int x, int y) const
{
if (img.IsValid())
{
screen.DrawTexture(img, true, x + ST_X, y + ST_Y, DTA_Bottom320x200, Scaled);
}
}
//---------------------------------------------------------------------------
//
// PROC DrawImage
//
// Draws an optionally dimmed image with the status bar's upper-left corner
// as the origin.
//
//---------------------------------------------------------------------------
void DrawDimImage(TextureID img, int x, int y, bool dimmed) const
{
if (img.IsValid())
{
screen.DrawTexture(img, true, x + ST_X, y + ST_Y, DTA_ColorOverlay, dimmed ? Color(170, 0, 0, 0) : 0, DTA_Bottom320x200, Scaled);
}
}
}