diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index dfbd22ffb..092a49710 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1517,8 +1517,135 @@ void DBaseStatusBar::DrawString(FFont *font, const FString &cstring, double x, d x -= static_cast ((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 - (Scaled ? VerticalResolution : 200) + RelTop; + if (Scaled) + screen->VirtualToRealCoords(rx, ry, rw, rh, HorizontalResolution, VerticalResolution, true); + else + { + ry += (200 - VerticalResolution); + } + } + 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 +1654,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 +1763,46 @@ 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); +} diff --git a/src/gl/textures/gl_material.cpp b/src/gl/textures/gl_material.cpp index b4a13af7c..b981b4ecf 100644 --- a/src/gl/textures/gl_material.cpp +++ b/src/gl/textures/gl_material.cpp @@ -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); diff --git a/wadsrc/static/fontdefs.txt b/wadsrc/static/fontdefs.txt index 3858ef742..c70c8024d 100644 --- a/wadsrc/static/fontdefs.txt +++ b/wadsrc/static/fontdefs.txt @@ -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. diff --git a/wadsrc/static/zscript/statusbar/statusbar.txt b/wadsrc/static/zscript/statusbar/statusbar.txt index 742d0995b..22bfe6222 100644 --- a/wadsrc/static/zscript/statusbar/statusbar.txt +++ b/wadsrc/static/zscript/statusbar/statusbar.txt @@ -46,19 +46,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 +72,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,6 +118,12 @@ class BaseStatusBar native ui HUD_HorizCenter } + enum ENumFlags + { + FNF_FILLZEROS, + FNF_WHENNOTZERO, + } + const XHAIRSHRINKSIZE =(1./18); const XHAIRPICKUPSIZE = (2+XHAIRSHRINKSIZE); @@ -154,11 +166,13 @@ class BaseStatusBar native ui virtual void SetMugShotState (String state_name, bool wait_till_done=false, bool reset=false) {} native void RefreshBackground () const; + + // 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 = ""); //============================================================================ @@ -243,10 +257,74 @@ class BaseStatusBar native ui if (w == null) return ""; return w.GetTag(); } - + // 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 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 +339,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)); } //============================================================================ @@ -436,7 +514,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 +545,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 +559,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 +571,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 +614,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 +638,7 @@ class BaseStatusBar native ui // //============================================================================ - void DrawInventoryIcon(class 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 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()) @@ -570,3 +647,82 @@ class BaseStatusBar native ui } } } + +//============================================================================ +// +// 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; + } +} diff --git a/wadsrc/static/zscript/statusbar/strife_sbar.txt b/wadsrc/static/zscript/statusbar/strife_sbar.txt index f75bfffb5..80aedb105 100644 --- a/wadsrc/static/zscript/statusbar/strife_sbar.txt +++ b/wadsrc/static/zscript/statusbar/strife_sbar.txt @@ -371,15 +371,16 @@ class StrifeStatusBar : BaseStatusBar { 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 +391,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 +413,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 +424,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 +470,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) @@ -679,150 +663,6 @@ 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