//------------------------------------------------------------------------- /* Copyright (C) 2010-2019 EDuke32 developers and contributors Copyright (C) 2019 Nuke.YKT Copyright (C) 2020-2021 Christoph Oelckers This file is part of Raze. This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //------------------------------------------------------------------------- class BloodStatusBar : RazeStatusBar { static const String gPackIcons[] = { "PackIcon1", "PackIcon2", "PackIcon3", "PackIcon4", "PackIcon5" }; HUDFont smallf, tinyf; int team_score[2], team_ticker[2]; // placeholders for MP display bool gBlueFlagDropped, gRedFlagDropped; // also placeholders until we know where MP will go. override void Init() { smallf = HUDFont.Create(SmallFont, 0, Mono_Off, 0, 0); tinyf = HUDFont.Create(Font.FindFont("DIGIFONT"), 4, Mono_CellRight, 0, 0); } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- int texWidth(String name) { let tex = TexMan.CheckForTexture(name, TexMan.Type_Any); let siz = TexMan.GetScaledSize(tex); return siz.x; } int texHeight(String name) { let tex = TexMan.CheckForTexture(name, TexMan.Type_Any); let siz = TexMan.GetScaledSize(tex); return siz.y; } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void DrawStatNumber(String pFormat, int nNumber, String nametemplate, double x, double y, int nShade, int nPalette, double nScale = 1, int align = 0) { String texname = String.Format("%s%d", nametemplate, 1); double width = (texWidth(texname) + 1) * nScale; String tempbuf = String.Format(pFormat, nNumber); x += 0.5; y += 0.5; // This is needed because due to using floating point math, this code rounds slightly differently which for the numbers can be a problem. for (uint i = 0; i < tempbuf.length(); i++, x += width) { int c = tempbuf.ByteAt(i); if (c < "0" || c > "9") continue; texname = String.Format("%s%d", nametemplate, c - int("0")); int flags = align | DI_ITEM_RELCENTER; DrawImage(texname, (x, y), flags, 1, (-1, -1), (nScale, nScale), STYLE_Translucent, Raze.shadeToLight(nShade), Translation.MakeID(Translation_Remap, nPalette)); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void DrawCharArray(String text, String nametemplate, double x, double y) { String texname = String.Format("%s%d", nametemplate, 1); double width = (texWidth(texname) + 1); x += 0.5; y += 0.5; // This is needed because due to using floating point math, this code rounds slightly differently which for the numbers can be a problem. for (uint i = 0; i < text.length(); i++, x += width) { int c = text.ByteAt(i); // Hackasaurus rex to give me a slash when drawing the weapon count of a reloadable gun. if (c == 47) { DrawImage("SBarSlash", (x, y), DI_ITEM_RELCENTER); } else { if (c < "0" || c > "9") continue; texname = String.Format("%s%d", nametemplate, c - int("0")); DrawImage(texname, (x, y), DI_ITEM_RELCENTER); } } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void TileHGauge(String nTile, double x, double y, int nMult, int nDiv, double sc = 1) { int w = texWidth(nTile); double bx = w * sc * nMult / nDiv + x; double scale = (bx - x) / w; DrawImage(nTile, (x, y), DI_ITEM_LEFT_TOP, 1., (-1, -1), (sc, sc), clipwidth:scale); } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void DoLevelStats(BloodPlayer pPlayer, int bottomy, Summaryinfo summary) { StatsPrintInfo stats; stats.fontscale = 1.; stats.screenbottomspace = bottomy; stats.letterColor = TEXTCOLOR_DARKRED; stats.standardColor = TEXTCOLOR_DARKGRAY; int y = -1; int mask = 1; if (automapMode == am_full) { stats.statfont = SmallFont2; stats.spacing = 6; stats.altspacing = SmallFont.GetHeight() + 2; if (hud_size <= Hud_StbarOverlay) stats.screenbottomspace = 56; y = PrintAutomapInfo(stats, summary, false); mask = 2; } // Blood does not use am_overlay. if (hud_stats & mask) { stats.statfont = SmallFont; stats.completeColor = TEXTCOLOR_DARKGREEN; stats.spacing = SmallFont.GetHeight() + 2; PrintLevelStats(stats, summary, y); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- const nPowerUps = 11; void drawPowerUps(BloodPlayer pPlayer) { static const float powerScale[] = { 0.4f, 0.4f, 0.3f, 0.3f, 0.4f, 0.3f, 0.4f, 0.5f, 0.3f, 0.4f, 0.4f }; static const int powerYoffs[] = { 0, 5, 9, 5, 9, 7, 4, 5, 9, 4, 4 }; static const int powerOrder[] = { Blood.kPwUpShadowCloak, Blood.kPwUpReflectShots, Blood.kPwUpDeathMask, Blood.kPwUpTwoGuns, Blood.kPwUpShadowCloakUseless, Blood.kPwUpFeatherFall, Blood.kPwUpGasMask, Blood.kPwUpDoppleganger, Blood.kPwUpAsbestArmor, Blood.kPwUpGrowShroom, Blood.kPwUpShrinkShroom }; if (!hud_powerupduration) return; int powersort[nPowerUps]; for (int i = 0; i < nPowerUps; i++) powersort[i] = i; for (int i = 0; i < nPowerUps; i++) { for (int j = i + 1; j < nPowerUps; j++) { int power1 = powersort[i]; int power2 = powersort[j]; if (pPlayer.pwUpTime[powerOrder[power1]] > pPlayer.pwUpTime[powerOrder[power2]]) { powersort[i] = power2; powersort[j] = power1; } } } int warningTime = 5; int x = 15; int y = -50; for (int i = 0; i < nPowerUps; i++) { int order = powersort[i]; int power = powerOrder[order]; int time = pPlayer.pwUpTime[power]; if (time > 0) { int remainingSeconds = time / 100; if (remainingSeconds > warningTime || (PlayClock & 32)) { DrawTexture(Blood.PowerUpIcon(power), (x, y + powerYoffs[order]), DI_SCREEN_LEFT_CENTER | DI_ITEM_RELCENTER, scale:(powerScale[order], powerScale[order])); } DrawStatNumber("%d", remainingSeconds, "SBarNumberInv", x + 15, y, 0, remainingSeconds > warningTime ? 0 : Translation.MakeID(Translation_Remap, 2), 0.5, DI_SCREEN_LEFT_CENTER); y += 20; } } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void drawInventory(BloodPlayer pPlayer, int x, int y) { int packs[5]; if (pPlayer.packItemTime) { int nPacks = 0; int width = 0; for (int i = 0; i < 5; i++) { if (pPlayer.packSlots[i].curAmount) { packs[nPacks++] = i; width += texWidth(gPackIcons[i]) + 1; } } width /= 2; x -= width; for (int i = 0; i < nPacks; i++) { int nPack = packs[i]; DrawImage("PackBG", (x + 1, y - 8), DI_ITEM_RELCENTER, style:STYLE_Normal); DrawImage("PackBG", (x + 1, y - 6), DI_ITEM_RELCENTER, style:STYLE_Normal); DrawImage(gPackIcons[nPack], (x + 1, y + 1), DI_ITEM_RELCENTER, style:STYLE_Normal); if (nPack == pPlayer.packItemId) DrawImage("PackSelect", (x + 1, y + 1), DI_ITEM_RELCENTER); int nShade; if (pPlayer.packSlots[nPack].isActive) nShade = 4; else nShade = 24; DrawStatNumber("%3d", pPlayer.packSlots[nPack].curAmount, "SBarPackAmount", x - 4, y - 13, nShade, 0); x += texWidth(gPackIcons[nPack]) + 1; } } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void DrawPackItemInStatusBar(BloodPlayer pPlayer, int x, int y, int x2, int y2) { let id = pPlayer.packItemId; //id = 0; if (id < 0) return; DrawImage(gPackIcons[id], (x, y), DI_ITEM_RELCENTER, style:STYLE_Normal); DrawStatNumber("%3d", pPlayer.packSlots[id].curAmount, "SBarPackAmount", x2, y2, 0, 0); } void DrawPackItemInStatusBar2(BloodPlayer pPlayer, int x, int y, int x2, int y2, double nScale) { static const String packIcons2[] = { "Pack2Icon1", "Pack2Icon2", "Pack2Icon3", "Pack2Icon4", "Pack2Icon5" }; static const float packScale[] = { 0.5f, 0.3f, 0.6f, 0.5f, 0.4f }; static const int packYoffs[] = { 0, 0, 0, -4, 0 }; if (pPlayer.packItemId < 0) return; let sc = packScale[pPlayer.packItemId]; DrawImage(packIcons2[pPlayer.packItemId], (x, y + packYoffs[pPlayer.packItemId]), DI_ITEM_RELCENTER, scale:(sc, sc), style:STYLE_Normal); DrawStatNumber("%3d", pPlayer.packSlots[pPlayer.packItemId].curAmount, "SBarNumberInv", x2, y2, 0, 0, nScale); } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void drawPlayerSlots(Array players) { for (int nRows = (players.Size() - 1) / 4; nRows >= 0; nRows--) { for (int nCol = 0; nCol < 4; nCol++) { DrawImage("SBPlayerSlot", (-120 + nCol * 80, 4 + nRows * 9), DI_ITEM_RELCENTER|DI_SCREEN_CENTER_TOP, style:STYLE_Normal, col:0xffc0c0c0); } } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void drawPlayerFrags(Array players) { drawPlayerSlots(players); for (int i = 0; i < players.Size(); i++) { int x = -160 + 80 * (i & 3); int y = 9 * (i / 4); int col = players[i].teamId & 3; int cr = col == 0? Font.CR_UNTRANSLATED : col == 1? Font.CR_BLUE : Font.CR_RED; DrawString(tinyf, Raze.PlayerName(i), (x + 4, y), DI_SCREEN_CENTER_TOP, cr, 1., -1, -1); String gTempStr = String.Format("%2d", players[i].fragCount); DrawString(tinyf, gTempStr, (x + 76, y), DI_SCREEN_CENTER_TOP, cr, 1., -1, -1); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void drawPlayerFlags(Array players) { String gTempStr; drawPlayerSlots(players); for (int i = 0; i < players.Size(); i++) { int x = -160 + 80 * (i & 3); int y = 9 * (i / 4); int col = players[i].teamId & 3; gTempStr = String.Format("%s", Raze.PlayerName(i)); int cr = col == 0? Font.CR_UNTRANSLATED : col == 1? Font.CR_BLUE : Font.CR_RED; DrawString(tinyf, gTempStr.MakeUpper(), (x + 4, y), DI_SCREEN_CENTER_TOP, cr, 1., -1, -1); x += 76; if (players[i].hasFlag & 2) { DrawString(tinyf, "F", (x, y), DI_SCREEN_CENTER_TOP, Font.CR_BLUE/*12*/, 1., -1, -1); x -= 6; } if (players[i].hasFlag & 1) DrawString(tinyf, "F", (x, y), DI_SCREEN_CENTER_TOP, Font.CR_RED/*11*/, 1., -1, -1); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void drawCtfHudVanilla(Array players) { String gTempStr; int x = 1, y = 1; if (team_ticker[0] == 0 || (PlayClock & 8)) { DrawString(smallf, "$TXT_COLOR_BLUE", (x, y), 0, Font.CR_LIGHTBLUE, 1., -1, -1); gTempStr = String.Format("%-3d", team_score[0]); DrawString(smallf, gTempStr, (x, y + 10), 0, Font.CR_LIGHTBLUE, 1., -1, -1); } x = -2; if (team_ticker[1] == 0 || (PlayClock & 8)) { DrawString(smallf, "$TXT_COLOR_RED", (x, y), DI_TEXT_ALIGN_RIGHT, Font.CR_BRICK, 1., -1, -1); gTempStr = String.Format("%3d", team_score[1]); DrawString(smallf, gTempStr, (x, y + 10), DI_TEXT_ALIGN_RIGHT, Font.CR_BRICK, 1., -1, -1); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void flashTeamScore(int team, bool show) { if (team_ticker[team] == 0 || (PlayClock & 8)) { if (show) DrawStatNumber("%d", team_score[team], "SBarNumberInv", -30, team ? 25 : -10, 0, team ? 2 : 10, 0.75, DI_SCREEN_RIGHT_CENTER); } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void drawCtfHud(BloodPlayer pPlayer, Array players) { if (hud_size == Hud_Nothing) { flashTeamScore(0, false); flashTeamScore(1, false); return; } bool blueFlagTaken = false; bool redFlagTaken = false; int blueFlagCarrierColor = 0; int redFlagCarrierColor = 0; for (int i = 0; i < players.Size(); i++) { if ((players[i].hasFlag & 1) != 0) { blueFlagTaken = true; blueFlagCarrierColor = players[i].teamId & 3; } if ((players[i].hasFlag & 2) != 0) { redFlagTaken = true; redFlagCarrierColor = players[i].teamId & 3; } } bool meHaveBlueFlag = pPlayer.hasFlag & 1; int trans10 = Translation.MakeID(Translation_Remap, 10); int trans2 = Translation.MakeID(Translation_Remap, 2); DrawImage(meHaveBlueFlag ? "FlagHave" : "FlagHaveNot", (0, 75 - 100), DI_SCREEN_RIGHT_CENTER|DI_ITEM_RELCENTER, scale:(0.35, 0.35), translation:trans10); if (gBlueFlagDropped) DrawImage("FlagDropped", (305 - 320, 83 - 100), DI_SCREEN_RIGHT_CENTER|DI_ITEM_RELCENTER, translation:trans10); else if (blueFlagTaken) DrawImage("FlagTaken", (307 - 320, 77 - 100), DI_SCREEN_RIGHT_CENTER|DI_ITEM_RELCENTER, translation:blueFlagCarrierColor ? trans2 : trans10); flashTeamScore(0, true); bool meHaveRedFlag = pPlayer.hasFlag & 2; DrawImage(meHaveRedFlag ? "FlagHave" : "FlagHaveNot", (0, 10), DI_SCREEN_RIGHT_CENTER|DI_ITEM_RELCENTER, scale:(0.35, 0.35), translation:trans2); if (gRedFlagDropped) DrawImage("FlagDropped", (305 - 320, 17), DI_SCREEN_RIGHT_CENTER|DI_ITEM_RELCENTER, translation:trans2); else if (redFlagTaken) DrawImage("FlagTaken", (307 - 320, 11), DI_SCREEN_RIGHT_CENTER|DI_ITEM_RELCENTER, translation:redFlagCarrierColor ? trans2 : trans10); flashTeamScore(1, true); } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- void drawMultiHUD(BloodPlayer pPlayer, int nGameType) { if (nGameType >= 1) { Array players; Blood.GetPlayers(players); if (nGameType == 3) { if (hud_ctf_Vanilla) { drawCtfHudVanilla(players); } else { drawCtfHud(pPlayer, players); drawPlayerFlags(players); } } else { drawPlayerFrags(players); } } } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- int DrawStatusBar(BloodPlayer pPlayer, int nPalette) { int th = texHeight("Statusbar"); BeginStatusBar(false, 320, 200, th); int health = pPlayer.GetHealth(); DrawImage("Statusbar", (160, 200), DI_ITEM_CENTER_BOTTOM); DrawPackItemInStatusBar(pPlayer, 265, 186, 260, 172); if (health >= 16 || (PlayClock & 16) || health == 0) { DrawStatNumber("%3d", health >> 4, "SBarHealthAmount", 86, 183, 0, 0); } if (pPlayer.curWeapon && pPlayer.weaponAmmo != -1) { int num = pPlayer.ammoCount[pPlayer.weaponAmmo]; if (pPlayer.weaponAmmo == 6) num /= 10; DrawStatNumber("%3d", num, "SBarNumberAmmo", 216, 183, 0, 0); } for (int i = 9; i >= 1; i--) { int x = 135 + ((i - 1) / 3) * 23; int y = 182 + ((i - 1) % 3) * 6; int num = pPlayer.ammoCount[i]; if (i == 6) num /= 10; DrawStatNumber("%3d", num, "SBarAmmoAmount", x, y, i == pPlayer.weaponAmmo ? -128 : 32, 10); } DrawStatNumber("%2d", pPlayer.ammoCount[10], "SBarAmmoAmount", 291, 194, pPlayer.weaponAmmo == 10 ? -128 : 32, 10); DrawStatNumber("%2d", pPlayer.ammoCount[11], "SBarAmmoAmount", 309, 194, pPlayer.weaponAmmo == 11 ? -128 : 32, 10); if (pPlayer.armor[1]) { TileHGauge("Armor1Gauge", 44, 174, pPlayer.armor[1], 3200); DrawStatNumber("%3d", pPlayer.armor[1] >> 4, "SBarAmmoAmount", 50, 177, 0, 0); } if (pPlayer.armor[0]) { TileHGauge("Armor3Gauge", 44, 182, pPlayer.armor[0], 3200); DrawStatNumber("%3d", pPlayer.armor[0] >> 4, "SBarAmmoAmount", 50, 185, 0, 0); } if (pPlayer.armor[2]) { TileHGauge("Armor2Gauge", 44, 190, pPlayer.armor[2], 3200); DrawStatNumber("%3d", pPlayer.armor[2] >> 4, "SBarAmmoAmount", 50, 193, 0, 0); } for (int i = 0; i < 6; i++) { String nTile = String.Format("KEYICON%d", i + 1); double x = 73.5 + (i & 1) * 173; double y = 171.5 + (i >> 1) * 11; if (pPlayer.hasKey[i + 1]) DrawImage(nTile, (x, y), DI_ITEM_RELCENTER, style:STYLE_Normal); else DrawImage(nTile, (x, y), DI_ITEM_RELCENTER, style:STYLE_Normal, col: 0xff606060, translation:Translation.MakeID(Translation_Remap, 5)); } DrawImage("BlinkIcon", (118.5, 185.5), DI_ITEM_RELCENTER, col:Raze.shadeToLight(pPlayer.isRunning || cl_bloodvanillarun ? 16 : 40)); DrawImage("BlinkIcon", (201.5, 185.5), DI_ITEM_RELCENTER, col:Raze.shadeToLight(pPlayer.isRunning || cl_bloodvanillarun ? 16 : 40)); if (pPlayer.throwPower) { TileHGauge("ThrowGauge", 124, 175.5, pPlayer.throwPower, 65536); } drawInventory(pPlayer, 166, 200 - th); // Depending on the scale we can lower the stats display. This needs some tweaking but this catches the important default case already. return (hud_statscale <= 0.501f || hud_scalefactor < 0.7) && screen.GetAspectRatio() > 1.6 ? 28 : 56; } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- int DrawHUD1(BloodPlayer pPlayer, int nPalette) { BeginHUD(1, false, 320, 200); DrawImage("FullHUD", (34, 187 - 200), DI_ITEM_RELCENTER, style:STYLE_Normal, col:0xffc0c0c0, translation:nPalette); int health = pPlayer.GetHealth(); if (health >= 16 || (PlayClock & 16) || health == 0) { DrawStatNumber("%3d", health >> 4, "SBarHealthAmount", 8, 183 - 200, 0, 0); } if (pPlayer.curWeapon && pPlayer.weaponAmmo != -1) { int num = pPlayer.ammoCount[pPlayer.weaponAmmo]; if (pPlayer.weaponAmmo == 6) num /= 10; DrawStatNumber("%3d", num, "SBarNumberAmmo", 42, 183 - 200, 0, 0); } DrawImage("ArmorBox", (284 - 320, 187 - 200), DI_ITEM_RELCENTER, style:STYLE_Normal, col:0xffc0c0c0, translation:nPalette); if (pPlayer.armor[1]) { TileHGauge("Armor1Gauge", 250 - 320, 175 - 200, pPlayer.armor[1], 3200); DrawStatNumber("%3d", pPlayer.armor[1] >> 4, "SBarAmmoAmount", 255 - 320, 178 - 200, 0, 0); } if (pPlayer.armor[0]) { TileHGauge("Armor3Gauge", 250 - 320, 183 - 200, pPlayer.armor[0], 3200); DrawStatNumber("%3d", pPlayer.armor[0] >> 4, "SBarAmmoAmount", 255 - 320, 186 - 200, 0, 0); } if (pPlayer.armor[2]) { TileHGauge("Armor2Gauge", 250 - 320, 191 - 200, pPlayer.armor[2], 3200); DrawStatNumber("%3d", pPlayer.armor[2] >> 4, "SBarAmmoAmount", 255 - 320, 194 - 200, 0, 0); } DrawPackItemInStatusBar(pPlayer, 286 - 320, 186 - 200, 302 - 320, 183 - 200); for (int i = 0; i < 6; i++) { String nTile = String.Format("KEYICON%d", i + 1); int x; int y = -6; if (i & 1) { x = -(78 + (i >> 1) * 10); } else { x = 73 + (i >> 1) * 10; } if (pPlayer.hasKey[i + 1]) DrawImage(nTile, (x, y), DI_ITEM_RELCENTER, style:STYLE_Normal); } return 28; } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- int DrawHUD2(BloodPlayer pPlayer) { static const String ammoIcons[] = { "", "AmmoIcon1", "AmmoIcon2", "AmmoIcon3", "AmmoIcon4", "AmmoIcon5", "AmmoIcon6", "AmmoIcon7", "AmmoIcon8", "AmmoIcon9", "AmmoIcon10", "AmmoIcon11" }; static const float ammoScale[] = { 0, 0.5f, 0.8f, 0.7f, 0.5f, 0.7f, 0.5f, 0.3f, 0.3f, 0.6f, 0.5f, 0.45f }; static const int ammoYoffs[] = { 0, 0, 0, 3, -6, 2, 4, -6, -6, -6, 2, 2 }; int health = pPlayer.GetHealth(); BeginHUD(1, false, 320, 200); DrawImage("HealthIcon", (12, 195 - 200), 0, scale:(0.56, 0.56)); DrawStatNumber("%d", health >> 4, "SBarNumberHealth", 28, 187 - 200, 0, 0); if (pPlayer.armor[1]) { DrawImage("Armor1Icon", (70, 186 - 200), DI_ITEM_RELCENTER, scale:(0.5, 0.5)); DrawStatNumber("%3d", pPlayer.armor[1] >> 4, "SBarNumberArmor2_", 83, 187 - 200, 0, 0, 0.65); } if (pPlayer.armor[0]) { DrawImage("Armor3Icon", (112, 195 - 200), DI_ITEM_RELCENTER, scale:(0.5, 0.5)); DrawStatNumber("%3d", pPlayer.armor[0] >> 4, "SBarNumberArmor1_", 125, 187 - 200, 0, 0, 0.65); } if (pPlayer.armor[2]) { DrawImage("Armor2Icon", (155, 196 - 200), DI_ITEM_RELCENTER, scale:(0.5, 0.5)); DrawStatNumber("%3d", pPlayer.armor[2] >> 4, "SBarNumberArmor3_", 170, 187 - 200, 0, 0, 0.65); } DrawPackItemInStatusBar2(pPlayer, 216 - 320, 194 - 200, 231 - 320, 187 - 200, 0.7); if (pPlayer.curWeapon && pPlayer.weaponAmmo != -1) { int num = pPlayer.ammoCount[pPlayer.weaponAmmo]; if (pPlayer.weaponAmmo == 6) num /= 10; if (ammoIcons[pPlayer.weaponAmmo]) { let scale = ammoScale[pPlayer.weaponAmmo]; DrawImage(ammoIcons[pPlayer.weaponAmmo], (304 - 320, -8 + ammoYoffs[pPlayer.weaponAmmo]), DI_ITEM_RELCENTER, scale:(scale, scale)); } bool reloadableWeapon = pPlayer.curWeapon == 3 && !pPlayer.powerupCheck(Blood.kPwUpTwoGuns); if (!reloadableWeapon || (reloadableWeapon && !cl_showmagamt)) { DrawStatNumber("%3d", num, "SBarNumberAmmo", 267 - 320, 187 - 200, 0, 0); } else { int clip = CalcMagazineAmount(num, 2, pPlayer.weaponState == 1); int total = num - clip; String format = String.Format("%d/%d", clip, num - clip); DrawCharArray(format, "SBarNumberAmmo", (total < 10 ? 267 : 258) - 320, 187 - 200); } } for (int i = 0; i < 6; i++) { if (pPlayer.hasKey[i + 1]) { let tile = String.Format("HUDKEYICON%d", i + 1); DrawImage(tile, (-60 + 10 * i, 170 - 200), DI_ITEM_RELCENTER, scale:(0.25, 0.25)); } } BeginStatusBar(false, 320, 200, 28); if (pPlayer.throwPower) TileHGauge("ThrowGauge", 124, 175, pPlayer.throwPower, 65536); else drawInventory(pPlayer, 166, 200 - texHeight("FULLHUD") / 2 - 30); return 28; } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- override void UpdateStatusBar(SummaryInfo summary) { int nPalette = 0; let pPlayer = Blood.GetViewPlayer(); int y = 0; int nGameType = Blood.getGameType(); if (nGameType == 3) { if (pPlayer.teamId & 1) nPalette = 7; else nPalette = 10; nPalette = Translation.MakeID(Translation_Remap, nPalette); } if (hud_size == Hud_full) { y = DrawHUD2(pPlayer); } else if (hud_size > Hud_Stbar) { BeginStatusBar(false, 320, 200, 28); if (pPlayer.throwPower) TileHGauge("ThrowGauge", 124, 175, pPlayer.throwPower, 65536); else if (hud_size > Hud_StbarOverlay) drawInventory(pPlayer, 166, 200 - texHeight("FullHUD") / 2); } if (hud_size == Hud_Mini) { y = DrawHUD1(pPlayer, nPalette); } else if (hud_size <= Hud_StbarOverlay) { y = DrawStatusBar(pPlayer, nPalette); } DoLevelStats(pPlayer, y, summary); // All remaining parts must be done with HUD alignment rules, even when showing a status bar. BeginHUD(1, false, 320, 200); drawPowerUps(pPlayer); drawMultiHUD(pPlayer, nGameType); } }