- Added: hasweaponpiece command to check for custom weapon pieces. - Added: usessecondaryammo command to check if the current weapon has a second ammo type. - Most of SBarInfo's mugshot scripting can be used with the default Doom status bar. - Fixed: By default drawmugshot would never come out of normal god mode state. In addition the state change to and from god mode was not quite as responsive as the original code. SVN r980 (trunk)
1069 lines
25 KiB
C++
1069 lines
25 KiB
C++
#include "doomtype.h"
|
|
#include "doomstat.h"
|
|
#include "v_font.h"
|
|
#include "v_video.h"
|
|
#include "sbar.h"
|
|
#include "r_defs.h"
|
|
#include "w_wad.h"
|
|
#include "m_random.h"
|
|
#include "d_player.h"
|
|
#include "st_stuff.h"
|
|
#include "r_local.h"
|
|
#include "m_swap.h"
|
|
#include "a_keys.h"
|
|
#include "templates.h"
|
|
#include "i_system.h"
|
|
#include "r_translate.h"
|
|
#include "sbarinfo.h"
|
|
|
|
|
|
#define ST_EVILGRINCOUNT (2*TICRATE)
|
|
#define ST_STRAIGHTFACECOUNT (TICRATE/2)
|
|
#define ST_TURNCOUNT (1*TICRATE)
|
|
#define ST_OUCHCOUNT (1*TICRATE)
|
|
#define ST_RAMPAGEDELAY (2*TICRATE)
|
|
|
|
#define ST_MUCHPAIN 20
|
|
|
|
EXTERN_CVAR (Bool, vid_fps)
|
|
|
|
class DDoomStatusBar : public DBaseStatusBar
|
|
{
|
|
DECLARE_CLASS(DDoomStatusBar, DBaseStatusBar)
|
|
public:
|
|
DDoomStatusBar () : DBaseStatusBar (32)
|
|
{
|
|
static const char *sharedLumpNames[] =
|
|
{
|
|
NULL, NULL, NULL, NULL, NULL,
|
|
NULL, NULL, NULL, NULL, NULL,
|
|
NULL, NULL, "STTMINUS", "STTNUM0", "STTNUM1",
|
|
"STTNUM2", "STTNUM3", "STTNUM4", "STTNUM5", "STTNUM6",
|
|
"STTNUM7", "STTNUM8", "STTNUM9", "STYSNUM0", "STYSNUM1",
|
|
"STYSNUM2", "STYSNUM3", "STYSNUM4", "STYSNUM5", "STYSNUM6",
|
|
"STYSNUM7", "STYSNUM8", "STYSNUM9"
|
|
};
|
|
FTexture *tex;
|
|
|
|
DBaseStatusBar::Images.Init (sharedLumpNames, NUM_BASESB_IMAGES);
|
|
tex = DBaseStatusBar::Images[imgBNumbers];
|
|
BigWidth = tex->GetWidth();
|
|
BigHeight = tex->GetHeight();
|
|
|
|
DoCommonInit ();
|
|
|
|
bEvilGrin = false;
|
|
bDamageFaceActive = false;
|
|
CurrentState = NULL;
|
|
RampageTimer = 0;
|
|
LastDamageAngle = 1;
|
|
}
|
|
|
|
~DDoomStatusBar ()
|
|
{
|
|
}
|
|
|
|
void NewGame ()
|
|
{
|
|
Images.Uninit ();
|
|
DoCommonInit ();
|
|
if (CPlayer != NULL)
|
|
{
|
|
AttachToPlayer (CPlayer);
|
|
}
|
|
}
|
|
|
|
void AddFaceToImageCollection (void *skn, FImageCollection *images)
|
|
{
|
|
AddFaceToImageCollectionActual (skn, images, true);
|
|
}
|
|
|
|
void MultiplayerChanged ()
|
|
{
|
|
DBaseStatusBar::MultiplayerChanged ();
|
|
if (multiplayer)
|
|
{
|
|
// set face background color
|
|
StatusBarTex.SetPlayerRemap(translationtables[TRANSLATION_Players][int(CPlayer - players)]);
|
|
}
|
|
}
|
|
|
|
void AttachToPlayer (player_t *player)
|
|
{
|
|
player_t *oldplayer = CPlayer;
|
|
|
|
DBaseStatusBar::AttachToPlayer (player);
|
|
if (oldplayer != CPlayer || savegamerestore/*added for morphing*/)
|
|
{
|
|
SetFace (&skins[CPlayer->morphTics ? CPlayer->MorphedPlayerClass : CPlayer->userinfo.skin]);
|
|
}
|
|
if (multiplayer)
|
|
{
|
|
// set face background color
|
|
StatusBarTex.SetPlayerRemap(translationtables[TRANSLATION_Players][int(CPlayer - players)]);
|
|
}
|
|
bEvilGrin = false;
|
|
}
|
|
|
|
void Tick ()
|
|
{
|
|
DBaseStatusBar::Tick ();
|
|
RandomNumber = M_Random ();
|
|
|
|
//Do some stuff related to the mug shot that has to be done at 35fps
|
|
if(CurrentState != NULL)
|
|
{
|
|
CurrentState->tick();
|
|
if(CurrentState->finished)
|
|
CurrentState = NULL;
|
|
}
|
|
if((CPlayer->cmd.ucmd.buttons & (BT_ATTACK|BT_ALTATTACK)) && !(CPlayer->cheats & (CF_FROZEN | CF_TOTALLYFROZEN)))
|
|
{
|
|
if(RampageTimer != ST_RAMPAGEDELAY)
|
|
{
|
|
RampageTimer++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RampageTimer = 0;
|
|
}
|
|
FaceHealth = CPlayer->health;
|
|
}
|
|
|
|
void Draw (EHudState state)
|
|
{
|
|
DBaseStatusBar::Draw (state);
|
|
|
|
if (state == HUD_Fullscreen)
|
|
{
|
|
SB_state = screen->GetPageCount ();
|
|
DrawFullScreenStuff ();
|
|
}
|
|
else if (state == HUD_StatusBar)
|
|
{
|
|
if (SB_state != 0)
|
|
{
|
|
SB_state--;
|
|
DrawImage (&StatusBarTex, 0, 0);
|
|
memset (OldArms, 255, sizeof(OldArms));
|
|
OldKeys = -1;
|
|
memset (OldAmmo, 255, sizeof(OldAmmo));
|
|
memset (OldMaxAmmo, 255, sizeof(OldMaxAmmo));
|
|
OldHealth = -1;
|
|
OldArmor = -1;
|
|
OldActiveAmmo = -1;
|
|
OldFrags = -9999;
|
|
FaceHealth = -9999;
|
|
}
|
|
DrawMainBar ();
|
|
if (CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR))
|
|
{
|
|
DrawInventoryBar ();
|
|
SB_state = screen->GetPageCount ();
|
|
}
|
|
}
|
|
}
|
|
|
|
//See sbarinfo_display.cpp
|
|
void SetMugShotState (const char* stateName, bool waitTillDone=false)
|
|
{
|
|
MugShotState *state = (MugShotState *) FindMugShotState(stateName);
|
|
if(state != CurrentState)
|
|
{
|
|
if(!waitTillDone || CurrentState == NULL || CurrentState->finished)
|
|
{
|
|
CurrentState = state;
|
|
state->reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
struct FDoomStatusBarTexture : public FTexture
|
|
{
|
|
void DrawToBar (const char *name, int x, int y, const BYTE *colormap_in = NULL);
|
|
|
|
public:
|
|
FDoomStatusBarTexture ();
|
|
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
|
|
const BYTE *GetPixels ();
|
|
void Unload ();
|
|
~FDoomStatusBarTexture ();
|
|
void SetPlayerRemap(FRemapTable *remap);
|
|
int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf = NULL);
|
|
|
|
FTextureFormat GetFormat()
|
|
{
|
|
return TEX_RGB;
|
|
}
|
|
|
|
|
|
protected:
|
|
void MakeTexture ();
|
|
|
|
FTexture *BaseTexture;
|
|
BYTE *Pixels;
|
|
FRemapTable *STFBRemap;
|
|
}
|
|
StatusBarTex;
|
|
|
|
void DoCommonInit ()
|
|
{
|
|
static const char *doomLumpNames[] =
|
|
{
|
|
"STKEYS0", "STKEYS1", "STKEYS2", "STKEYS3", "STKEYS4",
|
|
"STKEYS5", "STKEYS6", "STKEYS7", "STKEYS8",
|
|
"STGNUM2", "STGNUM3", "STGNUM4", "STGNUM5", "STGNUM6",
|
|
"STGNUM7", "MEDIA0", "ARTIBOX", "SELECTBO", "INVGEML1",
|
|
"INVGEML2", "INVGEMR1", "INVGEMR2",
|
|
};
|
|
|
|
Images.Init (doomLumpNames, NUM_DOOMSB_IMAGES);
|
|
|
|
// In case somebody wants to use the Heretic status bar graphics...
|
|
{
|
|
FTexture *artibox = Images[imgARTIBOX];
|
|
FTexture *selectbox = Images[imgSELECTBOX];
|
|
if (artibox != NULL && selectbox != NULL)
|
|
{
|
|
selectbox->LeftOffset = artibox->LeftOffset;
|
|
selectbox->TopOffset = artibox->TopOffset;
|
|
}
|
|
}
|
|
|
|
StatusBarTex.Unload ();
|
|
|
|
SB_state = screen->GetPageCount ();
|
|
}
|
|
|
|
void DrawMainBar ()
|
|
{
|
|
int amount;
|
|
|
|
DrawAmmoStats ();
|
|
DrawFace ();
|
|
DrawKeys ();
|
|
if (!deathmatch)
|
|
{
|
|
DrawArms ();
|
|
}
|
|
else
|
|
{
|
|
if (OldFrags != CPlayer->fragcount)
|
|
{
|
|
OldFrags = CPlayer->fragcount;
|
|
FragsRefresh = screen->GetPageCount ();
|
|
}
|
|
if (FragsRefresh)
|
|
{
|
|
FragsRefresh--;
|
|
DrawNumber (OldFrags, 138/*110*/, 3, 2);
|
|
}
|
|
}
|
|
if (CPlayer->health != OldHealth)
|
|
{
|
|
OldHealth = CPlayer->health;
|
|
HealthRefresh = screen->GetPageCount ();
|
|
}
|
|
if (HealthRefresh)
|
|
{
|
|
HealthRefresh--;
|
|
DrawNumber (OldHealth, 90/*48*/, 3);
|
|
}
|
|
AInventory *armor = CPlayer->mo->FindInventory<ABasicArmor>();
|
|
int armorpoints = armor != NULL ? armor->Amount : 0;
|
|
if (armorpoints != OldArmor)
|
|
{
|
|
OldArmor = armorpoints;
|
|
ArmorRefresh = screen->GetPageCount ();
|
|
}
|
|
if (ArmorRefresh)
|
|
{
|
|
ArmorRefresh--;
|
|
DrawNumber (OldArmor, 221/*179*/, 3);
|
|
}
|
|
if (CPlayer->ReadyWeapon != NULL)
|
|
{
|
|
AAmmo *ammo = CPlayer->ReadyWeapon->Ammo1;
|
|
amount = ammo != NULL ? ammo->Amount : -9999;
|
|
}
|
|
else
|
|
{
|
|
amount = -9999;
|
|
}
|
|
if (amount != OldActiveAmmo)
|
|
{
|
|
OldActiveAmmo = amount;
|
|
ActiveAmmoRefresh = screen->GetPageCount ();
|
|
}
|
|
if (ActiveAmmoRefresh)
|
|
{
|
|
ActiveAmmoRefresh--;
|
|
if (OldActiveAmmo != -9999)
|
|
{
|
|
DrawNumber (OldActiveAmmo, 44/*2*/, 3);
|
|
}
|
|
else
|
|
{
|
|
DrawPartialImage (&StatusBarTex, 2, BigWidth*3);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawArms ()
|
|
{
|
|
BYTE arms[6];
|
|
int i, j;
|
|
|
|
// Catalog the weapons the player owns
|
|
memset (arms, 0, sizeof(arms));
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
for (j = 0; j < MAX_WEAPONS_PER_SLOT; j++)
|
|
{
|
|
const PClass *weap = LocalWeapons.Slots[i+2].GetWeapon (j);
|
|
if (weap != NULL && CPlayer->mo->FindInventory (weap) != NULL)
|
|
{
|
|
arms[i] = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw slots that have changed ownership since last time
|
|
for (i = 0; i < 6; i++)
|
|
{
|
|
if (arms[i] != OldArms[i])
|
|
{
|
|
ArmsRefresh[i%3] = screen->GetPageCount ();
|
|
}
|
|
}
|
|
|
|
// Remember the arms state for next time
|
|
memcpy (OldArms, arms, sizeof(arms));
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
if (ArmsRefresh[i])
|
|
{
|
|
ArmsRefresh[i]--;
|
|
int x = 111 + i * 12;
|
|
|
|
DrawArm (arms[i], i, x, 4, true);
|
|
DrawArm (arms[i+3], i+3, x, 14, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawArm (int on, int picnum, int x, int y, bool drawBackground)
|
|
{
|
|
int w;
|
|
FTexture *pic = on ? DBaseStatusBar::Images[imgSmNumbers + 2 + picnum] : Images[imgGNUM2 + picnum];
|
|
|
|
if (pic != NULL)
|
|
{
|
|
w = pic->GetWidth();
|
|
x -= pic->LeftOffset;
|
|
y -= pic->TopOffset;
|
|
|
|
if (drawBackground)
|
|
{
|
|
DrawPartialImage (&StatusBarTex, x, w);
|
|
}
|
|
DrawImage (pic, x, y);
|
|
}
|
|
}
|
|
|
|
void DrawAmmoStats ()
|
|
{
|
|
static const ENamedName ammoTypes[4] =
|
|
{
|
|
NAME_Clip,
|
|
NAME_Shell,
|
|
NAME_RocketAmmo,
|
|
NAME_Cell
|
|
};
|
|
int ammo[4], maxammo[4];
|
|
int i;
|
|
|
|
// Catalog the player's ammo
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
const PClass *type = PClass::FindClass (ammoTypes[i]);
|
|
AInventory *item = CPlayer->mo->FindInventory (type);
|
|
if (item != NULL)
|
|
{
|
|
ammo[i] = item->Amount;
|
|
maxammo[i] = item->MaxAmount;
|
|
}
|
|
else
|
|
{
|
|
ammo[i] = 0;
|
|
maxammo[i] = ((AInventory *)GetDefaultByType (type))->MaxAmount;
|
|
}
|
|
}
|
|
|
|
// Draw ammo amounts that have changed since last time
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (ammo[i] != OldAmmo[i])
|
|
{
|
|
AmmoRefresh = screen->GetPageCount ();
|
|
}
|
|
if (maxammo[i] != OldMaxAmmo[i])
|
|
{
|
|
MaxAmmoRefresh = screen->GetPageCount ();
|
|
}
|
|
}
|
|
|
|
// Remember ammo counts for next time
|
|
memcpy (OldAmmo, ammo, sizeof(ammo));
|
|
memcpy (OldMaxAmmo, maxammo, sizeof(ammo));
|
|
|
|
if (AmmoRefresh)
|
|
{
|
|
AmmoRefresh--;
|
|
DrawPartialImage (&StatusBarTex, 276, 4*3);
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
DrSmallNumber (ammo[i], 276, 5 + 6*i);
|
|
}
|
|
}
|
|
if (MaxAmmoRefresh)
|
|
{
|
|
MaxAmmoRefresh--;
|
|
DrawPartialImage (&StatusBarTex, 302, 4*3);
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
DrSmallNumber (maxammo[i], 302, 5 + 6*i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawKeys ()
|
|
{
|
|
AInventory *item;
|
|
int keys;
|
|
|
|
// Catalog the player's current keys
|
|
keys = 0;
|
|
for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
|
|
{
|
|
if (item->IsKindOf (RUNTIME_CLASS(AKey)))
|
|
{
|
|
int keynum = static_cast<AKey*>(item)->KeyNumber;
|
|
if (keynum >= 1 && keynum <= 6)
|
|
{
|
|
keys |= 1 << (keynum-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remember keys for next time
|
|
if (OldKeys != keys)
|
|
{
|
|
OldKeys = keys;
|
|
KeysRefresh = screen->GetPageCount ();
|
|
}
|
|
|
|
// Draw keys that have changed since last time
|
|
if (KeysRefresh)
|
|
{
|
|
KeysRefresh--;
|
|
DrawPartialImage (&StatusBarTex, 239, 8);
|
|
|
|
// Blue Keys
|
|
switch (keys & (2|16))
|
|
{
|
|
case 2: DrawImage (Images[imgKEYS0], 239, 3); break;
|
|
case 16: DrawImage (Images[imgKEYS3], 239, 3); break;
|
|
case 18: DrawImage (Images[imgKEYS6], 239, 3); break;
|
|
}
|
|
|
|
// Yellow Keys
|
|
switch (keys & (4|32))
|
|
{
|
|
case 4: DrawImage (Images[imgKEYS1], 239, 13); break;
|
|
case 32: DrawImage (Images[imgKEYS4], 239, 13); break;
|
|
case 36: DrawImage (Images[imgKEYS7], 239, 13); break;
|
|
}
|
|
|
|
// Red Keys
|
|
switch (keys & (1|8))
|
|
{
|
|
case 1: DrawImage (Images[imgKEYS2], 239, 23); break;
|
|
case 8: DrawImage (Images[imgKEYS5], 239, 23); break;
|
|
case 9: DrawImage (Images[imgKEYS8], 239, 23); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// PROC DrawInventoryBar
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
void DrawInventoryBar ()
|
|
{
|
|
AInventory *item;
|
|
int i;
|
|
|
|
// If the player has no artifacts, don't draw the bar
|
|
CPlayer->mo->InvFirst = ValidateInvFirst (7);
|
|
if (CPlayer->mo->InvFirst != NULL)
|
|
{
|
|
for (item = CPlayer->mo->InvFirst, i = 0; item != NULL && i < 7; item = item->NextInv(), ++i)
|
|
{
|
|
DrawImage (Images[imgARTIBOX], 50+i*31, 2);
|
|
DrawDimImage (TexMan(item->Icon), 50+i*31, 2, item->Amount <= 0);
|
|
if (item->Amount != 1)
|
|
{
|
|
DrSmallNumber (item->Amount, 66+i*31, 24);
|
|
}
|
|
if (item == CPlayer->mo->InvSel)
|
|
{
|
|
DrawImage (Images[imgSELECTBOX], 50+i*31, 2);
|
|
}
|
|
}
|
|
for (; i < 7; ++i)
|
|
{
|
|
DrawImage (Images[imgARTIBOX], 50+i*31, 2);
|
|
}
|
|
// Is there something to the left?
|
|
if (CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst)
|
|
{
|
|
DrawImage (Images[!(gametic & 4) ?
|
|
imgINVLFGEM1 : imgINVLFGEM2], 38, 2);
|
|
}
|
|
// Is there something to the right?
|
|
if (item != NULL)
|
|
{
|
|
DrawImage (Images[!(gametic & 4) ?
|
|
imgINVRTGEM1 : imgINVRTGEM2], 269, 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DrawNumber (int val, int x, int y, int size=3)
|
|
{
|
|
DrawPartialImage (&StatusBarTex, x-BigWidth*size, size*BigWidth);
|
|
DrBNumber (val, x, y, size);
|
|
}
|
|
|
|
void DrawFullScreenStuff ()
|
|
{
|
|
AInventory *item;
|
|
int i;
|
|
int ammotop;
|
|
|
|
// Draw health
|
|
screen->DrawTexture (Images[imgMEDI], 20, -2,
|
|
DTA_HUDRules, HUD_Normal,
|
|
DTA_CenterBottomOffset, true,
|
|
TAG_DONE);
|
|
DrBNumberOuter (CPlayer->health, 40, -BigHeight-4);
|
|
|
|
// Draw armor
|
|
ABasicArmor *armor = CPlayer->mo->FindInventory<ABasicArmor>();
|
|
if (armor != NULL && armor->Amount != 0)
|
|
{
|
|
screen->DrawTexture (TexMan(armor->Icon), 20, -24,
|
|
DTA_HUDRules, HUD_Normal,
|
|
DTA_CenterBottomOffset, true,
|
|
TAG_DONE);
|
|
DrBNumberOuter (armor->Amount, 40, -39);
|
|
}
|
|
|
|
// Draw ammo
|
|
AAmmo *ammo1, *ammo2;
|
|
int ammocount1, ammocount2;
|
|
|
|
GetCurrentAmmo (ammo1, ammo2, ammocount1, ammocount2);
|
|
ammotop = -1;
|
|
if (ammo1 != NULL)
|
|
{
|
|
FTexture *ammoIcon = TexMan(ammo1->Icon);
|
|
// Draw primary ammo in the bottom-right corner
|
|
screen->DrawTexture (ammoIcon, -14, -4,
|
|
DTA_HUDRules, HUD_Normal,
|
|
DTA_CenterBottomOffset, true,
|
|
TAG_DONE);
|
|
DrBNumberOuter (ammo1->Amount, -67, -4 - BigHeight);
|
|
ammotop = -4 - BigHeight;
|
|
if (ammo2 != NULL && ammo2!=ammo1)
|
|
{
|
|
// Draw secondary ammo just above the primary ammo
|
|
int y = MIN (-6 - BigHeight, -6 - (ammoIcon != NULL ? ammoIcon->GetHeight() : 0));
|
|
screen->DrawTexture (TexMan(ammo2->Icon), -14, y,
|
|
DTA_HUDRules, HUD_Normal,
|
|
DTA_CenterBottomOffset, true,
|
|
TAG_DONE);
|
|
DrBNumberOuter (ammo2->Amount, -67, y - BigHeight);
|
|
ammotop = y - BigHeight;
|
|
}
|
|
}
|
|
|
|
if (deathmatch)
|
|
{ // Draw frags (in DM)
|
|
DrBNumberOuter (CPlayer->fragcount, -44, 1);
|
|
}
|
|
else
|
|
{ // Draw keys (not DM)
|
|
int maxw = 0;
|
|
int count = 0;
|
|
int x = -2;
|
|
int y = vid_fps? 12 : 2;
|
|
|
|
for (item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
|
|
{
|
|
if (item->Icon > 0 && item->IsKindOf (RUNTIME_CLASS(AKey)))
|
|
{
|
|
FTexture *keypic = TexMan(item->Icon);
|
|
if (keypic != NULL)
|
|
{
|
|
int w = keypic->GetWidth ();
|
|
int h = keypic->GetHeight ();
|
|
if (w > maxw)
|
|
{
|
|
maxw = w;
|
|
}
|
|
screen->DrawTexture (keypic, x, y,
|
|
DTA_LeftOffset, w,
|
|
DTA_TopOffset, 0,
|
|
DTA_HUDRules, HUD_Normal,
|
|
TAG_DONE);
|
|
if (++count == 3)
|
|
{
|
|
count = 0;
|
|
y = vid_fps? 12 : 2;
|
|
x -= maxw + 2;
|
|
maxw = 0;
|
|
}
|
|
else
|
|
{
|
|
y += h + 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Draw inventory
|
|
if (!(level.flags & LEVEL_NOINVENTORYBAR))
|
|
{
|
|
if (CPlayer->inventorytics == 0)
|
|
{
|
|
if (CPlayer->mo->InvSel != NULL)
|
|
{
|
|
screen->DrawTexture (TexMan(CPlayer->mo->InvSel->Icon), -14, ammotop - 1/*-24*/,
|
|
DTA_HUDRules, HUD_Normal,
|
|
DTA_CenterBottomOffset, true,
|
|
DTA_ColorOverlay, CPlayer->mo->InvSel->Amount > 0 ? 0 : DIM_OVERLAY,
|
|
TAG_DONE);
|
|
DrBNumberOuter (CPlayer->mo->InvSel->Amount, -68, ammotop - 18/*-41*/);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CPlayer->mo->InvFirst = ValidateInvFirst (7);
|
|
i = 0;
|
|
if (CPlayer->mo->InvFirst != NULL)
|
|
{
|
|
for (item = CPlayer->mo->InvFirst; item != NULL && i < 7; item = item->NextInv(), ++i)
|
|
{
|
|
screen->DrawTexture (Images[imgARTIBOX], -106+i*31, -32,
|
|
DTA_HUDRules, HUD_HorizCenter,
|
|
DTA_Alpha, HX_SHADOW,
|
|
TAG_DONE);
|
|
screen->DrawTexture (TexMan(item->Icon), -105+i*31, -32,
|
|
DTA_HUDRules, HUD_HorizCenter,
|
|
DTA_ColorOverlay, item->Amount > 0 ? 0 : DIM_OVERLAY,
|
|
TAG_DONE);
|
|
if (item->Amount != 1)
|
|
{
|
|
DrSmallNumberOuter (item->Amount, -90+i*31, -10, true);
|
|
}
|
|
if (item == CPlayer->mo->InvSel)
|
|
{
|
|
screen->DrawTexture (Images[imgSELECTBOX], -91+i*31, -2,
|
|
DTA_HUDRules, HUD_HorizCenter,
|
|
DTA_CenterBottomOffset, true,
|
|
TAG_DONE);
|
|
}
|
|
}
|
|
for (; i < 7; i++)
|
|
{
|
|
screen->DrawTexture (Images[imgARTIBOX], -106+i*31, -32,
|
|
DTA_HUDRules, HUD_HorizCenter,
|
|
DTA_Alpha, HX_SHADOW,
|
|
TAG_DONE);
|
|
}
|
|
// Is there something to the left?
|
|
if (CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst)
|
|
{
|
|
screen->DrawTexture (Images[!(gametic & 4) ?
|
|
imgINVLFGEM1 : imgINVLFGEM2], -118, -33,
|
|
DTA_HUDRules, HUD_HorizCenter,
|
|
TAG_DONE);
|
|
}
|
|
// Is there something to the right?
|
|
if (item != NULL)
|
|
{
|
|
screen->DrawTexture (Images[!(gametic & 4) ?
|
|
imgINVRTGEM1 : imgINVRTGEM2], 113, -33,
|
|
DTA_HUDRules, HUD_HorizCenter,
|
|
TAG_DONE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int CalcPainOffset ()
|
|
{
|
|
int health;
|
|
static int lastcalc;
|
|
static int oldhealth = -1;
|
|
|
|
health = CPlayer->health > 100 ? 100 : CPlayer->health;
|
|
|
|
if (health != oldhealth)
|
|
{
|
|
lastcalc = ST_FACESTRIDE * (((100 - health) * ST_NUMPAINFACES) / 101);
|
|
oldhealth = health;
|
|
}
|
|
return lastcalc;
|
|
}
|
|
|
|
void ReceivedWeapon (AWeapon *weapon)
|
|
{
|
|
bEvilGrin = true;
|
|
}
|
|
|
|
int UpdateState ()
|
|
{
|
|
int i;
|
|
angle_t badguyangle;
|
|
angle_t diffang;
|
|
|
|
if(CPlayer->health > 0)
|
|
{
|
|
if(bEvilGrin)
|
|
{
|
|
if(CurrentState == NULL)
|
|
bEvilGrin = false;
|
|
else if(CPlayer->bonuscount)
|
|
{
|
|
SetMugShotState("grin", false);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (CPlayer->damagecount)
|
|
{
|
|
int damageAngle = 1;
|
|
if(CPlayer->attacker && CPlayer->attacker != CPlayer->mo)
|
|
{
|
|
if(CPlayer->mo != NULL)
|
|
{
|
|
//The next 12 lines is from the Doom statusbar code.
|
|
badguyangle = R_PointToAngle2(CPlayer->mo->x, CPlayer->mo->y, CPlayer->attacker->x, CPlayer->attacker->y);
|
|
if(badguyangle > CPlayer->mo->angle)
|
|
{
|
|
// whether right or left
|
|
diffang = badguyangle - CPlayer->mo->angle;
|
|
i = diffang > ANG180;
|
|
}
|
|
else
|
|
{
|
|
// whether left or right
|
|
diffang = CPlayer->mo->angle - badguyangle;
|
|
i = diffang <= ANG180;
|
|
} // confusing, aint it?
|
|
if(i && diffang >= ANG45)
|
|
{
|
|
damageAngle = 0;
|
|
}
|
|
else if(!i && diffang >= ANG45)
|
|
{
|
|
damageAngle = 2;
|
|
}
|
|
}
|
|
}
|
|
const char* stateName = new char[5];
|
|
if (FaceHealth != -1 && CPlayer->health - FaceHealth > 20)
|
|
stateName = "ouch";
|
|
else
|
|
stateName = "pain";
|
|
char* fullStateName = new char[sizeof(stateName)+sizeof((const char*) CPlayer->LastDamageType) + 1];
|
|
sprintf(fullStateName, "%s.%s", stateName, (const char*) CPlayer->LastDamageType);
|
|
if(FindMugShotState(fullStateName) != NULL)
|
|
SetMugShotState(fullStateName);
|
|
else
|
|
SetMugShotState(stateName);
|
|
bDamageFaceActive = !(CurrentState == NULL);
|
|
LastDamageAngle = damageAngle;
|
|
return damageAngle;
|
|
}
|
|
if(bDamageFaceActive)
|
|
{
|
|
if(CurrentState == NULL)
|
|
bDamageFaceActive = false;
|
|
else
|
|
{
|
|
const char* stateName = new char[5];
|
|
if (FaceHealth != -1 && CPlayer->health - FaceHealth > 20)
|
|
stateName = "ouch";
|
|
else
|
|
stateName = "pain";
|
|
char* fullStateName = new char[sizeof(stateName)+sizeof((const char*) CPlayer->LastDamageType) + 1];
|
|
sprintf(fullStateName, "%s.%s", stateName, (const char*) CPlayer->LastDamageType);
|
|
if(FindMugShotState(fullStateName) != NULL)
|
|
SetMugShotState(fullStateName);
|
|
else
|
|
SetMugShotState(stateName);
|
|
return LastDamageAngle;
|
|
}
|
|
}
|
|
|
|
if(RampageTimer == ST_RAMPAGEDELAY)
|
|
{
|
|
SetMugShotState("rampage", true);
|
|
return 0;
|
|
}
|
|
|
|
if(!bEvilGrin)
|
|
{
|
|
if((CPlayer->cheats & CF_GODMODE) || (CPlayer->mo != NULL && CPlayer->mo->flags2 & MF2_INVULNERABLE))
|
|
SetMugShotState("god");
|
|
else
|
|
SetMugShotState("normal");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const char* stateName = new char[7];
|
|
stateName = "death";
|
|
//new string the size of stateName and the damage type put together
|
|
char* fullStateName = new char[sizeof(stateName)+sizeof((const char*) CPlayer->LastDamageType) + 1];
|
|
sprintf(fullStateName, "%s.%s", stateName, (const char*) CPlayer->LastDamageType);
|
|
if(FindMugShotState(fullStateName) != NULL)
|
|
SetMugShotState(fullStateName);
|
|
else
|
|
SetMugShotState(stateName);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void DrawFace ()
|
|
{
|
|
if (CPlayer->mo->InvSel == NULL || (level.flags & LEVEL_NOINVENTORYBAR))
|
|
{
|
|
int angle = UpdateState();
|
|
int level = 0;
|
|
for(level = 0;CPlayer->health < (4-level)*(CPlayer->mo->GetMaxHealth()/5);level++);
|
|
if(CurrentState != NULL)
|
|
{
|
|
FString defaultFace = "STF";
|
|
FPlayerSkin *skin = &skins[CPlayer->morphTics ? CPlayer->MorphedPlayerClass : CPlayer->userinfo.skin];
|
|
FTexture *face = CurrentState->getCurrentFrameTexture(defaultFace, skin, level, angle);
|
|
if (face != NULL)
|
|
{
|
|
DrawPartialImage (&StatusBarTex, 142, 37);
|
|
DrawImage (face, 143, 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DrawDimImage (TexMan(CPlayer->mo->InvSel->Icon), 144, 0, CPlayer->mo->InvSel->Amount <= 0);
|
|
if (CPlayer->mo->InvSel->Amount != 1)
|
|
{
|
|
DrSmallNumber (CPlayer->mo->InvSel->Amount, 165, 24);
|
|
}
|
|
}
|
|
}
|
|
|
|
enum
|
|
{
|
|
imgKEYS0,
|
|
imgKEYS1,
|
|
imgKEYS2,
|
|
imgKEYS3,
|
|
imgKEYS4,
|
|
imgKEYS5,
|
|
imgKEYS6,
|
|
imgKEYS7,
|
|
imgKEYS8,
|
|
imgGNUM2,
|
|
imgGNUM3,
|
|
imgGNUM4,
|
|
imgGNUM5,
|
|
imgGNUM6,
|
|
imgGNUM7,
|
|
imgMEDI,
|
|
imgARTIBOX,
|
|
imgSELECTBOX,
|
|
imgINVLFGEM1,
|
|
imgINVLFGEM2,
|
|
imgINVRTGEM1,
|
|
imgINVRTGEM2,
|
|
|
|
NUM_DOOMSB_IMAGES
|
|
};
|
|
|
|
FImageCollection Images;
|
|
|
|
int BigWidth;
|
|
int BigHeight;
|
|
|
|
int RandomNumber;
|
|
BYTE OldArms[6];
|
|
int OldKeys;
|
|
int OldAmmo[4];
|
|
int OldMaxAmmo[4];
|
|
int OldHealth;
|
|
int OldArmor;
|
|
int OldActiveAmmo;
|
|
int OldFrags;
|
|
|
|
char HealthRefresh;
|
|
char ArmorRefresh;
|
|
char ActiveAmmoRefresh;
|
|
char FragsRefresh;
|
|
char ArmsRefresh[3];
|
|
char AmmoRefresh;
|
|
char MaxAmmoRefresh;
|
|
char FaceRefresh;
|
|
char KeysRefresh;
|
|
|
|
//Mugshot
|
|
MugShotState *CurrentState;
|
|
int RampageTimer;
|
|
int LastDamageAngle;
|
|
int FaceHealth;
|
|
bool bEvilGrin;
|
|
bool bDamageFaceActive;
|
|
};
|
|
|
|
IMPLEMENT_CLASS(DDoomStatusBar)
|
|
|
|
DDoomStatusBar::FDoomStatusBarTexture::FDoomStatusBarTexture ()
|
|
{
|
|
BaseTexture = TexMan["STBAR"];
|
|
if (BaseTexture==NULL)
|
|
{
|
|
I_Error("Fatal error: STBAR not found");
|
|
}
|
|
UseType = FTexture::TEX_MiscPatch;
|
|
Name[0]=0; // doesn't need a name
|
|
|
|
// now copy all the properties from the base texture
|
|
CopySize(BaseTexture);
|
|
Pixels = NULL;
|
|
STFBRemap = NULL;
|
|
}
|
|
|
|
const BYTE *DDoomStatusBar::FDoomStatusBarTexture::GetColumn (unsigned int column, const Span **spans_out)
|
|
{
|
|
if (Pixels == NULL)
|
|
{
|
|
MakeTexture ();
|
|
}
|
|
|
|
BaseTexture->GetColumn(column, spans_out);
|
|
return Pixels + column*Height;
|
|
}
|
|
|
|
const BYTE *DDoomStatusBar::FDoomStatusBarTexture::GetPixels ()
|
|
{
|
|
if (Pixels == NULL)
|
|
{
|
|
MakeTexture ();
|
|
}
|
|
return Pixels;
|
|
}
|
|
|
|
void DDoomStatusBar::FDoomStatusBarTexture::Unload ()
|
|
{
|
|
if (Pixels != NULL)
|
|
{
|
|
delete[] Pixels;
|
|
Pixels = NULL;
|
|
}
|
|
}
|
|
|
|
DDoomStatusBar::FDoomStatusBarTexture::~FDoomStatusBarTexture ()
|
|
{
|
|
Unload ();
|
|
}
|
|
|
|
|
|
void DDoomStatusBar::FDoomStatusBarTexture::MakeTexture ()
|
|
{
|
|
Pixels = new BYTE[Width*Height];
|
|
const BYTE *pix = BaseTexture->GetPixels();
|
|
memcpy(Pixels, pix, Width*Height);
|
|
if (!deathmatch) DrawToBar("STARMS", 104, 0, NULL);
|
|
DrawToBar("STTPRCNT", 90, 3, NULL);
|
|
DrawToBar("STTPRCNT", 221, 3, NULL);
|
|
if (multiplayer) DrawToBar("STFBANY", 143, 1, STFBRemap? STFBRemap->Remap : NULL);
|
|
}
|
|
|
|
int DDoomStatusBar::FDoomStatusBarTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf)
|
|
{
|
|
FTexture *tex;
|
|
|
|
// rotate and inf are never used here
|
|
BaseTexture->CopyTrueColorPixels(bmp, x, y);
|
|
if (!deathmatch)
|
|
{
|
|
tex = TexMan["STARMS"];
|
|
if (tex != NULL)
|
|
{
|
|
tex->CopyTrueColorPixels(bmp, x+104, y);
|
|
}
|
|
}
|
|
|
|
tex = TexMan["STTPRCNT"];
|
|
if (tex != NULL)
|
|
{
|
|
tex->CopyTrueColorPixels(bmp, x+90, y+3);
|
|
tex->CopyTrueColorPixels(bmp, x+221, y+3);
|
|
}
|
|
if (multiplayer)
|
|
{
|
|
tex = TexMan["STFBANY"];
|
|
if (tex != NULL)
|
|
{
|
|
tex->CopyTrueColorTranslated(bmp, x+143, y+1, 0, STFBRemap);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
void DDoomStatusBar::FDoomStatusBarTexture::DrawToBar (const char *name, int x, int y, const BYTE *colormap)
|
|
{
|
|
FTexture *pic = TexMan[name];
|
|
if (pic != NULL)
|
|
{
|
|
x -= pic->LeftOffset;
|
|
pic->CopyToBlock (Pixels, Width, Height, x, y, colormap);
|
|
}
|
|
}
|
|
|
|
void DDoomStatusBar::FDoomStatusBarTexture::SetPlayerRemap(FRemapTable *remap)
|
|
{
|
|
Unload();
|
|
KillNative();
|
|
STFBRemap = remap;
|
|
}
|
|
|
|
DBaseStatusBar *CreateDoomStatusBar ()
|
|
{
|
|
return new DDoomStatusBar;
|
|
}
|