From 4850a98c131c039561c00331d9855cca764a8db4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 1 Jun 2008 03:35:47 +0000 Subject: [PATCH] - Consolidated the mug shot code shared by DSBarInfo and DDoomStatusBar into a single place. - Fixed: Setting an invalid mug shot state crashed the game. - Fixed my attempts to be clever with strings yesterday. SVN r1009 (trunk) --- docs/rh-log.txt | 6 + src/g_doom/doom_sbar.cpp | 218 ++------------ src/g_shared/sbar.h | 89 +++++- src/g_shared/sbar_mugshot.cpp | 473 ++++++++++++++++++++++++++++++ src/g_shared/sbarinfo.h | 54 +--- src/g_shared/sbarinfo_display.cpp | 291 +----------------- src/g_shared/sbarinfo_parser.cpp | 51 +--- src/g_shared/shared_sbar.cpp | 4 + zdoom.vcproj | 440 +++++++++++++-------------- 9 files changed, 837 insertions(+), 789 deletions(-) create mode 100644 src/g_shared/sbar_mugshot.cpp diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 80e42ed00d..d976c2915c 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,9 @@ +May 31, 2008 +- Consolidated the mug shot code shared by DSBarInfo and DDoomStatusBar + into a single place. +- Fixed: Setting an invalid mug shot state crashed the game. +- Fixed my attempts to be clever with strings yesterday. + May 30, 2008 - If an actor's current target temporarily goes unshootable, its threshold is now reset to 0, so it will more readily switch back to it. diff --git a/src/g_doom/doom_sbar.cpp b/src/g_doom/doom_sbar.cpp index edbcadb6fd..07ae34b0ed 100644 --- a/src/g_doom/doom_sbar.cpp +++ b/src/g_doom/doom_sbar.cpp @@ -21,9 +21,6 @@ #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) @@ -51,14 +48,6 @@ public: BigHeight = tex->GetHeight(); DoCommonInit (); - - bEvilGrin = false; - bNormal = true; - bDamageFaceActive = false; - bOuchActive = false; - CurrentState = NULL; - RampageTimer = 0; - LastDamageAngle = 1; } ~DDoomStatusBar () @@ -104,7 +93,7 @@ public: // set face background color StatusBarTex.SetPlayerRemap(translationtables[TRANSLATION_Players][int(CPlayer - players)]); } - bEvilGrin = false; + MugShot.bEvilGrin = false; } void Tick () @@ -113,28 +102,7 @@ public: 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) - { - bNormal = true; - bOuchActive = false; - 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; + MugShot.Tick(CPlayer); } void Draw (EHudState state) @@ -160,7 +128,6 @@ public: OldArmor = -1; OldActiveAmmo = -1; OldFrags = -9999; - FaceHealth = -9999; } DrawMainBar (); if (CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR)) @@ -171,22 +138,6 @@ public: } } - //See sbarinfo_display.cpp - void SetMugShotState (const char* stateName, bool waitTillDone=false) - { - bNormal = false; //Assume we are not setting god or normal for now. - bOuchActive = false; - MugShotState *state = (MugShotState *) FindMugShotState(stateName); - if(state != CurrentState) - { - if(!waitTillDone || CurrentState == NULL || CurrentState->finished) - { - CurrentState = state; - state->reset(); - } - } - } - private: struct FDoomStatusBarTexture : public FTexture { @@ -747,161 +698,37 @@ private: void ReceivedWeapon (AWeapon *weapon) { - bEvilGrin = true; + MugShot.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; - } - } - } - bool useOuch = false; - const char *stateName; - if ((FaceHealth != -1 && CPlayer->health - FaceHealth > 20) || bOuchActive) - { - useOuch = true; - stateName = "ouch."; - } - else - stateName = "pain."; - FString fullStateName; - fullStateName << stateName << CPlayer->LastDamageType; - if(FindMugShotState(fullStateName) != NULL) - SetMugShotState(fullStateName); - else - SetMugShotState(stateName); - bDamageFaceActive = !(CurrentState == NULL); - LastDamageAngle = damageAngle; - bOuchActive = useOuch; - return damageAngle; - } - if(bDamageFaceActive) - { - if(CurrentState == NULL) - bDamageFaceActive = false; - else - { - bool useOuch = false; - const char *stateName; - if ((FaceHealth != -1 && CPlayer->health - FaceHealth > 20) || bOuchActive) - { - useOuch = true; - stateName = "ouch."; - } - else - stateName = "pain."; - FString fullStateName; - fullStateName << stateName << CPlayer->LastDamageType; - if(FindMugShotState(fullStateName) != NULL) - SetMugShotState(fullStateName); - else - SetMugShotState(stateName); - bOuchActive = useOuch; - return LastDamageAngle; - } - } - - if(RampageTimer == ST_RAMPAGEDELAY) - { - SetMugShotState("rampage", !bNormal); //If we have nothing better to show use the rampage face. - return 0; - } - - if(bNormal) - { - if((CPlayer->cheats & CF_GODMODE) || (CPlayer->mo != NULL && CPlayer->mo->flags2 & MF2_INVULNERABLE)) - SetMugShotState("god"); - else - SetMugShotState("normal"); - bNormal = true; //SetMugShotState sets bNormal to false. - } - } - else - { - FString fullStateName; - fullStateName << "death." << CPlayer->LastDamageType; - if(FindMugShotState(fullStateName) != NULL) - SetMugShotState(fullStateName); - else - SetMugShotState("death"); - } - return 0; - } - - void DrawFace () + 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 (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) + FTexture *face = MugShot.GetFace(CPlayer, "STF", 5, false, false); + if (face != 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); - } + DrawPartialImage(&StatusBarTex, 142, 37); + DrawImage(face, 143, 0); } } else { - DrawDimImage (TexMan(CPlayer->mo->InvSel->Icon), 144, 0, CPlayer->mo->InvSel->Amount <= 0); + 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); + DrSmallNumber(CPlayer->mo->InvSel->Amount, 165, 24); } } } + void SetMugShotState (const char *state_name, bool wait_till_done) + { + MugShot.SetState(state_name, wait_till_done); + } + enum { imgKEYS0, @@ -952,18 +779,9 @@ private: char ArmsRefresh[3]; char AmmoRefresh; char MaxAmmoRefresh; - char FaceRefresh; char KeysRefresh; - //Mugshot - MugShotState *CurrentState; - int RampageTimer; - int LastDamageAngle; - int FaceHealth; - bool bEvilGrin; - bool bDamageFaceActive; - bool bNormal; - bool bOuchActive; + FMugShot MugShot; }; IMPLEMENT_CLASS(DDoomStatusBar) diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 26f9c28676..66ce4f08cd 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -52,6 +52,8 @@ enum EHudState class AWeapon; +// HUD Message base object -------------------------------------------------- + class DHUDMessage : public DObject { DECLARE_CLASS (DHUDMessage, DObject) @@ -92,6 +94,8 @@ private: friend class DBaseStatusBar; }; +// HUD Message; appear instantly, then fade out type ------------------------ + class DHUDMessageFadeOut : public DHUDMessage { DECLARE_CLASS (DHUDMessageFadeOut, DHUDMessage) @@ -109,6 +113,8 @@ protected: DHUDMessageFadeOut() {} }; +// HUD Message; fade in, then fade out type --------------------------------- + class DHUDMessageFadeInOut : public DHUDMessageFadeOut { DECLARE_CLASS (DHUDMessageFadeInOut, DHUDMessageFadeOut) @@ -126,6 +132,8 @@ protected: DHUDMessageFadeInOut() {} }; +// HUD Message; type on, then fade out type --------------------------------- + class DHUDMessageTypeOnFadeOut : public DHUDMessageFadeOut { DECLARE_CLASS (DHUDMessageTypeOnFadeOut, DHUDMessageFadeOut) @@ -147,6 +155,73 @@ protected: DHUDMessageTypeOnFadeOut() {} }; +// Mug shots ---------------------------------------------------------------- + +struct FMugShotFrame +{ + TArray Graphic; + int Delay; + + FMugShotFrame(); + ~FMugShotFrame(); + FTexture *GetTexture(const char *default_face, FPlayerSkin *skin, int random, int level=0, + int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, + bool directional=false); +}; + +struct FMugShotState +{ + BYTE bUsesLevels:1; + BYTE bHealth2:1; // Health level is the 2nd character from the end. + BYTE bHealthSpecial:1; // Like health2 only the 2nd frame gets the normal health type. + BYTE bDirectional:1; // Faces direction of damage. + BYTE bFinished:1; + + unsigned int Position; + int Time; + int Random; + FName State; + TArray Frames; + + FMugShotState(FName name); + ~FMugShotState(); + void Tick(); + void Reset(); + FMugShotFrame &GetCurrentFrame() { return Frames[Position]; } + FTexture *GetCurrentFrameTexture(const char *default_face, FPlayerSkin *skin, int level=0, int direction=0) + { + return GetCurrentFrame().GetTexture(default_face, skin, Random, level, direction, bUsesLevels, bHealth2, bHealthSpecial, bDirectional); + } +private: + FMugShotState(); +}; + +class player_s; +struct FMugShot +{ + FMugShot(); + void Tick(player_s *player); + bool SetState(const char *state_name, bool wait_till_done=false); + int UpdateState(player_s *player, bool xdeath, bool animated_god_mode); + FTexture *GetFace(player_s *player, const char *default_face, int accuracy, bool xdeath, bool animated_god_mode); + + FMugShotState *CurrentState; + int RampageTimer; + int LastDamageAngle; + int FaceHealth; + bool bEvilGrin; + bool bDamageFaceActive; + bool bNormal; + bool bOuchActive; +}; + +extern TArray MugShotStates; + +FMugShotState *FindMugShotState(FName state); +int FindMugShotStateIndex(FName state); + +// Base Status Bar ---------------------------------------------------------- + class FTexture; class AAmmo; @@ -218,7 +293,7 @@ public: virtual void ShowPop (int popnum); virtual void ReceivedWeapon (AWeapon *weapon); virtual bool MustDrawLog(EHudState state); - virtual void SetMugShotState (const char* stateName, bool waitTillDone=false) {} + virtual void SetMugShotState (const char *state_name, bool wait_till_done=false); void DrawLog(); protected: @@ -285,8 +360,10 @@ private: extern DBaseStatusBar *StatusBar; -DBaseStatusBar *CreateDoomStatusBar (); -DBaseStatusBar *CreateHereticStatusBar (); -DBaseStatusBar *CreateHexenStatusBar (); -DBaseStatusBar *CreateStrifeStatusBar (); -DBaseStatusBar *CreateCustomStatusBar (); +// Status bar factories ----------------------------------------------------- + +DBaseStatusBar *CreateDoomStatusBar(); +DBaseStatusBar *CreateHereticStatusBar(); +DBaseStatusBar *CreateHexenStatusBar(); +DBaseStatusBar *CreateStrifeStatusBar(); +DBaseStatusBar *CreateCustomStatusBar(); diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp new file mode 100644 index 0000000000..d3aa3786d8 --- /dev/null +++ b/src/g_shared/sbar_mugshot.cpp @@ -0,0 +1,473 @@ +/* +** sbar_mugshot.cpp +** +** Draws customizable mugshots for the status bar. +** +**--------------------------------------------------------------------------- +** Copyright 2008 Braden Obrzut +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "r_defs.h" +#include "r_main.h" +#include "m_random.h" +#include "d_player.h" +#include "d_event.h" +#include "sbar.h" + +#define ST_RAMPAGEDELAY (2*TICRATE) +#define ST_MUCHPAIN 20 + +TArray MugShotStates; + + +//=========================================================================== +// +// FMugShotFrame constructor +// +//=========================================================================== + +FMugShotFrame::FMugShotFrame() +{ +} + +//=========================================================================== +// +// FMugShotFrame destructor +// +//=========================================================================== + +FMugShotFrame::~FMugShotFrame() +{ +} + +//=========================================================================== +// +// FMugShotFrame :: GetTexture +// +// Assemble a graphic name with the specified prefix and return the FTexture. +// +//=========================================================================== + +FTexture *FMugShotFrame::GetTexture(const char *default_face, FPlayerSkin *skin, int random, int level, + int direction, bool uses_levels, bool health2, bool healthspecial, bool directional) +{ + int index = !directional ? random % Graphic.Size() : direction; + if ((unsigned int)index > Graphic.Size() - 1) + { + index = Graphic.Size() - 1; + } + FString sprite(skin->face[0] != 0 ? skin->face : default_face, 3); + sprite += Graphic[index]; + if (uses_levels) //change the last character to the level + { + if (!health2 && (!healthspecial || index == 1)) + { + sprite.LockBuffer()[2 + Graphic[index].Len()] += level; + } + else + { + sprite.LockBuffer()[1 + Graphic[index].Len()] += level; + } + sprite.UnlockBuffer(); + } + return TexMan[TexMan.CheckForTexture(sprite, 0, true)]; +} + +//=========================================================================== +// +// MugShotState default constructor +// +//=========================================================================== + +FMugShotState::FMugShotState() +{ +} + +//=========================================================================== +// +// MugShotState named constructor +// +//=========================================================================== + +FMugShotState::FMugShotState(FName name) +{ + State = name; + bUsesLevels = false; + bHealth2 = false; + bHealthSpecial = false; + bDirectional = false; + bFinished = true; + Random = M_Random(); +} + +//=========================================================================== +// +// MugShotState destructor +// +//=========================================================================== + +FMugShotState::~FMugShotState() +{ +} + +//=========================================================================== +// +// FMugShotState :: Tick +// +//=========================================================================== + +void FMugShotState::Tick() +{ + if (Time == -1) + { //When the delay is negative 1, stay on this frame indefinitely. + return; + } + if (Time != 0) + { + Time--; + } + else if (Position < Frames.Size() - 1) + { + Position++; + Time = Frames[Position].Delay; + Random = M_Random(); + } + else + { + bFinished = true; + } +} + +//=========================================================================== +// +// FMugShotState :: Reset +// +//=========================================================================== + +void FMugShotState::Reset() +{ + Time = Frames[0].Delay; + Position = 0; + bFinished = false; + Random = M_Random(); +} + +//=========================================================================== +// +// FindMugShotState +// +//=========================================================================== + +FMugShotState *FindMugShotState(FName state) +{ + for (unsigned int i = 0; i < MugShotStates.Size(); i++) + { + if (MugShotStates[i].State == state) + return &MugShotStates[i]; + } + return NULL; +} + +//=========================================================================== +// +// FindMugShotStateIndex +// +// Used to allow replacements of states +// +//=========================================================================== + +int FindMugShotStateIndex(FName state) +{ + for (unsigned int i = 0; i < MugShotStates.Size(); i++) + { + if (MugShotStates[i].State == state) + return i; + } + return -1; +} + +//=========================================================================== +// +// FMugShot constructor +// +//=========================================================================== + +FMugShot::FMugShot() +{ + FaceHealth = -1; + bEvilGrin = false; + bNormal = true; + bDamageFaceActive = false; + bOuchActive = false; + CurrentState = NULL; + RampageTimer = 0; + LastDamageAngle = 1; +} + +//=========================================================================== +// +// FMugShot :: Tick +// +// Do some stuff related to the mug shot that has to be done at 35fps +// +//=========================================================================== + +void FMugShot::Tick(player_t *player) +{ + if (CurrentState != NULL) + { + CurrentState->Tick(); + if (CurrentState->bFinished) + { + bNormal = true; + bOuchActive = false; + CurrentState = NULL; + } + } + if ((player->cmd.ucmd.buttons & (BT_ATTACK|BT_ALTATTACK)) && !(player->cheats & (CF_FROZEN | CF_TOTALLYFROZEN))) + { + if (RampageTimer != ST_RAMPAGEDELAY) + { + RampageTimer++; + } + } + else + { + RampageTimer = 0; + } + FaceHealth = player->health; +} + +//=========================================================================== +// +// FMugShot :: SetState +// +// Sets the mug shot state and resets it if it is not the state we are +// already on. Wait_till_done is basically a priority variable; when set to +// true the state won't change unless the previous state is finished. +// Returns true if the requested state was switched to or is already playing, +// and false if the requested state could not be set. +// +//=========================================================================== + +bool FMugShot::SetState(const char *state_name, bool wait_till_done) +{ + // Search for full name. + FMugShotState *state = FindMugShotState(FName(state_name, true)); + if (state == NULL) + { + // Search for initial name, if the full one contains a dot. + const char *dot = strchr(state_name, '.'); + if (dot != NULL) + { + state = FindMugShotState(FName(state_name, dot - state_name, true)); + } + if (state == NULL) + { + // Requested state does not exist, so do nothing. + return false; + } + } + bNormal = false; //Assume we are not setting god or normal for now. + bOuchActive = false; + if (state != CurrentState) + { + if (!wait_till_done || CurrentState == NULL || CurrentState->bFinished) + { + CurrentState = state; + state->Reset(); + return true; + } + return false; + } + return true; +} + +//=========================================================================== +// +// FMugShot :: UpdateState +// +//=========================================================================== + +int FMugShot::UpdateState(player_t *player, bool xdeath, bool animated_god_mode) +{ + int i; + angle_t badguyangle; + angle_t diffang; + FString full_state_name; + + if (player->health > 0) + { + if (bEvilGrin) + { + if (CurrentState == NULL) + { + bEvilGrin = false; + } + else if (player->bonuscount) + { + SetState("grin", false); + return 0; + } + } + + if (player->damagecount) + { + int damage_angle = 1; + if (player->attacker && player->attacker != player->mo) + { + if (player->mo != NULL) + { + // The next 12 lines are from the Doom statusbar code. + badguyangle = R_PointToAngle2(player->mo->x, player->mo->y, player->attacker->x, player->attacker->y); + if (badguyangle > player->mo->angle) + { + // whether right or left + diffang = badguyangle - player->mo->angle; + i = diffang > ANG180; + } + else + { + // whether left or right + diffang = player->mo->angle - badguyangle; + i = diffang <= ANG180; + } // confusing, aint it? + if (i && diffang >= ANG45) + { + damage_angle = 0; + } + else if (!i && diffang >= ANG45) + { + damage_angle = 2; + } + } + } + bool use_ouch = false; + if ((FaceHealth != -1 && player->health - FaceHealth > ST_MUCHPAIN) || bOuchActive) + { + use_ouch = true; + full_state_name = "ouch."; + } + else + { + full_state_name = "pain."; + } + full_state_name += player->LastDamageType; + if (SetState(full_state_name)) + { + bDamageFaceActive = (CurrentState != NULL); + LastDamageAngle = damage_angle; + bOuchActive = use_ouch; + } + return damage_angle; + } + if (bDamageFaceActive) + { + if (CurrentState == NULL) + { + bDamageFaceActive = false; + } + else + { + bool use_ouch = false; + if ((FaceHealth != -1 && player->health - FaceHealth > ST_MUCHPAIN) || bOuchActive) + { + use_ouch = true; + full_state_name = "ouch."; + } + else + { + full_state_name = "pain."; + } + full_state_name += player->LastDamageType; + if (SetState(full_state_name)) + { + bOuchActive = use_ouch; + } + return LastDamageAngle; + } + } + + if (RampageTimer == ST_RAMPAGEDELAY) + { + SetState("rampage", !bNormal); //If we have nothing better to show, use the rampage face. + return 0; + } + + if (bNormal) + { + bool good; + if ((player->cheats & CF_GODMODE) || (player->mo != NULL && player->mo->flags2 & MF2_INVULNERABLE)) + { + good = SetState(animated_god_mode ? "godanimated" : "god"); + } + else + { + good = SetState("normal"); + } + if (good) + { + bNormal = true; //SetState sets bNormal to false. + } + } + } + else + { + if (!xdeath || !(player->cheats & CF_EXTREMELYDEAD)) + { + full_state_name = "death."; + } + else + { + full_state_name = "xdeath."; + } + full_state_name += player->LastDamageType; + SetState(full_state_name); + } + return 0; +} + +FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accuracy, bool xdeath, bool animated_god_mode) +{ + if (player->mo->InvSel == NULL || (level.flags & LEVEL_NOINVENTORYBAR)) + { + int angle = UpdateState(player, xdeath, animated_god_mode); + int level = 0; + while (player->health < (4-level) * (player->mo->GetMaxHealth()/5)) + { + level++; + } + if (CurrentState != NULL) + { + FPlayerSkin *skin = &skins[player->morphTics ? player->MorphedPlayerClass : player->userinfo.skin]; + return CurrentState->GetCurrentFrameTexture(default_face, skin, level, angle); + } + } + return NULL; +} diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index b9e8891485..36c721c0e9 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -133,7 +133,7 @@ struct SBarInfo int GetGameType() { return gameType; } void ParseSBarInfo(int lump); void ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block); - void ParseMugShotBlock(FScanner &sc, MugShotState &state); + void ParseMugShotBlock(FScanner &sc, FMugShotState &state); void getCoordinates(FScanner &sc, SBarInfoCommand &cmd); //retrieves the next two arguments as x and y. int getSignedInteger(FScanner &sc); //returns a signed integer. int newImage(const char* patchname); @@ -147,47 +147,6 @@ struct SBarInfo extern SBarInfo *SBarInfoScript; -//Mug Shot scripting structs. -struct MugShotState; - -struct MugShotFrame -{ - TArray graphic; - int delay; - - MugShotFrame(); - ~MugShotFrame(); - FTexture *getTexture(FString &defaultFace, FPlayerSkin *skn, int random, int level=0, int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, bool directional=false); -}; - - -struct MugShotState -{ - bool usesLevels; - bool health2; //health level is the 2nd character from the end. - bool healthspecial; //like health2 only the 2nd frame gets the normal health type. - bool directional; //faces direction of damage. - - unsigned int position; - int time; - int random; - bool finished; - FName state; - TArray frames; - - MugShotState(); - MugShotState(FString name); - ~MugShotState(); - void tick(); - void reset(); - MugShotFrame getCurrentFrame() { return frames[position]; } - FTexture *getCurrentFrameTexture(FString &defaultFace, FPlayerSkin *skn, int level=0, int direction=0) { return getCurrentFrame().getTexture(defaultFace, skn, random, level, direction, usesLevels, health2, healthspecial, directional); } -}; - -extern TArray MugShotStates; - -const MugShotState *FindMugShotState(FString state); -int FindMugShotStateIndex(FName state); // Enums used between the parser and the display enum //statusbar flags @@ -386,7 +345,7 @@ private: void DrawGraphic(FTexture* texture, int x, int y, int xOffset, int yOffset, int alpha, bool translate=false, bool dim=false, bool center=false); void DrawString(const char* str, int x, int y, int xOffset, int yOffset, int alpha, EColorRange translation, int spacing=0); void DrawNumber(int num, int len, int x, int y, int xOffset, int yOffset, int alpha, EColorRange translation, int spacing=0, bool fillzeros=false); - void DrawFace(FString &defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y, int xOffset, int yOffset, int alpha); + void DrawFace(const char *defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y, int xOffset, int yOffset, int alpha); int updateState(bool xdth, bool animatedgodmode); void DrawInventoryBar(int type, int num, int x, int y, int xOffset, int yOffset, int alpha, bool alwaysshow, int counterx, int countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter); @@ -397,14 +356,6 @@ private: FImageCollection Images; FPlayerSkin *oldSkin; FFont *drawingFont; - FString lastPrefix; - MugShotState *currentState; - bool weaponGrin; - bool damageFaceActive; - bool mugshotNormal; - bool ouchActive; - int lastDamageAngle; - int rampageTimer; int oldHealth; int oldArmor; int mugshotHealth; @@ -417,6 +368,7 @@ private: FBarShader shader_horz_reverse; FBarShader shader_vert_normal; FBarShader shader_vert_reverse; + FMugShot MugShot; }; #endif //__SBarInfo_SBAR_H__ diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp index 2fbaafc98c..bb91e8845f 100644 --- a/src/g_shared/sbarinfo_display.cpp +++ b/src/g_shared/sbarinfo_display.cpp @@ -74,83 +74,6 @@ enum imgINVRTGEM2, }; - -// Custom Mug Shot Stuff (Find mug shot state functions are with the parser). -MugShotFrame::MugShotFrame() -{ -} - -MugShotFrame::~MugShotFrame() -{ - graphic.Clear(); -} - -//Assemble a graphic name with the specified prefix and return the FTexture. -FTexture *MugShotFrame::getTexture(FString &defaultFace, FPlayerSkin *skin, int random, int level, int direction, bool usesLevels, bool health2, bool healthspecial, bool directional) -{ - int index = !directional ? random % graphic.Size() : direction; - if(index > (signed int) (graphic.Size()-1)) - index = graphic.Size()-1; - FString sprite(skin->face[0] != 0 ? skin->face : &defaultFace[0], 3); - sprite += graphic[index]; - if(usesLevels) //change the last character to the level - { - if(!health2 && (!healthspecial || index == 1)) - sprite.LockBuffer()[2 + graphic[index].Len()] += level; - else - sprite.LockBuffer()[1 + graphic[index].Len()] += level; - sprite.UnlockBuffer(); - } - return TexMan[TexMan.CheckForTexture(sprite, 0, true)]; -} - -MugShotState::MugShotState() -{ -} -MugShotState::MugShotState(FString name) -{ - name.ToLower(); - state = FName(name); - usesLevels = false; - health2 = false; - healthspecial = false; - directional = false; - random = M_Random(); -} - -MugShotState::~MugShotState() -{ - frames.Clear(); -} - -void MugShotState::tick() -{ - if(time == -1) //When the delay is negative 1 stay on this frame indefinitely - return; - if(time != 0) - { - time--; - } - else if(position != frames.Size()-1) - { - position++; - time = frames[position].delay; - random = M_Random(); - } - else - { - finished = true; - } -} - -void MugShotState::reset() -{ - time = frames[0].delay; - position = 0; - finished = false; - random = M_Random(); -} - //Used for shading FBarShader::FBarShader(bool vertical, bool reverse) //make an alpha map { @@ -258,19 +181,10 @@ DSBarInfo::DSBarInfo () : DBaseStatusBar (SBarInfoScript->height), invBarOffset = SBarInfoScript->Images.Size(); Images.Init(&patchnames[0], patchnames.Size()); drawingFont = V_GetFont("ConFont"); - rampageTimer = 0; oldHealth = 0; oldArmor = 0; - mugshotHealth = -1; - lastPrefix = ""; - weaponGrin = false; - damageFaceActive = false; - mugshotNormal = true; - ouchActive = false; - lastDamageAngle = 1; chainWiggle = 0; artiflash = 4; - currentState = NULL; currentPopup = POP_None; pendingPopup = POP_None; } @@ -347,9 +261,13 @@ void DSBarInfo::NewGame () void DSBarInfo::AttachToPlayer (player_t *player) { - player_t *oldplayer = CPlayer; - currentState = NULL; DBaseStatusBar::AttachToPlayer(player); + MugShot.CurrentState = NULL; +} + +void DSBarInfo::SetMugShotState (const char *state_name, bool wait_till_done) +{ + MugShot.SetState(state_name, wait_till_done); } void DSBarInfo::Tick () @@ -400,29 +318,7 @@ void DSBarInfo::Tick () artiflash--; } - //Do some stuff related to the mug shot that has to be done at 35fps - if(currentState != NULL) - { - currentState->tick(); - if(currentState->finished) - { - ouchActive = false; - mugshotNormal = true; - currentState = NULL; - } - } - if((CPlayer->cmd.ucmd.buttons & (BT_ATTACK|BT_ALTATTACK)) && !(CPlayer->cheats & (CF_FROZEN | CF_TOTALLYFROZEN))) - { - if(rampageTimer != ST_RAMPAGETIME) - { - rampageTimer++; - } - } - else - { - rampageTimer = 0; - } - mugshotHealth = CPlayer->health; + MugShot.Tick(CPlayer); if(currentPopup != POP_None) { SBarInfoScript->popups[currentPopup].tick(); @@ -435,9 +331,9 @@ void DSBarInfo::Tick () } } -void DSBarInfo::ReceivedWeapon (AWeapon *weapon) +void DSBarInfo::ReceivedWeapon(AWeapon *weapon) { - weaponGrin = true; + MugShot.bEvilGrin = true; } void DSBarInfo::FlashItem(const PClass *itemtype) @@ -465,24 +361,6 @@ void DSBarInfo::ShowPop(int popnum) } } -//Public so it can be called by ACS -//Sets the mug shot state and resets it if it is not the state we are already on. -//waitTillDone is basically a priority variable when just to true the state won't change unless the previous state is finished. -void DSBarInfo::SetMugShotState(const char* stateName, bool waitTillDone) -{ - mugshotNormal = false; - ouchActive = false; - MugShotState *state = (MugShotState *) FindMugShotState(stateName); - if(state != currentState) - { - if(!waitTillDone || currentState == NULL || currentState->finished) - { - currentState = state; - state->reset(); - } - } -} - void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset, int alpha) { //prepare ammo counts @@ -1349,160 +1227,19 @@ void DSBarInfo::DrawNumber(int num, int len, int x, int y, int xOffset, int yOff } if(SBarInfoScript->spacingCharacter == '\0') x -= int(drawingFont->StringWidth(value)+(spacing * value.Len())); - else //monospaced so just multiplay the character size + else //monospaced, so just multiplay the character size x -= int((drawingFont->GetCharWidth((int) SBarInfoScript->spacingCharacter) + spacing) * value.Len()); DrawString(value, x, y, xOffset, yOffset, alpha, translation, spacing); } //draws the mug shot -void DSBarInfo::DrawFace(FString &defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y, int xOffset, int yOffset, int alpha) +void DSBarInfo::DrawFace(const char *defaultFace, int accuracy, bool xdth, bool animatedgodmode, int x, int y, int xOffset, int yOffset, int alpha) { - int angle = updateState(xdth, animatedgodmode); - int level = 0; - while (CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy)) + FTexture *face = MugShot.GetFace(CPlayer, defaultFace, accuracy, xdth, animatedgodmode); + if (face != NULL) { - level++; + DrawGraphic(face, x, y, xOffset, yOffset, alpha); } - if(currentState != NULL) - { - FPlayerSkin *skin = &skins[CPlayer->morphTics ? CPlayer->MorphedPlayerClass : CPlayer->userinfo.skin]; - FTexture *face = currentState->getCurrentFrameTexture(defaultFace, skin, level, angle); - if (face != NULL) - DrawGraphic(face, x, y, xOffset, yOffset, alpha); - } -} - -int DSBarInfo::updateState(bool xdth, bool animatedgodmode) -{ - int i; - angle_t badguyangle; - angle_t diffang; - - if(CPlayer->health > 0) - { - if(weaponGrin) - { - if(currentState == NULL) - weaponGrin = false; - 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; - } - } - } - bool setOuch = false; - const char *stateName; - if ((mugshotHealth != -1 && CPlayer->health - mugshotHealth > 20) || ouchActive) - { - setOuch = true; - stateName = "ouch."; - } - else - stateName = "pain."; - FString fullStateName; - fullStateName << stateName << CPlayer->LastDamageType; - if(FindMugShotState(fullStateName) != NULL) - SetMugShotState(fullStateName); - else - SetMugShotState(stateName); - damageFaceActive = !(currentState == NULL); - lastDamageAngle = damageAngle; - ouchActive = setOuch; - return damageAngle; - } - if(damageFaceActive) - { - if(currentState == NULL) - damageFaceActive = false; - else - { - bool setOuch = false; - const char *stateName; - if ((mugshotHealth != -1 && CPlayer->health - mugshotHealth > 20) || ouchActive) - { - setOuch = true; - stateName = "ouch."; - } - else - stateName = "pain."; - FString fullStateName; - fullStateName << stateName << CPlayer->LastDamageType; - if(FindMugShotState(fullStateName) != NULL) - SetMugShotState(fullStateName); - else - SetMugShotState(stateName); - ouchActive = setOuch; - return lastDamageAngle; - } - } - - if(rampageTimer == ST_RAMPAGETIME) - { - SetMugShotState("rampage", !mugshotNormal); - return 0; - } - - if(mugshotNormal) - { - if((CPlayer->cheats & CF_GODMODE) || (CPlayer->mo != NULL && CPlayer->mo->flags2 & MF2_INVULNERABLE)) - { - if(animatedgodmode) - SetMugShotState("godanimated"); - else - SetMugShotState("god"); - } - else - SetMugShotState("normal"); - mugshotNormal = true; //SetMugShotState sets this to false - } - } - else - { - const char *stateName; - if(!xdth || !(CPlayer->cheats & CF_EXTREMELYDEAD)) - stateName = "death."; - else - stateName = "xdeath."; - FString fullStateName; - fullStateName << stateName << CPlayer->LastDamageType; - if(FindMugShotState(fullStateName) != NULL) - SetMugShotState(fullStateName); - else - SetMugShotState(stateName); - } - return 0; } void DSBarInfo::DrawInventoryBar(int type, int num, int x, int y, int xOffset, int yOffset, int alpha, bool alwaysshow, diff --git a/src/g_shared/sbarinfo_parser.cpp b/src/g_shared/sbarinfo_parser.cpp index cb92d3c63f..eb3bd584aa 100644 --- a/src/g_shared/sbarinfo_parser.cpp +++ b/src/g_shared/sbarinfo_parser.cpp @@ -38,8 +38,8 @@ #include "sc_man.h" #include "v_font.h" #include "w_wad.h" -#include "sbar.h" #include "d_player.h" +#include "sbar.h" #include "sbarinfo.h" #include "templates.h" #include "m_random.h" @@ -47,7 +47,6 @@ #include "i_system.h" SBarInfo *SBarInfoScript; -TArray MugShotStates; static const char *SBarInfoTopLevel[] = { @@ -287,28 +286,28 @@ void SBarInfo::ParseSBarInfo(int lump) case SBARINFO_MUGSHOT: { sc.MustGetToken(TK_StringConst); - MugShotState state(sc.String); + FMugShotState state(sc.String); if(sc.CheckToken(',')) //first loop must be a comma { do { sc.MustGetToken(TK_Identifier); if(sc.Compare("health")) - state.usesLevels = true; + state.bUsesLevels = true; else if(sc.Compare("health2")) - state.usesLevels = state.health2 = true; + state.bUsesLevels = state.bHealth2 = true; else if(sc.Compare("healthspecial")) - state.usesLevels = state.healthspecial = true; + state.bUsesLevels = state.bHealthSpecial = true; else if(sc.Compare("directional")) - state.directional = true; + state.bDirectional = true; else sc.ScriptError("Unknown MugShot state flag '%s'.", sc.String); } while(sc.CheckToken(',') || sc.CheckToken('|')); } ParseMugShotBlock(sc, state); - int index = 0; - if((index = FindMugShotStateIndex(state.state)) != -1) //We already had this state, remove the old one. + int index; + if((index = FindMugShotStateIndex(state.State)) != -1) //We already had this state, remove the old one. { MugShotStates.Delete(index); } @@ -1152,12 +1151,12 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block) sc.MustGetToken('}'); } -void SBarInfo::ParseMugShotBlock(FScanner &sc, MugShotState &state) +void SBarInfo::ParseMugShotBlock(FScanner &sc, FMugShotState &state) { sc.MustGetToken('{'); while(!sc.CheckToken('}')) { - MugShotFrame frame; + FMugShotFrame frame; bool multiframe = false; if(sc.CheckToken('{')) multiframe = true; @@ -1165,15 +1164,15 @@ void SBarInfo::ParseMugShotBlock(FScanner &sc, MugShotState &state) { sc.MustGetToken(TK_Identifier); if(strlen(sc.String) > 5) - sc.ScriptError("MugShot frames can not exceed 5 characters."); - frame.graphic.Push(sc.String); + sc.ScriptError("MugShot frames cannot exceed 5 characters."); + frame.Graphic.Push(sc.String); } while(multiframe && sc.CheckToken(',')); if(multiframe) sc.MustGetToken('}'); - frame.delay = getSignedInteger(sc); + frame.Delay = getSignedInteger(sc); sc.MustGetToken(';'); - state.frames.Push(frame); + state.Frames.Push(frame); } } @@ -1315,17 +1314,6 @@ SBarInfoBlock::SBarInfoBlock() alpha = FRACUNIT; } -const MugShotState *FindMugShotState(FString state) -{ - state.ToLower(); - for(unsigned int i = 0;i < MugShotStates.Size();i++) - { - if(MugShotStates[i].state == state) - return &MugShotStates[i]; - } - return NULL; -} - //Popup Popup::Popup() { @@ -1435,14 +1423,3 @@ void Popup::close() opened = false; moving = true; } - -//Used to allow replacements of states -int FindMugShotStateIndex(FName state) -{ - for(unsigned int i = 0;i < MugShotStates.Size();i++) - { - if(MugShotStates[i].state == state) - return i; - } - return -1; -} diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index 0a24bce13f..c6f479ff24 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1331,6 +1331,10 @@ bool DBaseStatusBar::MustDrawLog(EHudState) return true; } +void DBaseStatusBar::SetMugShotState(const char *stateName, bool waitTillDone) +{ +} + //--------------------------------------------------------------------------- // // DrawTopStuff diff --git a/zdoom.vcproj b/zdoom.vcproj index 9c4261dc10..0de14641e9 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - @@ -950,6 +940,16 @@ Outputs=""src/$(InputName).h"" /> + + + @@ -1544,16 +1544,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + + + + @@ -1924,14 +1932,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - + + @@ -2793,6 +2797,14 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> + + + @@ -2802,14 +2814,6 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> - - - @@ -3080,7 +3084,7 @@ />