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