#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(); 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(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(); 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; }