- ported Exhumed's status bar.

Not tested yet.
This commit is contained in:
Christoph Oelckers 2021-05-13 22:28:02 +02:00
parent 5a6121d424
commit b71c725e3e
11 changed files with 997 additions and 30 deletions

View file

@ -829,10 +829,10 @@ void CreateStatusBar()
StatusBar->SetSize(0, 320, 200);
InitStatusBar();
// this is for comparing the scriptification with the C++ versions
//stbarclass = PClass::FindClass("NativeBloodStatusBar");
//StatusBar2 = static_cast<DBaseStatusBar*>(stbarclass->CreateNew());
//StatusBar2->SetSize(0, 320, 200);
//StatusBar2->Release();
stbarclass = PClass::FindClass("NativeExhumedStatusBar");
StatusBar2 = static_cast<DBaseStatusBar*>(stbarclass->CreateNew());
StatusBar2->SetSize(0, 320, 200);
StatusBar2->Release();
}

View file

@ -203,17 +203,17 @@ static void cmd_Give(int player, uint8_t** stream, bool skip)
if (buttons & kButtonCheatGuns) // LOBOCOP cheat
{
FillWeapons(player);
if (player == myconnectindex) StatusMessage(150, GStrings("TXT_EX_WEAPONS"));
if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_WEAPONS"));
}
if (buttons & kButtonCheatKeys) // LOBOPICK cheat
{
PlayerList[player].keys = 0xFFFF;
if (player == myconnectindex) StatusMessage(150, GStrings("TXT_EX_KEYS"));
if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_KEYS"));
}
if (buttons & kButtonCheatItems) // LOBOSWAG cheat
{
FillItems(player);
if (player == myconnectindex) StatusMessage(150, GStrings("TXT_EX_ITEMS"));
if (player == myconnectindex) Printf(PRINT_NOTIFY, "%s\n", GStrings("TXT_EX_ITEMS"));
}
}

View file

@ -1,3 +1,13 @@
x(Torch1, 338)
x(Torch2, 350)
x(TileRamsesGold, 590)
x(TileRamsesWorkTile, 591)
x(TileRamsesNormal, 592)
x(TileStatusBar, 657)
x(KeyIcon1, 675)
x(KeyIcon2, 679)
x(KeyIcon3, 683)
x(KeyIcon4, 687)
x(CrosshairTile, 1579)
x(SkullJaw, 3437)
x(PowerslaveLogo, 3442)

View file

@ -20,12 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
enum
{
kTorch1 = 338,
kTorch2 = 350,
kTileRamsesGold = 590,
kTileRamsesWorkTile = 591,
kTileRamsesNormal = 592,
kTileStatusBar = 657,
kTile985 = 985,
kTile986 = 986,
kTile3000 = 3000,

View file

@ -2760,4 +2760,54 @@ void SerializePlayer(FSerializer& arc)
}
}
DEFINE_FIELD_X(ExhumedPlayer, Player, nHealth);
DEFINE_FIELD_X(ExhumedPlayer, Player, nLives);
DEFINE_FIELD_X(ExhumedPlayer, Player, nDouble);
DEFINE_FIELD_X(ExhumedPlayer, Player, nInvisible);
DEFINE_FIELD_X(ExhumedPlayer, Player, nTorch);
DEFINE_FIELD_X(ExhumedPlayer, Player, field_2);
DEFINE_FIELD_X(ExhumedPlayer, Player, nAction);
DEFINE_FIELD_X(ExhumedPlayer, Player, nSprite);
DEFINE_FIELD_X(ExhumedPlayer, Player, bIsMummified);
DEFINE_FIELD_X(ExhumedPlayer, Player, invincibility);
DEFINE_FIELD_X(ExhumedPlayer, Player, nAir);
DEFINE_FIELD_X(ExhumedPlayer, Player, nSeq);
DEFINE_FIELD_X(ExhumedPlayer, Player, nMaskAmount);
DEFINE_FIELD_X(ExhumedPlayer, Player, keys);
DEFINE_FIELD_X(ExhumedPlayer, Player, nMagic);
DEFINE_FIELD_X(ExhumedPlayer, Player, nItem);
DEFINE_FIELD_X(ExhumedPlayer, Player, items);
DEFINE_FIELD_X(ExhumedPlayer, Player, nAmmo); // TODO - kMaxWeapons?
DEFINE_FIELD_X(ExhumedPlayer, Player, pad);
DEFINE_FIELD_X(ExhumedPlayer, Player, nCurrentWeapon);
DEFINE_FIELD_X(ExhumedPlayer, Player, field_3FOUR);
DEFINE_FIELD_X(ExhumedPlayer, Player, bIsFiring);
DEFINE_FIELD_X(ExhumedPlayer, Player, field_38);
DEFINE_FIELD_X(ExhumedPlayer, Player, field_3A);
DEFINE_FIELD_X(ExhumedPlayer, Player, field_3C);
DEFINE_FIELD_X(ExhumedPlayer, Player, nRun);
DEFINE_FIELD_X(ExhumedPlayer, Player, bPlayerPan);
DEFINE_FIELD_X(ExhumedPlayer, Player, bLockPan);
DEFINE_ACTION_FUNCTION(_Exhumed, GetViewPlayer)
{
ACTION_RETURN_POINTER(&PlayerList[nLocalPlayer]);
}
DEFINE_ACTION_FUNCTION(_ExhumedPlayer, IsUnderwater)
{
PARAM_SELF_STRUCT_PROLOGUE(Player);
auto nLocalPlayer = self - PlayerList;
ACTION_RETURN_BOOL(SectFlag[nPlayerViewSect[nLocalPlayer]] & kSectUnderwater);
}
DEFINE_ACTION_FUNCTION(_ExhumedPlayer, GetAngle)
{
PARAM_SELF_STRUCT_PROLOGUE(Player);
ACTION_RETURN_INT(sprite[self->nSprite].ang);
}
END_PS_NS

View file

@ -65,7 +65,7 @@ struct Player
uint16_t keys;
short nMagic;
short nItem;
char items[8];
uint8_t items[8];
short nAmmo[7]; // TODO - kMaxWeapons?
short pad[2];

View file

@ -47,9 +47,77 @@ void InitStatus()
nStatusSeqOffset = SeqOffsets[kSeqStatus];
}
class DExhumedStatusBar : public DBaseStatusBar
//---------------------------------------------------------------------------
//
// This is to hide the dirt from the script code.
// These sequence arrays later need to be refactored
// if this is ever supposed to become a useful feature,
// so hide the dirty internals behind a handful of functions.
//
//---------------------------------------------------------------------------
struct ChunkFrame
{
DECLARE_CLASS(DExhumedStatusBar, DBaseStatusBar)
FTextureID tex;
int x, y;
int flags;
void GetChunkFrame(int nFrameBase)
{
x = ChunkXpos[nFrameBase];
y = ChunkYpos[nFrameBase];
auto ttex = tileGetTexture(nFrameBase);
if (ttex) tex = ttex->GetID();
else tex.SetInvalid();
flags = ChunkFlag[nFrameBase];
}
};
DEFINE_ACTION_FUNCTION(_ChunkFrame, GetChunkFrame)
{
PARAM_SELF_STRUCT_PROLOGUE(ChunkFrame);
PARAM_INT(index);
self->GetChunkFrame(index);
return 0;
}
DEFINE_ACTION_FUNCTION(_Exhumed, GetStatusSequence)
{
PARAM_PROLOGUE;
PARAM_INT(nSequence);
PARAM_INT(frameindex);
frameindex += SeqBase[nStatusSeqOffset + nSequence];
if (numret > 0) ret[0].SetInt(FrameBase[frameindex]);
if (numret > 1) ret[1].SetInt(FrameSize[frameindex]);
return min(numret, 2);
}
DEFINE_ACTION_FUNCTION(_Exhumed, MoveStatusSequence)
{
PARAM_PROLOGUE;
PARAM_INT(s1);
PARAM_INT(s2);
seq_MoveSequence(-1, nStatusSeqOffset + s1, s2);
ACTION_RETURN_INT(SeqSize[nStatusSeqOffset + s1]);
}
int SizeOfStatusSequence(int s1)
{
return SeqSize[nStatusSeqOffset + s1];
}
DEFINE_ACTION_FUNCTION_NATIVE(_Exhumed, SizeOfStatusSequence, SizeOfStatusSequence)
{
PARAM_PROLOGUE;
PARAM_INT(s1);
ACTION_RETURN_INT(SeqSize[nStatusSeqOffset + s1]);
}
class DNativeExhumedStatusBar : public DBaseStatusBar
{
DECLARE_CLASS(DNativeExhumedStatusBar, DBaseStatusBar)
HAS_OBJECT_POINTERS
TObjPtr<DHUDFont*> textfont, numberFont;
@ -81,7 +149,7 @@ class DExhumedStatusBar : public DBaseStatusBar
};
public:
DExhumedStatusBar()
DNativeExhumedStatusBar()
{
textfont = Create<DHUDFont>(SmallFont, 1, Off, 1, 1);
numberFont = Create<DHUDFont>(BigFont, 0, Off, 1, 1);
@ -505,12 +573,6 @@ private:
}
DrawMulti();
if (nSnakeCam >= 0)
{
BeginHUD(320, 200, 1);
SBar_DrawString(this, textfont, "S E R P E N T C A M", 0, 0, DI_TEXT_ALIGN_CENTER | DI_SCREEN_CENTER_TOP, CR_UNTRANSLATED, 1, -1, 0, 1, 1);
}
}
//---------------------------------------------------------------------------
@ -898,8 +960,8 @@ public:
}
};
IMPLEMENT_CLASS(DExhumedStatusBar, false, true)
IMPLEMENT_POINTERS_START(DExhumedStatusBar)
IMPLEMENT_CLASS(DNativeExhumedStatusBar, false, true)
IMPLEMENT_POINTERS_START(DNativeExhumedStatusBar)
IMPLEMENT_POINTER(textfont)
IMPLEMENT_POINTER(numberFont)
IMPLEMENT_POINTERS_END
@ -928,7 +990,7 @@ void StatusMessage(int messageTime, const char* fmt, ...)
va_end(ap);
}
CVAR(Bool, sb_native, false, 0)
void DrawStatusBar()
{
if (nFreeze == 2) return; // Hide when Ramses is talking.
@ -936,7 +998,21 @@ void DrawStatusBar()
{
UpdateFrame();
}
StatusBar->UpdateStatusBar();
SummaryInfo info{};
info.kills = nCreaturesKilled;
info.maxkills = nCreaturesTotal;
// got no secrets in the game
info.time = Scale(PlayClock, 1000, 120);
if (!sb_native) UpdateStatusBar(&info);
else StatusBar2->UpdateStatusBar();
if (nSnakeCam >= 0)
{
const char* text = "S E R P E N T C A M";
int width = SmallFont->StringWidth(text);
DrawText(twod, SmallFont, CR_UNTRANSLATED, 160 - width / 2, 1, text, DTA_FullscreenScale, FSMode_Fit320x200, TAG_DONE);
}
}
END_PS_NS

View file

@ -43,4 +43,5 @@ version "4.3"
#include "zscript/games/sw/ui/screens.zs"
#include "zscript/games/exhumed/exhumedgame.zs"
#include "zscript/games/exhumed/ui/menu.zs"
#include "zscript/games/exhumed/ui/sbar.zs"
#include "zscript/games/exhumed/ui/screens.zs"

View file

@ -7,14 +7,17 @@ struct Exhumed native
native static bool LocalSoundPlaying();
native static void playCDTrack(int track, bool looped);
native static void DrawPlasma();
native static int, int GetStatusSequence(int seq, int index);
native static int MoveStatusSequence(int s1, int s2);
native static int SizeOfStatusSequence(int s1);
native static ExhumedPlayer GetViewPlayer();
static void DrawAbs(String img, int x, int y, int shade = 0)
{
Screen.DrawTexture(TexMan.CheckForTexture(img, TexMan.Type_Any), false, x, y, DTA_FullscreenScale, FSMode_Fit320x200, DTA_TopLeft, true, DTA_Color, Raze.shadeToLight(shade));
}
static void DRawRel(String img, int x, int y, int shade = 0)
static void DrawRel(String img, int x, int y, int shade = 0)
{
let tex = TexMan.CheckForTexture(img, TexMan.Type_Any);
if (!tex.IsValid()) return;
@ -27,6 +30,56 @@ struct Exhumed native
}
}
struct ExhumedPlayer native
{
native int16 nHealth;
native int16 nLives;
native int16 nDouble;
native int16 nInvisible;
native int16 nTorch;
native int16 field_2;
native int16 nAction;
native int16 nSprite;
native int16 bIsMummified;
native int16 invincibility;
native int16 nAir;
native int16 nSeq;
native int16 nMaskAmount;
native uint16 keys;
native int16 nMagic;
native int16 nItem;
native uint8 items[8];
native int16 nAmmo[7]; // TODO - kMaxWeapons?
native int16 pad[2];
native int16 nCurrentWeapon;
native int16 field_3FOUR;
native int16 bIsFiring;
native int16 field_38;
native int16 field_3A;
native int16 field_3C;
native int16 nRun;
native bool bPlayerPan, bLockPan;
//fixedhoriz nDestVertPan;
//PlayerHorizon horizon;
//PlayerAngle angle;
native bool IsUnderwater();
native int GetAngle();
}
enum EEWeap
{
kWeaponSword = 0,
kWeaponPistol,
kWeaponM60,
kWeaponFlamer,
kWeaponGrenade,
kWeaponStaff,
kWeaponRing,
kWeaponMummified
}
struct ExhumedSnd native
{

View file

@ -0,0 +1,781 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 sirlemonhead, 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.
*/
//-------------------------------------------------------------------------
struct ChunkFrame // this wraps the internal (mis-)representation of the chunk data.
{
TextureID tex;
int x, y;
int flags;
native void GetChunkFrame(int nFrameBase);
}
class ExhumedStatusBar : RazeStatusBar
{
HUDFont textfont, numberFont;
int keyanims[4];
int airframe, lungframe;
int nSelectedItem;
int nHealthLevel;
int nMagicLevel;
int nMeterRange;
int nHurt;
int nHealthFrame;
int nMagicFrame;
int nItemAltSeq;
int nItemSeq;
int nItemFrames;
int nItemFrame;
int totalmoves;
int nCounter;
int nCounterDest;
int nDigit[3];
int ammodelay;
int nLastWeapon;
enum EConst
{
KeySeq = 36,
}
override void Init()
{
textfont = HUDFont.Create(SmallFont, 1, Mono_Off, 1, 1);
numberFont = HUDFont.Create(BigFont, 0, Mono_Off, 1, 1);
let nPicNum = GetStatusSequencePic(0, 0);
let siz = TexMan.GetScaledSize(nPicNum);
nMeterRange = siz.Y;
Reset();
}
override void Reset()
{
airframe = lungframe = nHurt = nHealthFrame = nMagicFrame = nItemAltSeq = nItemFrames = nItemFrame = nCounter = 0;
nDigit[0] = nDigit[1] = nDigit[2] = 0;
nHealthLevel = -1;
nMagicLevel = -1;
nSelectedItem = -1;
nItemSeq = -1;
ammodelay = 3;
nLastWeapon = -1;
totalmoves = 0;
nCounterDest = 0;
}
//---------------------------------------------------------------------------
//
// draws a sequence animation to the status bar
//
//---------------------------------------------------------------------------
void DrawStatusSequence(int nSequence, int frameindex, double yoffset, double xoffset = 0)
{
int nFrameBase, nFrameSize;
[nFrameBase, nFrameSize] = Exhumed.GetStatusSequence(nSequence, frameindex);
for(; nFrameSize > 0; nFrameSize--, nFrameBase++)
{
int flags = 0;
ChunkFrame chunk;
chunk.GetChunkFrame(nFrameBase);
double x = chunk.x + xoffset;
double y = chunk.y + yoffset;
if (hud_size <= Hud_StbarOverlay)
{
x += 161;
y += 100;
}
else
{
if (x < 0)
{
x += 160;
flags |= DI_SCREEN_LEFT_BOTTOM;
}
else if (x > 0)
{
x -= 159; // graphics do not match up precisely.
flags |= DI_SCREEN_RIGHT_BOTTOM;
}
y -= 100;
}
if (chunk.flags & 3)
{
// This is hard to align with bad offsets, so skip that treatment for mirrored elements.
flags |= DI_ITEM_RELCENTER;
}
else
{
let tsiz = TexMan.GetScaledSize(chunk.tex);
x -= tsiz.x * .5;
y -= tsiz.y * .5;
flags |= DI_ITEM_OFFSETS;
}
if (chunk.flags & 1)
flags |= DI_MIRROR;
if (chunk.flags & 2)
flags |= DI_MIRRORY;
DrawTexture(chunk.tex, (x, y), flags);
}
}
//---------------------------------------------------------------------------
//
// draws a sequence animation to the status bar
//
//---------------------------------------------------------------------------
TextureID GetStatusSequencePic(int nSequence, int frameindex)
{
int nFrameBase = Exhumed.GetStatusSequence(nSequence, frameindex);
ChunkFrame chunk;
chunk.GetChunkFrame(nFrameBase);
return chunk.tex;
}
//---------------------------------------------------------------------------
//
// Frag display - very ugly and may have to be redone if multiplayer support gets added.
//
//---------------------------------------------------------------------------
void DrawMulti()
{
/*
char stringBuf[30];
if (netgame)
{
BeginHUD(1, false, 320, 200);
int shade;
if ((PlayClock / 120) & 1)
shade = -100;
else
shade = 127;
int nTile = 3593;
int xx = 320 / (nTotalPlayers + 1);
int x = xx - 160;
for (int i = 0; i < nTotalPlayers; i++)
{
DrawImage(String.Format("#%05d", nTile)), (x, 7), DI_ITEM_CENTER);
if (i != nLocalPlayer) {
shade = -100;
}
sprintf(stringBuf, "%d", nPlayerScore[i]);
DrawString(this, textfont, stringBuf, x, 0, DI_ITEM_TOP | DI_TEXT_ALIGN_CENTER, i != nLocalPlayer ? CR_UNTRANSLATED : CR_GOLD, 1, -1, 0, 1, 1);
x += xx;
nTile++;
}
}
*/
}
//==========================================================================
//
// Fullscreen HUD variant #1
//
//==========================================================================
int ItemTimer(ExhumedPlayer pPlayer, int num)
{
switch (num) {
case 1: //Scarab item
return (pPlayer.invincibility * 100) / 900;
case 3: //Hand item
return (pPlayer.nDouble * 100) / 1350;
case 5: //Mask
return (pPlayer.nMaskAmount * 100) / 1350;
case 4: //Invisible
return (pPlayer.nInvisible * 100) / 900;
case 2: //Torch
return (pPlayer.nTorch * 100) / 900;
}
return -1;
}
void DrawHUD2(ExhumedPlayer pp)
{
BeginHUD(1, false, 320, 200);
String format;
TextureID img;
double imgScale;
double baseScale = numberFont.mFont.GetHeight() * 0.75;
//
// Health
//
img = GetStatusSequencePic(125, 0);
let size = TexMan.GetScaledSize(img);
imgScale = baseScale / size.Y;
DrawTexture(img, (1.5, -1), DI_ITEM_LEFT_BOTTOM, scale:(imgScale, imgScale));
if (!hud_flashing || pp.nHealth > 150 || (PlayClock & 32))
{
int s = -8;
if (hud_flashing && pp.nHealth > 800)
s += Raze.bsin(PlayClock << 5, -10);
int intens = clamp(255 - 4 * s, 0, 255);
format = String.Format("%d", pp.nHealth >> 3);
DrawString(numberFont, format, (13, -numberFont.mFont.GetHeight() + 3), DI_TEXT_ALIGN_LEFT, intens / 255.);
}
//
// Air
//
if (pp.isUnderwater())
{
img = GetStatusSequencePic(133, airframe);
let size = TexMan.GetScaledSize(img);
imgScale = baseScale / size.Y;
DrawTexture(img, (-4, -22), DI_ITEM_RIGHT_BOTTOM, scale:(imgScale, imgScale));
}
//
// Magic
//
if (nItemSeq >= 0)
{
img = GetStatusSequencePic(nItemSeq, nItemFrame);
//int tile = GetStatusSequenceTile(nItemSeq, nItemFrame);
//int tile2 = tile;
//if (tile2 > 744 && tile2 < 751) tile2 = 744;
let size = TexMan.GetScaledSize(img);
imgScale = baseScale / size.Y;
DrawTexture(img, (70, -1), DI_ITEM_CENTER_BOTTOM, scale:(imgScale, imgScale));
format = String.Format("%d", pp.nMagic / 10);
int nItem = pp.nItem;
int timer = ItemTimer(pp, nItem);
if (timer > 0)
{
format.AppendFormat("/%d", timer);
}
DrawString(numberFont, format, (79.5, -numberFont.mFont.GetHeight() + 3), DI_TEXT_ALIGN_LEFT);
}
//
// Weapon
//
int weapon = pp.nCurrentWeapon;
int ammo = nCounterDest;
if (ammo > 0) // wicon > 0
{
format = String.Format("%d", ammo);
/* non-implemented weapon icon.
int wicon = 0;// ammo_sprites[weapon];
img = tileGetTexture(wicon);
imgScale = baseScale / img.GetDisplayHeight();
let imgX = 21.125;
let strlen = format.Len();
if (strlen > 1)
{
imgX += (imgX * 0.855) * (strlen - 1);
}
*/
if ((!hud_flashing || PlayClock & 32 || ammo > 10))// (DamageData[weapon].max_ammo / 10)))
{
DrawString(numberFont, format, (-3, -numberFont.mFont.GetHeight() + 3), DI_TEXT_ALIGN_RIGHT);
}
//DrawGraphic(img, (-imgX, -1), DI_ITEM_RIGHT_BOTTOM, scale:(imgScale, imgScale));
}
//
// keys
//
int nKeys = pp.keys;
int x = -134;
for (int i = 0; i < 4; i++)
{
if (nKeys & (0x1000 << i))
{
DrawImage(String.Format("KeyIcon%d", i+1), (x, -2), DI_ITEM_LEFT_BOTTOM);
}
x += 20;
}
}
//---------------------------------------------------------------------------
//
// draw the full status bar
//
//---------------------------------------------------------------------------
void DrawStatus(ExhumedPlayer pp)
{
if (hud_size <= Hud_StbarOverlay)
{
// draw the main bar itself
BeginStatusBar(false, 320, 200, 40);
if (hud_size == Hud_StbarOverlay) Set43ClipRect();
DrawImage("TileStatusBar", (160, 200), DI_ITEM_CENTER_BOTTOM);
screen.ClearClipRect();
}
else if (hud_size == Hud_Mini)
{
BeginHUD(1, false, 320, 200);
DrawImage("hud_l", (0, 0), DI_ITEM_LEFT_BOTTOM | DI_SCREEN_LEFT_BOTTOM);
DrawImage("hud_r", (0, 0), DI_ITEM_RIGHT_BOTTOM | DI_SCREEN_RIGHT_BOTTOM);
}
else if (hud_size == Hud_full)
{
DrawHUD2(pp);
return;
}
for (int i = 0; i < 4; i++)
{
if (pp.keys & (4096 << i))
{
DrawStatusSequence(KeySeq + 2 * i, keyanims[i], 0.5, 0.5);
}
}
//if (/*!bFullScreen &&*/ nNetTime)
{
DrawStatusSequence(127, 0, 0);
DrawStatusSequence(129, nMagicFrame, nMagicLevel);
DrawStatusSequence(131, 0, 0); // magic pool frame (bottom)
DrawStatusSequence(128, 0, 0);
DrawStatusSequence(1, nHealthFrame, nHealthLevel);
DrawStatusSequence(125, 0, 0); // draw ankh on health pool
DrawStatusSequence(130, 0, 0); // draw health pool frame (top)
// Item on the magic pool
if (nItemSeq >= 0) DrawStatusSequence(nItemSeq, nItemFrame, 1);
// draw the blue air level meter when underwater
if (pp.isUnderwater()) DrawStatusSequence(133, airframe, 0, 0.5);
else DrawStatusSequence(132, lungframe, 0);
// item count dots.
if (nSelectedItem >= 0)
{
int count = pp.items[nSelectedItem];
DrawStatusSequence(156 + 2 * count, 0, 0);
}
// life dots.
DrawStatusSequence(145 + (2 * pp.nLives), 0, 0);
if (nHurt > 0) DrawStatusSequence(4, nHurt - 1, 0);
// draw compass
if (hud_size <= Hud_StbarOverlay) DrawStatusSequence(35, ((pp.GetAngle() + 128) & Raze.kAngleMask) >> 8, 0, 0.5);
//if (hud_size < Hud_full)
{
// draw ammo count
DrawStatusSequence(44, nDigit[2], 0, 0.5);
DrawStatusSequence(45, nDigit[1], 0, 0.5);
DrawStatusSequence(46, nDigit[0], 0, 0.5);
}
}
DrawMulti();
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void DoLevelStats(int bottomy, Summaryinfo summary)
{
StatsPrintInfo stats;
stats.fontscale = 1.;
stats.spacing = SmallFont.GetHeight();
stats.screenbottomspace = bottomy;
stats.statfont = SmallFont;
stats.letterColor = TEXTCOLOR_RED;
stats.standardColor = TEXTCOLOR_UNTRANSLATED;
if (automapMode == am_full)
{
PrintAutomapInfo(stats, true);
}
else if (automapMode == am_off && hud_stats)
{
stats.completeColor = TEXTCOLOR_DARKGREEN;
PrintLevelStats(stats, summary);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SetItemSeq(ExhumedPlayer pp)
{
static const int nItemSeqOffset[] = { 91, 72, 76, 79, 68, 87, 83 };
static const int nItemMagic[] = { 500, 1000, 100, 500, 400, 200, 700, 0 };
int nItem = pp.nItem;
if (nItem < 0)
{
nItemSeq = -1;
return;
}
if (nItemMagic[nItem] <= pp.nMagic) nItemAltSeq = 0;
else nItemAltSeq = 2;
nItemFrame = 0;
nItemSeq = nItemSeqOffset[nItem] + nItemAltSeq;
nItemFrames = Exhumed.SizeofStatusSequence(nItemSeq);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SetMagicFrame(ExhumedPlayer pp)
{
int magicperline = 1000 / nMeterRange;
int newMagicLevel = (1000 - pp.nMagic) / magicperline;
newMagicLevel = clamp(newMagicLevel, 0, nMeterRange - 1);
if (newMagicLevel != nMagicLevel) SetItemSeq(pp);
nMagicLevel = newMagicLevel;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SetHealthFrame(ExhumedPlayer pp)
{
if (nHurt)
{
nHurt++;
if (nHurt > Exhumed.SizeofStatusSequence(4)) nHurt = 0;
}
int healthperline = 800 / nMeterRange;
int newHealthLevel = (800 - pp.nHealth) / healthperline;
newHealthLevel = clamp(newHealthLevel, 0, nMeterRange - 1);
if (newHealthLevel > nHealthLevel) nHurt = 1;
nHealthLevel = newHealthLevel;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SetCounter(int nVal)
{
nCounterDest = clamp(nVal, 0, 999);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SetCounterImmediate(int nVal)
{
SetCounter(nVal);
nCounter = nCounterDest;
SetCounterDigits();
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SetCounterDigits()
{
nDigit[2] = 3 * (nCounter / 100 % 10);
nDigit[1] = 3 * (nCounter / 10 % 10);
nDigit[0] = 3 * (nCounter % 10);
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void UpdateCounter(ExhumedPlayer pp)
{
int nWeapon = pp.nCurrentWeapon;
if (nWeapon < 0)
{
SetCounterImmediate(0);
}
else
{
int thiscount;
if (nWeapon >= kWeaponSword && nWeapon <= kWeaponRing)
thiscount = pp.nAmmo[nWeapon];
else
thiscount = 0;
if (nWeapon != nLastWeapon) SetCounterImmediate(thiscount);
else SetCounter(thiscount);
}
nLastWeapon = nWeapon;
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void MoveStatus(ExhumedPlayer pp)
{
if (nItemSeq >= 0)
{
nItemFrame++;
if (nItemFrame >= nItemFrames)
{
if (nItemSeq == 67) {
SetItemSeq(pp);
}
else
{
nItemSeq -= nItemAltSeq;
if (nItemAltSeq || (totalmoves & 0x1F))
{
if (nItemSeq < 2) {
nItemAltSeq = 0;
}
}
else
{
nItemAltSeq = 1;
}
nItemFrame = 0;
nItemSeq += nItemAltSeq;
nItemFrames = Exhumed.SizeofStatusSequence(nItemSeq);
}
}
}
nHealthFrame++;
if (nHealthFrame >= Exhumed.SizeofStatusSequence(1)) nHealthFrame = 0;
nMagicFrame++;
if (nMagicFrame >= Exhumed.SizeofStatusSequence(129)) nMagicFrame = 0;
if (nCounter == nCounterDest)
{
nCounter = nCounterDest;
ammodelay = 3;
return;
}
else
{
ammodelay--;
if (ammodelay > 0)
return;
}
int eax = nCounterDest - nCounter;
if (eax <= 0)
{
if (eax >= -30)
{
for (int i = 0; i < 3; i++)
{
nDigit[i]--;
if (nDigit[i] < 0)
{
nDigit[i] += 30;
}
if (nDigit[i] < 27) {
break;
}
}
}
else
{
nCounter += (nCounterDest - nCounter) >> 1;
SetCounterDigits();
return;
}
}
else
{
if (eax <= 30)
{
for (int i = 0; i < 3; i++)
{
nDigit[i]++;
if (nDigit[i] <= 27)
break;
if (nDigit[i] >= 30)
nDigit[i] -= 30;
}
}
else
{
nCounter += (nCounterDest - nCounter) >> 1;
SetCounterDigits();
return;
}
}
if (!(nDigit[0] % 3))
nCounter = nDigit[0] / 3 + 100 * (nDigit[2] / 3) + 10 * (nDigit[1] / 3);
eax = nCounterDest - nCounter;
if (eax < 0)
eax = -eax;
ammodelay = max(1, 4 - (eax >> 1));
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SetPlayerItem(ExhumedPlayer pp)
{
if (nSelectedItem != pp.nItem)
{
nSelectedItem = pp.nItem;
SetItemSeq(pp);
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
override void Tick()
{
totalmoves++;
let pp = Exhumed.GetViewPlayer();
SetMagicFrame(pp);
SetHealthFrame(pp);
SetPlayerItem(pp);
UpdateCounter(pp);
MoveStatus(pp);
for (int i = 0; i < 4; i++)
{
int seq = KeySeq + 2 * i;
if (pp.keys & (4096 << i))
{
if (keyanims[i] < Exhumed.SizeofStatusSequence(seq) - 1)
{
Exhumed.MoveStatusSequence(seq, 0); // this plays the pickup sound.
keyanims[i]++;
}
}
else
{
keyanims[i] = 0;
}
}
if (pp.isUnderwater())
{
int nAirFrames = Exhumed.SizeofStatusSequence(133);
int airperline = 100 / nAirFrames;
airframe = pp.nAir / airperline;
if (airframe >= nAirFrames)
{
airframe = nAirFrames - 1;
}
else if (airframe < 0)
{
airframe = 0;
}
lungframe = 0;
}
else
{
int size = Exhumed.SizeofStatusSequence(132);
if (++lungframe == size) lungframe = 0;
}
}
override void UpdateStatusBar(SummaryInfo info)
{
if (hud_size <= Hud_full)
{
DrawStatus(Exhumed.GetViewPlayer());
}
DoLevelStats(hud_size == Hud_Nothing ? 0 : hud_size == Hud_full ? 22 : 40, info);
}
}

View file

@ -134,6 +134,8 @@ struct SummaryInfo native
struct Raze
{
const kAngleMask = 0x7FF;
static int calcSinTableValue(int ang)
{
return int(16384 * sin((360./2048) * ang));
@ -254,7 +256,7 @@ class DukeStatusBar : DukeCommonStatusBar native
class RedneckStatusBar : DukeCommonStatusBar native
{}
class ExhumedStatusBar : BaseStatusBar native
class NativeExhumedStatusBar : BaseStatusBar native
{}
class SWStatusBar : BaseStatusBar native