gzdoom/src/g_doom/doom_sbar.cpp
Christoph Oelckers e08da03a3d - Increased precision of texture scaling factors to full fixed point. In the process
I got rid of the old tx and ty CVARs because they made the texture scaling
  much more complicated than it was actually needed (and besides, they were completely
  useless except for testing purposes anyway.)


SVN r522 (trunk)
2007-04-29 12:07:27 +00:00

1136 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"
#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 FDoomStatusBar : public FBaseStatusBar
{
public:
FDoomStatusBar () : FBaseStatusBar (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;
FBaseStatusBar::Images.Init (sharedLumpNames, NUM_BASESB_IMAGES);
tex = FBaseStatusBar::Images[imgBNumbers];
BigWidth = tex->GetWidth();
BigHeight = tex->GetHeight();
DoCommonInit ();
bEvilGrin = false;
}
~FDoomStatusBar ()
{
}
void NewGame ()
{
Images.Uninit ();
DoCommonInit ();
if (CPlayer != NULL)
{
AttachToPlayer (CPlayer);
}
}
void SetFace (void *skn)
{
const char *nameptrs[ST_NUMFACES];
char names[ST_NUMFACES][9];
char prefix[4];
int i, j;
int namespc;
int facenum;
FPlayerSkin *skin = (FPlayerSkin *)skn;
for (i = 0; i < ST_NUMFACES; i++)
{
nameptrs[i] = names[i];
}
if (skin->face[0] != 0)
{
prefix[0] = skin->face[0];
prefix[1] = skin->face[1];
prefix[2] = skin->face[2];
prefix[3] = 0;
namespc = skin->namespc;
}
else
{
prefix[0] = 'S';
prefix[1] = 'T';
prefix[2] = 'F';
prefix[3] = 0;
namespc = ns_global;
}
facenum = 0;
for (i = 0; i < ST_NUMPAINFACES; i++)
{
for (j = 0; j < ST_NUMSTRAIGHTFACES; j++)
{
sprintf (names[facenum++], "%sST%d%d", prefix, i, j);
}
sprintf (names[facenum++], "%sTR%d0", prefix, i); // turn right
sprintf (names[facenum++], "%sTL%d0", prefix, i); // turn left
sprintf (names[facenum++], "%sOUCH%d", prefix, i); // ouch!
sprintf (names[facenum++], "%sEVL%d", prefix, i); // evil grin ;)
sprintf (names[facenum++], "%sKILL%d", prefix, i); // pissed off
}
sprintf (names[facenum++], "%sGOD0", prefix);
sprintf (names[facenum++], "%sDEAD0", prefix);
Faces.Uninit ();
Faces.Init (nameptrs, ST_NUMFACES, namespc);
FaceIndex = 0;
FaceCount = 0;
OldFaceIndex = -1;
}
void MultiplayerChanged ()
{
FBaseStatusBar::MultiplayerChanged ();
if (multiplayer)
{
// draw face background
StatusBarTex.DrawToBar ("STFBANY", 143, 1,
translationtables[TRANSLATION_Players] + (CPlayer - players)*256);
}
}
void AttachToPlayer (player_t *player)
{
player_t *oldplayer = CPlayer;
FBaseStatusBar::AttachToPlayer (player);
if (oldplayer != CPlayer)
{
SetFace (&skins[CPlayer->userinfo.skin]);
}
if (multiplayer)
{
// draw face background
StatusBarTex.DrawToBar ("STFBANY", 143, 1,
translationtables[TRANSLATION_Players] + (CPlayer - players)*256);
}
bEvilGrin = false;
}
void Tick ()
{
FBaseStatusBar::Tick ();
RandomNumber = M_Random ();
UpdateFace ();
}
void Draw (EHudState state)
{
FBaseStatusBar::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));
OldFaceIndex = -1;
OldHealth = -1;
OldArmor = -1;
OldActiveAmmo = -1;
OldFrags = -9999;
FaceHealth = -9999;
}
DrawMainBar ();
if (CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR))
{
DrawInventoryBar ();
SB_state = screen->GetPageCount ();
}
}
}
private:
struct FDoomStatusBarTexture : public FTexture
{
public:
FDoomStatusBarTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels ();
void Unload ();
~FDoomStatusBarTexture ();
void DrawToBar (const char *name, int x, int y, BYTE *colormap_in = NULL);
protected:
void MakeTexture ();
FTexture * BaseTexture;
BYTE *Pixels;
}
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 ();
if (!deathmatch)
{
StatusBarTex.DrawToBar ("STARMS", 104, 0);
}
StatusBarTex.DrawToBar ("STTPRCNT", 90, 3); // Health %
StatusBarTex.DrawToBar ("STTPRCNT", 221, 3); // Armor %
SB_state = screen->GetPageCount ();
FaceLastAttackDown = -1;
FacePriority = 0;
}
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 ? FBaseStatusBar::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 DrawFace ()
{
// If a player has an inventory item selected, it takes the place of the
// face, for lack of a better place to put it.
if (OldFaceIndex != FaceIndex)
{
FaceRefresh = screen->GetPageCount ();
OldFaceIndex = FaceIndex;
}
if (FaceRefresh || (CPlayer->mo->InvSel != NULL && !(level.flags & LEVEL_NOINVENTORYBAR)))
{
if (FaceRefresh)
{
FaceRefresh--;
}
DrawPartialImage (&StatusBarTex, 142, 37);
if (CPlayer->mo->InvSel == NULL || (level.flags & LEVEL_NOINVENTORYBAR))
{
DrawImage (Faces[FaceIndex], 143, 0);
}
else
{
DrawImage (TexMan(CPlayer->mo->InvSel->Icon), 144, 0, CPlayer->mo->InvSel->Amount > 0 ? NULL : DIM_MAP);
if (CPlayer->mo->InvSel->Amount != 1)
{
DrSmallNumber (CPlayer->mo->InvSel->Amount, 165, 24);
}
OldFaceIndex = -1;
}
}
}
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 ()
{
const 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);
DrawImage (TexMan(item->Icon), 50+i*31, 2, item->Amount > 0 ? NULL : DIM_MAP);
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 ()
{
const 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_Translation, CPlayer->mo->InvSel->Amount > 0 ? NULL : DIM_MAP,
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_Translation, item->Amount > 0 ? NULL : DIM_MAP,
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, -3,
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;
}
//
// This is a not-very-pretty routine which handles the face states
// and their timing. The precedence of expressions is:
// dead > evil grin > turned head > straight ahead
//
void UpdateFace ()
{
int i;
angle_t badguyangle;
angle_t diffang;
if (FacePriority < 10)
{
// dead
if (CPlayer->health <= 0)
{
FacePriority = 9;
FaceIndex = ST_DEADFACE;
FaceCount = 1;
}
}
if (FacePriority < 9)
{
if (CPlayer->bonuscount)
{
// picking up bonus
if (bEvilGrin)
{
// evil grin if just picked up weapon
bEvilGrin = false;
FacePriority = 8;
FaceCount = ST_EVILGRINCOUNT;
FaceIndex = CalcPainOffset() + ST_EVILGRINOFFSET;
}
}
else
{
// This happens when a weapon is added to the inventory
// by other means than being picked up.
bEvilGrin = false;
}
}
if (FacePriority < 8)
{
if (CPlayer->damagecount
&& CPlayer->attacker
&& CPlayer->attacker != CPlayer->mo)
{
// being attacked
FacePriority = 7;
if (FaceHealth != -9999 && FaceHealth - CPlayer->health > ST_MUCHPAIN)
{
FaceCount = ST_TURNCOUNT;
FaceIndex = CalcPainOffset() + ST_OUCHOFFSET;
FacePriority = 8;
}
else if (CPlayer->mo != NULL)
{
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?
FaceCount = ST_TURNCOUNT;
FaceIndex = CalcPainOffset();
if (diffang < ANG45)
{
// head-on
FaceIndex += ST_RAMPAGEOFFSET;
}
else if (i)
{
// turn face right
FaceIndex += ST_TURNOFFSET;
}
else
{
// turn face left
FaceIndex += ST_TURNOFFSET+1;
}
}
}
}
if (FacePriority < 7)
{
// getting hurt because of your own damn stupidity
if (CPlayer->damagecount)
{
if (OldHealth != -1 && CPlayer->health - OldHealth > ST_MUCHPAIN)
{
FacePriority = 7;
FaceCount = ST_TURNCOUNT;
FaceIndex = CalcPainOffset() + ST_OUCHOFFSET;
}
else
{
FacePriority = 6;
FaceCount = ST_TURNCOUNT;
FaceIndex = CalcPainOffset() + ST_RAMPAGEOFFSET;
}
}
}
if (FacePriority < 6)
{
// rapid firing
if ((CPlayer->cmd.ucmd.buttons & BT_ATTACK) && !(CPlayer->cheats & (CF_FROZEN | CF_TOTALLYFROZEN)))
{
if (FaceLastAttackDown == -1)
FaceLastAttackDown = ST_RAMPAGEDELAY;
else if (!--FaceLastAttackDown)
{
FacePriority = 5;
FaceIndex = CalcPainOffset() + ST_RAMPAGEOFFSET;
FaceCount = 1;
FaceLastAttackDown = 1;
}
}
else
{
FaceLastAttackDown = -1;
}
}
if (FacePriority < 5)
{
// invulnerability
if ((CPlayer->cheats & CF_GODMODE)
|| (CPlayer->mo != NULL && CPlayer->mo->flags2 & MF2_INVULNERABLE))
{
FacePriority = 4;
FaceIndex = ST_GODFACE;
FaceCount = 1;
}
}
// look left or look right if the facecount has timed out
if (!FaceCount)
{
FaceIndex = CalcPainOffset() + (RandomNumber % 3);
FaceCount = ST_STRAIGHTFACECOUNT;
FacePriority = 0;
}
FaceCount--;
FaceHealth = CPlayer->health;
}
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
};
enum
{
ST_NUMPAINFACES = 5,
ST_NUMSTRAIGHTFACES = 3,
ST_NUMTURNFACES = 2,
ST_NUMSPECIALFACES = 3,
ST_NUMEXTRAFACES = 2,
ST_FACESTRIDE = ST_NUMSTRAIGHTFACES+ST_NUMTURNFACES+ST_NUMSPECIALFACES,
ST_NUMFACES = ST_FACESTRIDE*ST_NUMPAINFACES+ST_NUMEXTRAFACES,
ST_TURNOFFSET = ST_NUMSTRAIGHTFACES,
ST_OUCHOFFSET = ST_TURNOFFSET + ST_NUMTURNFACES,
ST_EVILGRINOFFSET = ST_OUCHOFFSET + 1,
ST_RAMPAGEOFFSET = ST_EVILGRINOFFSET + 1,
ST_GODFACE = ST_NUMPAINFACES*ST_FACESTRIDE,
ST_DEADFACE = ST_GODFACE + 1
};
FImageCollection Images;
FImageCollection Faces;
int BigWidth;
int BigHeight;
int FaceIndex;
int FaceCount;
int RandomNumber;
int OldFaceIndex;
BYTE OldArms[6];
int OldKeys;
int OldAmmo[4];
int OldMaxAmmo[4];
int OldHealth;
int OldArmor;
int OldActiveAmmo;
int OldFrags;
int FaceHealth;
int FaceLastAttackDown;
int FacePriority;
char HealthRefresh;
char ArmorRefresh;
char ActiveAmmoRefresh;
char FragsRefresh;
char ArmsRefresh[3];
char AmmoRefresh;
char MaxAmmoRefresh;
char FaceRefresh;
char KeysRefresh;
bool bEvilGrin;
};
FDoomStatusBar::FDoomStatusBarTexture::FDoomStatusBarTexture ()
{
BaseTexture = TexMan[TexMan.AddPatch("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;
}
const BYTE *FDoomStatusBar::FDoomStatusBarTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
BaseTexture->GetColumn(column, spans_out);
return Pixels + column*Height;
}
const BYTE *FDoomStatusBar::FDoomStatusBarTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FDoomStatusBar::FDoomStatusBarTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
FDoomStatusBar::FDoomStatusBarTexture::~FDoomStatusBarTexture ()
{
Unload ();
}
void FDoomStatusBar::FDoomStatusBarTexture::MakeTexture ()
{
Pixels = new BYTE[Width*Height];
const BYTE *pix = BaseTexture->GetPixels();
memcpy(Pixels, pix, Width*Height);
}
void FDoomStatusBar::FDoomStatusBarTexture::DrawToBar (const char *name, int x, int y, BYTE *colormap_in)
{
FTexture *pic;
BYTE colormap[256];
if (Pixels == NULL)
{
MakeTexture ();
}
if (colormap_in != NULL)
{
for (int i = 0; i < 256; ++i)
{
colormap[i] = colormap_in[i] == 255 ? Near255 : colormap_in[i];
}
}
else
{
for (int i = 0; i < 255; ++i)
{
colormap[i] = i;
}
colormap[255] = Near255;
}
pic = TexMan[name];
if (pic != NULL)
{
x -= pic->LeftOffset;
pic->CopyToBlock (Pixels, Width, Height, x, y, colormap);
}
}
FBaseStatusBar *CreateDoomStatusBar ()
{
return new FDoomStatusBar;
}