raze/source/games/sw/src/sbar.cpp

1105 lines
33 KiB
C++

//-------------------------------------------------------------------------
/*
Copyright (C) 1997, 2005 - 3D Realms Entertainment
This file is part of Shadow Warrior version 1.2
Shadow Warrior is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
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.
Original Source: 1997 - Frank Maddin and Jim Norwood
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------
#include "ns.h"
#undef MAIN
#include "build.h"
#include "game.h"
#include "names.h"
#include "names2.h"
#include "panel.h"
#include "pal.h"
#include "misc.h"
#include "player.h"
#include "v_2ddrawer.h"
#include "statusbar.h"
#include "network.h"
#include "v_draw.h"
#include "menus.h"
#include "automap.h"
BEGIN_SW_NS
enum
{
ID_PanelMedkit = 2396,
ID_PanelRepairKit = 2399,
ID_PanelCloak = 2397, //2400
ID_PanelNightVision = 2398,
ID_PanelChemBomb = 2407,
ID_PanelFlashBomb = 2408,
ID_PanelCaltrops = 2409,
};
static const short icons[] = {
ID_PanelMedkit,
ID_PanelRepairKit,
ID_PanelCloak,
ID_PanelNightVision,
ID_PanelChemBomb,
ID_PanelFlashBomb,
ID_PanelCaltrops,
};
class DSWStatusBar : public DBaseStatusBar
{
DECLARE_CLASS(DSWStatusBar, DBaseStatusBar)
HAS_OBJECT_POINTERS
TObjPtr<DHUDFont*> miniFont, numberFont;
enum
{
PANEL_HEALTH_BOX_X = 20,
PANEL_BOX_Y = (174 - 6),
PANEL_HEALTH_XOFF = 2,
PANEL_HEALTH_YOFF = 4,
PANEL_AMMO_BOX_X = 197,
PANEL_AMMO_XOFF = 1,
PANEL_AMMO_YOFF = 4,
WSUM_X = 93,
WSUM_Y = PANEL_BOX_Y+1,
WSUM_XOFF = 25,
WSUM_YOFF = 6,
PANEL_KEYS_BOX_X = 276,
PANEL_KEYS_XOFF = 0,
PANEL_KEYS_YOFF = 2,
PANEL_ARMOR_BOX_X = 56,
PANEL_ARMOR_XOFF = 2,
PANEL_ARMOR_YOFF = 4,
FRAG_YOFF = 2,
INVENTORY_BOX_X = 231,
INVENTORY_BOX_Y = (176-8),
INVENTORY_PIC_XOFF = 1,
INVENTORY_PIC_YOFF = 1,
INVENTORY_PERCENT_XOFF = 19,
INVENTORY_PERCENT_YOFF = 13,
INVENTORY_STATE_XOFF = 19,
INVENTORY_STATE_YOFF = 1,
MINI_BAR_Y = 174 ,
MINI_BAR_HEALTH_BOX_X = 4,
MINI_BAR_AMMO_BOX_X = 32,
MINI_BAR_INVENTORY_BOX_X = 64,
MINI_BAR_INVENTORY_BOX_Y = MINI_BAR_Y,
};
enum
{
PANEL_FONT_G = 3636,
PANEL_FONT_Y = 3646,
PANEL_FONT_R = 3656,
PANEL_SM_FONT_G = 3601,
PANEL_SM_FONT_Y = 3613,
PANEL_SM_FONT_R = 3625,
PANEL_KEY_RED = 2392,
PANEL_KEY_GREEN = 2393,
PANEL_KEY_BLUE = 2394,
PANEL_KEY_YELLOW = 2395,
PANEL_SKELKEY_GOLD = 2448,
PANEL_SKELKEY_SILVER= 2449,
PANEL_SKELKEY_BRONZE= 2458,
PANEL_SKELKEY_RED = 2459,
MINI_BAR_HEALTH_BOX_PIC = 2437,
MINI_BAR_AMMO_BOX_PIC = 2437,
MINI_BAR_INVENTORY_BOX_PIC = 2438,
ID_SelectionBox = 2435,
};
public:
DSWStatusBar()
{
numberFont = Create<DHUDFont>( BigFont, 0, Off, 1, 1 );
miniFont = Create<DHUDFont>(SmallFont2, 0, Off, 1, 1 );
}
private:
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayPanelNumber(double xs, double ys, int number)
{
char buffer[32];
char* ptr;
double x;
mysnprintf(buffer, 32, "%03d", number);
for (ptr = buffer, x = xs; *ptr; ptr++)
{
if (!isdigit(*ptr))
{
continue;
}
int tex = PANEL_FONT_G + (*ptr - '0');
DrawGraphic(tileGetTexture(tex), x, ys, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1);
x += tileWidth(tex) + 1;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplaySummaryString(double xs, double ys, int color, int shade, const char* buffer)
{
double x;
const char* ptr;
char ch;
int font_pic;
static const short font_base[] = { PANEL_SM_FONT_G, PANEL_SM_FONT_Y, PANEL_SM_FONT_R };
assert(color < 3);
for (ptr = buffer, x = xs; *ptr; ptr++)
{
ch = *ptr;
if (ch == ' ')
{
x += 4;
continue;
}
switch (ch)
{
case '\\':
ch = '0' - 1; // one pic before 0
break;
case ':':
ch = '9' + 1; // one pic after nine
break;
}
font_pic = font_base[color] + (ch - '0');
DrawGraphic(tileGetTexture(font_pic), x, ys, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1, shadeToLight(shade));
x += tileWidth(font_pic) + 1;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayTimeLimit(PLAYERp pp)
{
int seconds = gNet.TimeLimitClock / 120;
sprintf(ds, "%03d:%02d", seconds / 60, seconds % 60);
DisplaySummaryString(PANEL_KEYS_BOX_X + 1, PANEL_BOX_Y + 6, 0, 0, ds);
}
//---------------------------------------------------------------------------
//
// todo: migrate to FFont to support localization
//
//---------------------------------------------------------------------------
void DisplayTinyString(double xs, double ys, const char* buffer, int pal)
{
SBar_DrawString(this, miniFont, buffer, xs, ys, DI_ITEM_LEFT_TOP, CR_UNTRANSLATED, 1, -1, -1, 1, 1);
}
void DisplayFragString(PLAYERp pp, double xs, double ys, const char* buffer)
{
DisplayTinyString(xs, ys, buffer, User[pp->SpriteP - sprite]->spal);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayFragNumbers()
{
for (int pnum = 0; pnum < 4; pnum++)
{
char buffer[32];
short xs, ys;
short frag_bar;
static int xoffs[] =
{
69, 147, 225, 303
};
ys = FRAG_YOFF;
// frag bar 0 or 1
frag_bar = ((pnum) / 4);
// move y down according to frag bar number
ys = ys + (tileHeight(FRAG_BAR) - 2) * frag_bar;
// move x over according to the number of players
xs = xoffs[MOD4(pnum)];
mysnprintf(buffer, 32, "%03d", Player[pnum].Kills);
DisplayFragString(&Player[pnum], xs, ys, buffer);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayFragNames()
{
for (int pnum = 0; pnum < 4; pnum++)
{
short xs, ys;
short frag_bar;
static int xoffs[] =
{
7, 85, 163, 241
};
ys = FRAG_YOFF;
// frag bar 0 or 1
frag_bar = ((pnum) / 4);
// move y down according to frag bar number
ys = ys + (tileHeight(FRAG_BAR) - 2) * frag_bar;
// move x over according to the number of players
xs = xoffs[MOD4(pnum)];
DisplayFragString(&Player[pnum], xs, ys, Player[pnum].PlayerName);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayFragBar(PLAYERp pp)
{
// must draw this in HUD mode and align to the top center
short i, num_frag_bars;
int y;
if (numplayers <= 1)
return;
if (gNet.MultiGameType == MULTI_GAME_COOPERATIVE)
return;
// if player sprite has not been initialized we have no business
// sticking a frag bar up. Prevents processing from MenuLevel etc.
if (!pp->SpriteP)
return;
//num_frag_bars = ((numplayers-1)/4)+1;
num_frag_bars = ((OrigCommPlayers - 1) / 4) + 1;
for (i = windowxy1.x; i <= windowxy2.x; i++)
{
y = (tileHeight(FRAG_BAR) * num_frag_bars) - (2 * (num_frag_bars - 1));
y = y * (ydim / 200.0);
}
for (i = 0, y = 0; i < num_frag_bars; i++)
{
DrawGraphic(tileGetTexture(FRAG_BAR), 0, y, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1);
y += tileHeight(FRAG_BAR) - 2;
}
DisplayFragNames();
DisplayFragNumbers();
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void PlayerUpdateWeaponSummary(PLAYERp pp, int UpdateWeaponNum)
{
USERp u = User[pp->PlayerSprite].Data();
int x, y;
int pos;
int column;
int WeaponNum, wpntmp;
int color, shade;
char ds[32];
WeaponNum = UpdateWeaponNum;
if (DamageData[WeaponNum].with_weapon != -1)
{
WeaponNum = DamageData[WeaponNum].with_weapon;
}
static short wsum_xoff[3] = { 0,36,66 };
static const char* wsum_fmt2[3] = { "%3d/%-3d", "%2d/%-2d", "%2d/%-2d" };
pos = WeaponNum - 1;
column = pos / 3;
if (column > 2) column = 2;
x = WSUM_X + wsum_xoff[column];
y = WSUM_Y + (WSUM_YOFF * (pos % 3));
if (UpdateWeaponNum == u->WeaponNum)
{
shade = 0;
color = 0;
}
else
{
shade = 11;
color = 0;
}
wpntmp = WeaponNum + 1;
if (wpntmp > 9)
wpntmp = 0;
mysnprintf(ds, 32, "%d:", wpntmp);
if (TEST(pp->WpnFlags, BIT(WeaponNum)))
DisplaySummaryString(x, y, 1, shade, ds);
else
DisplaySummaryString(x, y, 2, shade + 6, ds);
mysnprintf(ds, 32, wsum_fmt2[column], pp->WpnAmmo[WeaponNum], DamageData[WeaponNum].max_ammo);
DisplaySummaryString(x + 6, y, color, shade, ds);
}
void PlayerUpdateWeaponSummaryAll(PLAYERp pp)
{
for (int i = WPN_STAR; i <= WPN_HEART; i++)
{
PlayerUpdateWeaponSummary(pp, i);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayKeys(PLAYERp pp, double xs, double ys, double scalex = 1, double scaley = 1)
{
double x, y;
int row, col;
int i, xsize, ysize;
static short StatusKeyPics[] =
{
PANEL_KEY_RED,
PANEL_KEY_BLUE,
PANEL_KEY_GREEN,
PANEL_KEY_YELLOW,
PANEL_SKELKEY_GOLD,
PANEL_SKELKEY_SILVER,
PANEL_SKELKEY_BRONZE,
PANEL_SKELKEY_RED
};
xsize = tileWidth(PANEL_KEY_RED) + 1;
ysize = tileHeight(PANEL_KEY_RED) + 2;
i = 0;
for (row = 0; row < 2; row++)
{
for (col = 0; col < 2; col++)
{
if (pp->HasKey[i])
{
x = xs + PANEL_KEYS_XOFF + (row * xsize);
y = ys + PANEL_KEYS_YOFF + (col * ysize);
DrawGraphic(tileGetTexture(StatusKeyPics[i]), x, y, DI_ITEM_LEFT_TOP, 1, -1, -1, scalex, scaley);
}
i++;
}
}
// Check for skeleton keys
i = 0;
for (row = 0; row < 2; row++)
{
for (col = 0; col < 2; col++)
{
if (pp->HasKey[i + 4])
{
x = xs + PANEL_KEYS_XOFF + (row * xsize);
y = ys + PANEL_KEYS_YOFF + (col * ysize);
DrawGraphic(tileGetTexture(StatusKeyPics[i + 4]), x, y, DI_ITEM_LEFT_TOP, 1, -1, -1, scalex, scaley);
}
i++;
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void PlayerUpdateInventoryPercent(PLAYERp pp, int InventoryBoxX, int InventoryBoxY, int InventoryXoff, int InventoryYoff)
{
char ds[32];
INVENTORY_DATAp id = &InventoryData[pp->InventoryNum];
int x = InventoryBoxX + INVENTORY_PERCENT_XOFF + InventoryXoff;
int y = InventoryBoxY + INVENTORY_PERCENT_YOFF + InventoryYoff;
if (TEST(id->Flags, INVF_COUNT))
{
mysnprintf(ds, 32, "%d", pp->InventoryAmount[pp->InventoryNum]);
}
else
{
mysnprintf(ds, 32, "%d%c", pp->InventoryPercent[pp->InventoryNum], '%');
}
DisplayTinyString(x, y, ds, 0);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void PlayerUpdateInventoryPic(PLAYERp pp, int InventoryBoxX, int InventoryBoxY, int InventoryXoff, int InventoryYoff)
{
INVENTORY_DATAp id = &InventoryData[pp->InventoryNum];
int x = InventoryBoxX + INVENTORY_PIC_XOFF + InventoryXoff;
int y = InventoryBoxY + INVENTORY_PIC_YOFF + InventoryYoff;
DrawGraphic(tileGetTexture(icons[pp->InventoryNum]), x, y, DI_ITEM_LEFT_TOP, 1, -1, -1, id->Scale/65536., id->Scale / 65536.);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void PlayerUpdateInventoryState(PLAYERp pp, double InventoryBoxX, double InventoryBoxY, int InventoryXoff, int InventoryYoff)
{
char ds[32];
INVENTORY_DATAp id = &InventoryData[pp->InventoryNum];
double x = InventoryBoxX + INVENTORY_STATE_XOFF + InventoryXoff;
double y = InventoryBoxY + INVENTORY_STATE_YOFF + InventoryYoff;
if (TEST(id->Flags, INVF_AUTO_USE))
{
DisplayTinyString(x, y, "AUTO", 0);
}
else if (TEST(id->Flags, INVF_TIMED))
{
DisplayTinyString(x, y, pp->InventoryActive[pp->InventoryNum] ? "ON" : "OFF", 0);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayBarInventory(PLAYERp pp)
{
int InventoryBoxX = INVENTORY_BOX_X;
int InventoryBoxY = INVENTORY_BOX_Y;
int InventoryXoff = -1;
int InventoryYoff = 0;
// put pic
if (pp->InventoryAmount[pp->InventoryNum])
{
PlayerUpdateInventoryPic(pp, InventoryBoxX, InventoryBoxY, 0, InventoryYoff);
// Auto/On/Off
PlayerUpdateInventoryState(pp, InventoryBoxX, InventoryBoxY, InventoryXoff, InventoryYoff);
// Percent count/Item count
PlayerUpdateInventoryPercent(pp, InventoryBoxX, InventoryBoxY, InventoryXoff, InventoryYoff);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DrawCompass(PLAYERp pp)
{
enum
{
COMPASS_TIC = 2380,
COMPASS_TIC2 = 2381,
COMPASS_NORTH = 2382,
COMPASS_NORTH2 = 2383,
COMPASS_SOUTH = 2384,
COMPASS_SOUTH2 = 2385,
COMPASS_EAST = 2386,
COMPASS_EAST2 = 2387,
COMPASS_WEST = 2388,
COMPASS_WEST2 = 2389,
COMPASS_MID_TIC = 2390,
COMPASS_MID_TIC2 = 2391,
COMPASS_X = 140,
COMPASS_Y = (162-5),
};
auto NORM_CANG = [](int ang) { return (((ang)+32) & 31); };
int start_ang, ang;
int x_size = tileWidth(COMPASS_NORTH);
int x;
int i;
static const short CompassPic[32] =
{
COMPASS_EAST, COMPASS_EAST2,
COMPASS_TIC, COMPASS_TIC2,
COMPASS_MID_TIC, COMPASS_MID_TIC2,
COMPASS_TIC, COMPASS_TIC2,
COMPASS_SOUTH, COMPASS_SOUTH2,
COMPASS_TIC, COMPASS_TIC2,
COMPASS_MID_TIC, COMPASS_MID_TIC2,
COMPASS_TIC, COMPASS_TIC2,
COMPASS_WEST, COMPASS_WEST2,
COMPASS_TIC, COMPASS_TIC2,
COMPASS_MID_TIC, COMPASS_MID_TIC2,
COMPASS_TIC, COMPASS_TIC2,
COMPASS_NORTH, COMPASS_NORTH2,
COMPASS_TIC, COMPASS_TIC2,
COMPASS_MID_TIC, COMPASS_MID_TIC2,
COMPASS_TIC, COMPASS_TIC2,
};
static const short CompassShade[10] =
{
//20, 16, 11, 6, 1, 1, 6, 11, 16, 20
25, 19, 15, 9, 1, 1, 9, 15, 19, 25
};
ang = pp->angle.ang.asbuild();
if (pp->sop_remote)
ang = 0;
start_ang = (ang + 32) >> 6;
start_ang = NORM_CANG(start_ang - 4);
for (i = 0, x = COMPASS_X; i < 10; i++)
{
DrawGraphic(tileGetTexture(CompassPic[NORM_CANG(start_ang + i)]), x, COMPASS_Y, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1, shadeToLight(CompassShade[i]));
x += x_size;
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DrawStatusBar()
{
auto pp = Player + screenpeek;
USERp u = User[pp->PlayerSprite].Data();
BeginStatusBar(320, 200, tileHeight(STATUS_BAR));
if (hud_size == Hud_StbarOverlay) Set43ClipRect();
int left = (320 - tileWidth(STATUS_BAR)) / 2;
DrawGraphic(tileGetTexture(STATUS_BAR), left, 200, DI_ITEM_LEFT_BOTTOM, 1, -1, -1, 1, 1);
twod->ClearClipRect();
DisplayPanelNumber(PANEL_HEALTH_BOX_X + PANEL_HEALTH_XOFF, PANEL_BOX_Y + PANEL_HEALTH_YOFF, u->Health);
DisplayPanelNumber(PANEL_ARMOR_BOX_X + PANEL_ARMOR_XOFF, PANEL_BOX_Y + PANEL_ARMOR_YOFF, pp->Armor);
if (u->WeaponNum != WPN_FIST && u->WeaponNum != WPN_SWORD)
DisplayPanelNumber(PANEL_AMMO_BOX_X + PANEL_AMMO_XOFF, PANEL_BOX_Y + PANEL_AMMO_YOFF, pp->WpnAmmo[u->WeaponNum]);
PlayerUpdateWeaponSummaryAll(pp);
if (gNet.MultiGameType != MULTI_GAME_COMMBAT)
DisplayKeys(pp, PANEL_KEYS_BOX_X, PANEL_BOX_Y);
else if (gNet.TimeLimit)
DisplayTimeLimit(pp);
DisplayBarInventory(pp);
DrawCompass(pp);
PrintLevelStats(-3);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DisplayMinibarInventory(PLAYERp pp)
{
int InventoryBoxX = MINI_BAR_INVENTORY_BOX_X;
int InventoryBoxY = MINI_BAR_INVENTORY_BOX_Y - 200;
int InventoryXoff = 0;
int InventoryYoff = 1;
if (pp->InventoryAmount[pp->InventoryNum])
{
PlayerUpdateInventoryPic(pp, InventoryBoxX, InventoryBoxY, InventoryXoff+1, InventoryYoff);
// Auto/On/Off
PlayerUpdateInventoryState(pp, InventoryBoxX, InventoryBoxY, InventoryXoff, InventoryYoff);
// Percent count/Item count
PlayerUpdateInventoryPercent(pp, InventoryBoxX, InventoryBoxY, InventoryXoff, InventoryYoff);
}
}
//---------------------------------------------------------------------------
//
// Used in DrawHUD2() for determining whether a reloadable weapon is reloading.
//
//---------------------------------------------------------------------------
bool DoReloadStatus(char *reloadstate, int ammo)
{
bool reloading = ammo == 0 && *reloadstate != 2;
if (ammo == 0 && *reloadstate == 0)
{
*reloadstate = 1;
}
else if (ammo)
{
*reloadstate = 0;
}
return reloading;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DrawHUD1()
{
BeginHUD(320, 200, 1);
auto pp = Player + screenpeek;
USERp u = User[pp->PlayerSprite].Data();
int x, y;
INVENTORY_DATAp id;
x = MINI_BAR_HEALTH_BOX_X;
y = -26;
DrawGraphic(tileGetTexture(MINI_BAR_HEALTH_BOX_PIC), x, y, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1);
x = MINI_BAR_HEALTH_BOX_X + 3;
DisplayPanelNumber(x, y + 5, u->Health);
if (u->WeaponNum != WPN_SWORD && u->WeaponNum != WPN_FIST)
{
x = MINI_BAR_AMMO_BOX_X;
DrawGraphic(tileGetTexture(MINI_BAR_AMMO_BOX_PIC), x, y, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1);
x = MINI_BAR_AMMO_BOX_X + 3;
DisplayPanelNumber(x, y + 5, pp->WpnAmmo[u->WeaponNum]);
}
PrintLevelStats(30);
if (!pp->InventoryAmount[pp->InventoryNum])
return;
// Inventory Box
x = MINI_BAR_INVENTORY_BOX_X;
DrawGraphic(tileGetTexture(MINI_BAR_INVENTORY_BOX_PIC), x, y, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1);
DisplayMinibarInventory(pp);
}
//==========================================================================
//
// Fullscreen HUD variant #1
//
//==========================================================================
void DrawHUD2()
{
BeginHUD(320, 200, 1);
auto pp = Player + screenpeek;
USERp u = User[pp->PlayerSprite].Data();
FString format;
FGameTexture* img;
double imgScale;
double baseScale = numberFont->mFont->GetHeight() * 0.83125;
//
// Health
//
img = tileGetTexture(ICON_SM_MEDKIT);
imgScale = baseScale / img->GetDisplayHeight();
DrawGraphic(img, 1.5, -1, DI_ITEM_LEFT_BOTTOM, 1., -1, -1, imgScale, imgScale);
if (!althud_flashing || u->Health > (u->MaxHealth >> 2) || (PlayClock & 32))
{
int s = -8;
if (althud_flashing && u->Health > u->MaxHealth)
s += bsin(PlayClock << 5, -10);
int intens = clamp(255 - 4 * s, 0, 255);
auto pe = PalEntry(255, intens, intens, intens);
format.Format("%d", u->Health);
SBar_DrawString(this, numberFont, format, 24.25, -numberFont->mFont->GetHeight() + 2, DI_TEXT_ALIGN_LEFT, CR_UNTRANSLATED, 1, 0, 0, 1, 1);
}
//
// Armor
//
img = tileGetTexture(ICON_ARMOR);
imgScale = baseScale / img->GetDisplayHeight();
DrawGraphic(img, 80.75, -1, DI_ITEM_LEFT_BOTTOM, 1., -1, -1, imgScale, imgScale);
format.Format("%d", pp->Armor);
SBar_DrawString(this, numberFont, format, 108.5, -numberFont->mFont->GetHeight() + 2, DI_TEXT_ALIGN_LEFT, CR_UNTRANSLATED, 1, 0, 0, 1, 1);
//
// Weapon
//
const short ammo_sprites[] = { -1, ICON_STAR, ICON_LG_SHOTSHELL, ICON_LG_UZI_AMMO, ICON_MICRO_BATTERY, ICON_LG_GRENADE, ICON_LG_MINE, ICON_RAIL_AMMO,
ICON_FIREBALL_LG_AMMO, ICON_HEART_LG_AMMO, ICON_FIREBALL_LG_AMMO, ICON_FIREBALL_LG_AMMO,ICON_MICRO_BATTERY, -1 };
int weapon = u->WeaponNum;
int wicon = ammo_sprites[weapon];
if (wicon > 0)
{
int ammo = pp->WpnAmmo[weapon];
bool reloadableWeapon = weapon == WPN_SHOTGUN || weapon == WPN_UZI;
if (!reloadableWeapon || (reloadableWeapon && !cl_showmagamt))
{
format.Format("%d", ammo);
}
else
{
short capacity;
switch (weapon)
{
case WPN_SHOTGUN:
capacity = 4;
break;
case WPN_UZI:
capacity = pp->WpnUziType ? 50 : 100;
break;
}
short clip = CalcMagazineAmount(ammo, capacity, DoReloadStatus(&pp->WpnReloadState, ammo % capacity));
format.Format("%d/%d", clip, ammo - clip);
}
img = tileGetTexture(wicon);
imgScale = baseScale / img->GetDisplayHeight();
auto imgX = 21.125;
auto strlen = format.Len();
if (strlen > 1)
{
imgX += (imgX * 0.855) * (strlen - 1);
}
if ((!althud_flashing || PlayClock & 32 || ammo > (DamageData[weapon].max_ammo / 10)))
{
SBar_DrawString(this, numberFont, format, -1.5, -numberFont->mFont->GetHeight() + 2, DI_TEXT_ALIGN_RIGHT, CR_UNTRANSLATED, 1, 0, 0, 1, 1);
}
DrawGraphic(img, -imgX, -1, DI_ITEM_RIGHT_BOTTOM, 1, -1, -1, imgScale, imgScale);
}
//
// Selected inventory item
//
img = tileGetTexture(icons[pp->InventoryNum]);
imgScale = baseScale / img->GetDisplayHeight();
int x = 165;
DrawGraphic(img, x, -1, DI_ITEM_LEFT_BOTTOM, 1, -1, -1, imgScale, imgScale);
PlayerUpdateInventoryState(pp, x + 3.0, -18.0, 1, 1);
PlayerUpdateInventoryPercent(pp, x + 3.5, -20.5, 1, 1);
//
// keys
//
DisplayKeys(pp, -25, -38, 0.8625, 0.8625);
PrintLevelStats(int(baseScale + 4));
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DrawInventoryIcon(double xs, double ys, int align, int InventoryNum, int amount, bool selected)
{
double x, y;
const int INVENTORY_ICON_WIDTH = 28;
// check invalid value
assert(InventoryNum < MAX_INVENTORY);
x =xs + (InventoryNum * INVENTORY_ICON_WIDTH);
y = ys;
auto tex = icons[InventoryNum];
auto scale = InventoryData[InventoryNum].Scale / 65536.;
DrawGraphic(tileGetTexture(tex), x, y, align | DI_ITEM_LEFT_TOP, amount? 1. : 0.333, -1, -1, scale, scale);
if (selected)
{
DrawGraphic(tileGetTexture(ID_SelectionBox), x-5, y-5, align | DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1);
}
}
//////////////////////////////////////////////////////////////////////
//
// INVENTORY BAR
//
//////////////////////////////////////////////////////////////////////
void DrawInventory(double xs, double ys, int align)
{
auto pp = Player + screenpeek;
short inv = 0;
INVENTORY_DATAp id;
if (!pp->InventoryBarTics)
{
return;
}
for (id = InventoryData; id->Name; id++, inv++)
{
DrawInventoryIcon(xs, ys, align, inv, pp->InventoryAmount[inv], inv == pp->InventoryNum);
}
}
//==========================================================================
//
// Statistics output
//
//==========================================================================
void PrintLevelStats(int bottomy)
{
FLevelStats stats{};
stats.fontscale = 1;
stats.spacing = 7;
stats.screenbottomspace = bottomy;
stats.font = SmallFont;
stats.time = Scale(PlayClock, 1000, 120);
if (automapMode == am_full)
{
stats.letterColor = CR_SAPPHIRE;
stats.standardColor = CR_UNTRANSLATED;
bool textfont = am_textfont;
if (!am_textfont)
{
// For non-English languages force use of the text font. The tiny one is simply too small to ever add localized characters to it.
auto p = GStrings["REQUIRED_CHARACTERS"];
if (p && *p) textfont = true;
}
if (!textfont)
{
stats.font = SmallFont2;
stats.spacing = 6;
}
else stats.spacing = SmallFont->GetHeight() + 1;
DBaseStatusBar::PrintAutomapInfo(stats, textfont);
}
// JBF 20040124: display level stats in screen corner
else if (hud_stats && !(CommEnabled || numplayers > 1))
{
auto pp = Player + screenpeek;
stats.kills = Player->Kills;
stats.maxkills = TotalKillable;
stats.frags = -1;
stats.secrets = Player->SecretsFound;
stats.maxsecrets = LevelSecrets;
stats.letterColor = CR_RED;
stats.standardColor = CR_TAN;
stats.completeColor = CR_FIRE;
DBaseStatusBar::PrintLevelStats(stats);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
public:
void UpdateStatusBar()
{
int nPalette = 0;
double inv_x, inv_y;
int align;
if (hud_size == Hud_Nothing)
{
align = DI_SCREEN_RIGHT_BOTTOM;
inv_x = -210;
inv_y = -28;
PrintLevelStats(2);
}
else if (hud_size == Hud_full)
{
align = DI_SCREEN_CENTER_BOTTOM;
inv_x = -80;
inv_y = -40;
DrawHUD2();
}
else if (hud_size == Hud_Mini)
{
align = DI_SCREEN_RIGHT_BOTTOM;
inv_x = -210;
inv_y = -28;
DrawHUD1();
}
else
{
align = 0;
inv_x = 80;
inv_y = 130;
DrawStatusBar();
}
DrawInventory(inv_x, inv_y, align);
}
};
IMPLEMENT_CLASS(DSWStatusBar, false, true)
IMPLEMENT_POINTERS_START(DSWStatusBar)
IMPLEMENT_POINTER(miniFont)
IMPLEMENT_POINTER(numberFont)
IMPLEMENT_POINTERS_END
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
static void UpdateFrame(void)
{
static const int kBackTile = 51;
auto tex = tileGetTexture(kBackTile);
twod->AddFlatFill(0, 0, xdim, windowxy1.y - 3, tex);
twod->AddFlatFill(0, windowxy2.y + 4, xdim, ydim, tex);
twod->AddFlatFill(0, windowxy1.y - 3, windowxy1.x - 3, windowxy2.y + 4, tex);
twod->AddFlatFill(windowxy2.x + 4, windowxy1.y - 3, xdim, windowxy2.y + 4, tex);
twod->AddFlatFill(windowxy1.x - 3, windowxy1.y - 3, windowxy1.x, windowxy2.y + 1, tex, 0, 1, 0xff545454);
twod->AddFlatFill(windowxy1.x, windowxy1.y - 3, windowxy2.x + 4, windowxy1.y, tex, 0, 1, 0xff545454);
twod->AddFlatFill(windowxy2.x + 1, windowxy1.y, windowxy2.x + 4, windowxy2.y + 4, tex, 0, 1, 0xff2a2a2a);
twod->AddFlatFill(windowxy1.x - 3, windowxy2.y + 1, windowxy2.x + 1, windowxy2.y + 4, tex, 0, 1, 0xff2a2a2a);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DrawConString(int x, int y, const char* string, double alpha)
{
x = x * 2 - SmallFont->StringWidth(string) / 2;
y *= 2;
DrawText(twod, SmallFont, CR_TAN, x, y, string, DTA_FullscreenScale, FSMode_Fit640x400, DTA_Alpha, alpha, TAG_DONE);
}
void UpdateStatusBar()
{
if (hud_size <= Hud_Stbar)
{
UpdateFrame();
}
StatusBar->UpdateStatusBar();
PLAYERp pp = &Player[screenpeek];
if (pp->cookieTime > 0)
{
const int MESSAGE_LINE = 142; // Used to be 164
if (!SmallFont2->CanPrint(pp->cookieQuote))
DrawConString(160, MESSAGE_LINE, pp->cookieQuote, clamp(pp->cookieTime / 60., 0., 1.));
else
MNU_DrawSmallString(160, MESSAGE_LINE, pp->cookieQuote, 0, 0, 0, clamp(pp->cookieTime / 60., 0., 1.));
}
}
END_SW_NS