From 3f4f0a8ae4ab5a91c18b63df1049e2ec6849e495 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 1 Jan 2010 09:11:55 +0000 Subject: [PATCH] SBARINFO update: - Reorganized the SBarInfo code. - Added interpolate() flag to drawnumber, drawbar, and drawgem. The old way of interpolating the health and armor is depreciated. - Added: armortype to drawswitchableimage loosely based on Gez's submission. - As an extension to the previous you can now use comparison operators on inventory items and armortype in drawswitchableimage. SVN r2069 (trunk) --- docs/rh-log.txt | 8 + src/CMakeLists.txt | 3 +- src/g_shared/sbar.h | 48 +- src/g_shared/sbar_mugshot.cpp | 18 +- src/g_shared/sbarinfo.cpp | 1303 ++++++++++++++ src/g_shared/sbarinfo.h | 339 +--- src/g_shared/sbarinfo_commands.cpp | 2574 ++++++++++++++++++++++++++++ src/g_shared/sbarinfo_display.cpp | 1765 ------------------- src/g_shared/sbarinfo_parser.cpp | 1622 ------------------ src/p_acs.cpp | 1 - zdoom.vcproj | 772 +++++---- 11 files changed, 4333 insertions(+), 4120 deletions(-) create mode 100644 src/g_shared/sbarinfo.cpp create mode 100644 src/g_shared/sbarinfo_commands.cpp delete mode 100644 src/g_shared/sbarinfo_display.cpp delete mode 100644 src/g_shared/sbarinfo_parser.cpp diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 57fdbebbab..36d6d9a2e4 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,11 @@ +January 1, 2010 (SBARINFO update) +- Reorganized the SBarInfo code. +- Added interpolate() flag to drawnumber, drawbar, and drawgem. The old + way of interpolating the health and armor is depreciated. +- Added: armortype to drawswitchableimage loosely based on Gez's submission. +- As an extension to the previous you can now use comparison operators on + inventory items and armortype in drawswitchableimage. + January 1, 2010 (Changes by Graf Zahl) - Fixed: Heretic's Weredragon (Beast) should not have a melee state. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ee106ffb0b..3184bc6b7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -696,8 +696,7 @@ add_executable( zdoom WIN32 g_shared/a_weaponpiece.cpp g_shared/a_weapons.cpp g_shared/hudmessages.cpp - g_shared/sbarinfo_display.cpp - g_shared/sbarinfo_parser.cpp + g_shared/sbarinfo.cpp g_shared/sbar_mugshot.cpp g_shared/shared_hud.cpp g_shared/shared_sbar.cpp diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 162947bf49..d3e72c79e4 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -32,6 +32,9 @@ ** */ +#ifndef __SBAR_H__ +#define __SBAR_H__ + #include "dobject.h" #include "v_collection.h" #include "v_text.h" @@ -195,22 +198,37 @@ private: }; class player_t; -struct FMugShot +class FMugShot { - FMugShot(); - void Tick(player_t *player); - bool SetState(const char *state_name, bool wait_till_done=false, bool reset=false); - int UpdateState(player_t *player, int stateflags=0); - FTexture *GetFace(player_t *player, const char *default_face, int accuracy, int stateflags=0); + public: + enum StateFlags + { + STANDARD = 0x0, - FMugShotState *CurrentState; - int RampageTimer; - int LastDamageAngle; - int FaceHealth; - bool bEvilGrin; - bool bDamageFaceActive; - bool bNormal; - bool bOuchActive; + XDEATHFACE = 0x1, + ANIMATEDGODMODE = 0x2, + DISABLEGRIN = 0x4, + DISABLEOUCH = 0x8, + DISABLEPAIN = 0x10, + DISABLERAMPAGE = 0x20, + }; + + FMugShot(); + void Grin(bool grin=true) { bEvilGrin = grin; } + void Tick(player_t *player); + bool SetState(const char *state_name, bool wait_till_done=false, bool reset=false); + int UpdateState(player_t *player, StateFlags stateflags=STANDARD); + FTexture *GetFace(player_t *player, const char *default_face, int accuracy, StateFlags stateflags=STANDARD); + + private: + FMugShotState *CurrentState; + int RampageTimer; + int LastDamageAngle; + int FaceHealth; + bool bEvilGrin; + bool bDamageFaceActive; + bool bNormal; + bool bOuchActive; }; extern TArray MugShotStates; @@ -369,3 +387,5 @@ DBaseStatusBar *CreateCustomStatusBar(int script=0); void ST_LoadCrosshair(bool alwaysload=false); extern FTexture *CrosshairImage; + +#endif /* __SBAR_H__ */ diff --git a/src/g_shared/sbar_mugshot.cpp b/src/g_shared/sbar_mugshot.cpp index c62e7c4d61..a414765765 100644 --- a/src/g_shared/sbar_mugshot.cpp +++ b/src/g_shared/sbar_mugshot.cpp @@ -324,7 +324,7 @@ bool FMugShot::SetState(const char *state_name, bool wait_till_done, bool reset) // //=========================================================================== -int FMugShot::UpdateState(player_t *player, int stateflags) +int FMugShot::UpdateState(player_t *player, StateFlags stateflags) { int i; angle_t badguyangle; @@ -333,7 +333,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) if (player->health > 0) { - if (bEvilGrin && !(stateflags & DRAWMUGSHOT_DISABLEGRIN)) + if (bEvilGrin && !(stateflags & DISABLEGRIN)) { if (player->bonuscount) { @@ -348,7 +348,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) if (player->damagecount && // Now go in if pain is disabled but we think ouch will be shown (and ouch is not disabled!) - (!(stateflags & DRAWMUGSHOT_DISABLEPAIN) || (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DRAWMUGSHOT_DISABLEOUCH)))) + (!(stateflags & DISABLEPAIN) || (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH)))) { int damage_angle = 1; if (player->attacker && player->attacker != player->mo) @@ -380,7 +380,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) } } bool use_ouch = false; - if (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DRAWMUGSHOT_DISABLEOUCH)) + if (((FaceHealth != -1 && FaceHealth - player->health > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH)) { use_ouch = true; full_state_name = "ouch."; @@ -407,7 +407,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) else { bool use_ouch = false; - if (((FaceHealth != -1 && player->health - FaceHealth > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DRAWMUGSHOT_DISABLEOUCH)) + if (((FaceHealth != -1 && player->health - FaceHealth > ST_MUCHPAIN) || bOuchActive) && !(stateflags & DISABLEOUCH)) { use_ouch = true; full_state_name = "ouch."; @@ -425,7 +425,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) } } - if (RampageTimer == ST_RAMPAGEDELAY && !(stateflags & DRAWMUGSHOT_DISABLERAMPAGE)) + if (RampageTimer == ST_RAMPAGEDELAY && !(stateflags & DISABLERAMPAGE)) { SetState("rampage", !bNormal); //If we have nothing better to show, use the rampage face. return 0; @@ -436,7 +436,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) bool good; if ((player->cheats & CF_GODMODE) || (player->mo != NULL && player->mo->flags2 & MF2_INVULNERABLE)) { - good = SetState((stateflags & DRAWMUGSHOT_ANIMATEDGODMODE) ? "godanimated" : "god"); + good = SetState((stateflags & ANIMATEDGODMODE) ? "godanimated" : "god"); } else { @@ -450,7 +450,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) } else { - if (!(stateflags & DRAWMUGSHOT_XDEATHFACE) || !(player->cheats & CF_EXTREMELYDEAD)) + if (!(stateflags & XDEATHFACE) || !(player->cheats & CF_EXTREMELYDEAD)) { full_state_name = "death."; } @@ -473,7 +473,7 @@ int FMugShot::UpdateState(player_t *player, int stateflags) // //=========================================================================== -FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accuracy, int stateflags) +FTexture *FMugShot::GetFace(player_t *player, const char *default_face, int accuracy, StateFlags stateflags) { int angle = UpdateState(player, stateflags); int level = 0; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp new file mode 100644 index 0000000000..9a2fe38a40 --- /dev/null +++ b/src/g_shared/sbarinfo.cpp @@ -0,0 +1,1303 @@ +/* +** sbarinfo_display.cpp +** +** Contains all functions required for the display of custom statusbars. +** +**--------------------------------------------------------------------------- +** 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 "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 "sbarinfo.h" +#include "gi.h" +#include "r_translate.h" +#include "r_main.h" +#include "a_weaponpiece.h" +#include "a_strifeglobal.h" +#include "g_level.h" +#include "v_palette.h" +#include "p_acs.h" + +#define ADJUST_RELCENTER(x, y, outX, outY) \ + if(x.RelCenter()) \ + outX = *x + SCREENWIDTH/(hud_scale ? CleanXfac*2 : 2); \ + else \ + outX = *x; \ + if(y.RelCenter()) \ + outY = *y + SCREENHEIGHT/(hud_scale ? CleanYfac*2 : 2); \ + else \ + outY = *y; + +#define ARTIFLASH_OFFSET (statusBar->invBarOffset+6) +enum +{ + imgARTIBOX, + imgSELECTBOX, + imgCURSOR, + imgINVLFGEM1, + imgINVLFGEM2, + imgINVRTGEM1, + imgINVRTGEM2, +}; + +EXTERN_CVAR(Int, fraglimit) +EXTERN_CVAR(Int, screenblocks) +EXTERN_CVAR(Bool, vid_fps) +EXTERN_CVAR(Bool, hud_scale) + +class DSBarInfo; + +//////////////////////////////////////////////////////////////////////////////// + +/** + * This class is used to help prevent errors that may occur from adding or + * subtracting from coordinates. + * + * In order to provide the maximum flexibility, coordinates are packed into + * an int with one bit reserved for relCenter. + */ +class SBarInfoCoordinate +{ + public: + SBarInfoCoordinate &Add(int add) + { + value += add; + return *this; + } + int Coordinate() const { return value; } + bool RelCenter() const { return relCenter; } + void Set(int coord, bool center) { value = coord; relCenter = center; } + void SetCoord(int coord) { value = coord; } + void SetRelCenter(bool center) { relCenter = center; } + + int operator* () const { return Coordinate(); } + SBarInfoCoordinate operator+ (int add) const { return SBarInfoCoordinate(*this).Add(add); } + SBarInfoCoordinate operator+ (const SBarInfoCoordinate &other) const { return SBarInfoCoordinate(*this).Add(other.Coordinate()); } + SBarInfoCoordinate operator- (int sub) const { return SBarInfoCoordinate(*this).Add(-sub); } + SBarInfoCoordinate operator- (const SBarInfoCoordinate &other) const { return SBarInfoCoordinate(*this).Add(-other.Coordinate()); } + void operator+= (int add) { Add(add); } + void operator-= (int sub) { Add(-sub); } + + protected: + unsigned relCenter:1; + int value:31; +}; + +class SBarInfoMainBlock; + +//////////////////////////////////////////////////////////////////////////////// +/* There are three major classes here. The SBarInfoCommand is our root class. + * SBarInfoCommandFlowControl would be the base class for command which + * implements a sub-block. And SBarInfoMainBlock which is the root for a + * single hud (so all commands are held inside a MainBlock at some point). + * + * A MainBlock can be passed NULL for the first argument of the Draw function. + */ + +class SBarInfoCommand +{ + public: + enum Offset + { + TOP = 0x1, + VMIDDLE = 0x2, + BOTTOM = 0x4, + + LEFT = 0x10, + RIGHT = 0x20, + HMIDDLE = 0x40, + + CENTER = VMIDDLE|HMIDDLE, + CENTER_BOTTOM = BOTTOM|HMIDDLE + }; + + SBarInfoCommand(SBarInfo *script) : script(script) {} + virtual ~SBarInfoCommand() {} + + virtual void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar)=0; + virtual void Parse(FScanner &sc, bool fullScreenOffsets)=0; + virtual void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) {} + + protected: + void GetCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y) + { + bool negative = false; + bool relCenter = false; + SBarInfoCoordinate *coords[2] = {&x, &y}; + for(int i = 0;i < 2;i++) + { + negative = false; + relCenter = false; + if(i > 0) + sc.MustGetToken(','); + + // [-]INT center + negative = sc.CheckToken('-'); + sc.MustGetToken(TK_IntConst); + coords[i]->Set(negative ? -sc.Number : sc.Number, false); + if(sc.CheckToken('+')) + { + sc.MustGetToken(TK_Identifier); + if(!sc.Compare("center")) + sc.ScriptError("Expected 'center' but got '%s' instead.", sc.String); + relCenter = true; + } + if(fullScreenOffsets) + { + coords[i]->SetRelCenter(relCenter); + } + } + + if(!fullScreenOffsets) + y.SetCoord((negative ? -sc.Number : sc.Number) - (200 - script->height)); + } + EColorRange GetTranslation(FScanner &sc) + { + sc.MustGetToken(TK_Identifier); + EColorRange returnVal = CR_UNTRANSLATED; + FString namedTranslation; //we must send in "[translation]" + const BYTE *trans_ptr; + namedTranslation.Format("[%s]", sc.String); + trans_ptr = (const BYTE *)(&namedTranslation[0]); + if((returnVal = V_ParseFontColor(trans_ptr, CR_UNTRANSLATED, CR_UNTRANSLATED)) == CR_UNDEFINED) + { + sc.ScriptError("Missing definition for color %s.", sc.String); + } + return returnVal; + } + + SBarInfo *script; +}; + +class SBarInfoCommandFlowControl : public SBarInfoCommand +{ + public: + SBarInfoCommandFlowControl(SBarInfo *script) : SBarInfoCommand(script) {} + ~SBarInfoCommandFlowControl() + { + for(unsigned int i = 0;i < commands.Size();i++) + delete commands[i]; + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + for(unsigned int i = 0;i < commands.Size();i++) + commands[i]->Draw(block, statusBar); + } + int NumCommands() const { return commands.Size(); } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken('{'); + SBarInfoCommand *cmd = NULL; + while((cmd = NextCommand(sc)) != NULL) + { + cmd->Parse(sc, fullScreenOffsets); + commands.Push(cmd); + } + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + for(unsigned int i = 0;i < commands.Size();i++) + commands[i]->Tick(block, statusBar, hudChanged); + } + + private: + SBarInfoCommand *NextCommand(FScanner &sc); + + TArray commands; +}; + +class SBarInfoMainBlock : public SBarInfoCommandFlowControl +{ + public: + SBarInfoMainBlock(SBarInfo *script) : SBarInfoCommandFlowControl(script), + alpha(FRACUNIT), forceScaled(false), fullScreenOffsets(false) + { + } + + int Alpha() const { return alpha; } + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, int xOffset, int yOffset, int alpha) + { + this->xOffset = xOffset; + this->yOffset = yOffset; + this->alpha = alpha; + SBarInfoCommandFlowControl::Draw(this, statusBar); + } + bool ForceScaled() const { return forceScaled; } + bool FullScreenOffsets() const { return fullScreenOffsets; } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + this->fullScreenOffsets = fullScreenOffsets; + if(sc.CheckToken(',')) + { + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("forcescaled")) + forceScaled = true; + else if(sc.Compare("fullscreenoffsets")) + this->fullScreenOffsets = true; + else + sc.ScriptError("Unkown flag '%s'.", sc.String); + if(!sc.CheckToken('|') && !sc.CheckToken(',')) + { + SBarInfoCommandFlowControl::Parse(sc, this->fullScreenOffsets); + return; + } + } + sc.MustGetToken(TK_FloatConst); + alpha = fixed_t(FRACUNIT * sc.Float); + } + SBarInfoCommandFlowControl::Parse(sc, this->fullScreenOffsets); + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { SBarInfoCommandFlowControl::Tick(this, statusBar, hudChanged); } + int XOffset() const { return xOffset; } + int YOffset() const { return yOffset; } + + private: + int alpha; + bool forceScaled; + bool fullScreenOffsets; + int xOffset; + int yOffset; +}; + +//////////////////////////////////////////////////////////////////////////////// + +SBarInfo *SBarInfoScript[2] = {NULL,NULL}; + +enum //Key words +{ + SBARINFO_BASE, + SBARINFO_HEIGHT, + SBARINFO_INTERPOLATEHEALTH, + SBARINFO_INTERPOLATEARMOR, + SBARINFO_COMPLETEBORDER, + SBARINFO_MONOSPACEFONTS, + SBARINFO_LOWERHEALTHCAP, + SBARINFO_STATUSBAR, + SBARINFO_MUGSHOT, + SBARINFO_CREATEPOPUP, +}; + +enum //Bar types +{ + STBAR_NONE, + STBAR_FULLSCREEN, + STBAR_NORMAL, + STBAR_AUTOMAP, + STBAR_INVENTORY, + STBAR_INVENTORYFULLSCREEN, + STBAR_POPUPLOG, + STBAR_POPUPKEYS, + STBAR_POPUPSTATUS, +}; + +static const char *SBarInfoTopLevel[] = +{ + "base", + "height", + "interpolatehealth", + "interpolatearmor", + "completeborder", + "monospacefonts", + "lowerhealthcap", + "statusbar", + "mugshot", + "createpopup", + NULL +}; + +static const char *StatusBars[] = +{ + "none", + "fullscreen", + "normal", + "automap", + "inventory", + "inventoryfullscreen", + "popuplog", + "popupkeys", + "popupstatus", + NULL +}; + +static void FreeSBarInfoScript() +{ + for(int i = 0;i < 2;i++) + { + if (SBarInfoScript[i] != NULL) + { + delete SBarInfoScript[i]; + SBarInfoScript[i] = NULL; + } + } +} + +void SBarInfo::Load() +{ + if(gameinfo.statusbar.IsNotEmpty()) + { + int lump = Wads.CheckNumForFullName(gameinfo.statusbar, true); + if(lump != -1) + { + Printf ("ParseSBarInfo: Loading default status bar definition.\n"); + if(SBarInfoScript[SCRIPT_DEFAULT] == NULL) + SBarInfoScript[SCRIPT_DEFAULT] = new SBarInfo(lump); + else + SBarInfoScript[SCRIPT_DEFAULT]->ParseSBarInfo(lump); + } + } + + if(Wads.CheckNumForName("SBARINFO") != -1) + { + Printf ("ParseSBarInfo: Loading custom status bar definition.\n"); + int lastlump, lump; + lastlump = 0; + while((lump = Wads.FindLump("SBARINFO", &lastlump)) != -1) + { + if(SBarInfoScript[SCRIPT_CUSTOM] == NULL) + SBarInfoScript[SCRIPT_CUSTOM] = new SBarInfo(lump); + else //We now have to load multiple SBarInfo Lumps so the 2nd time we need to use this method instead. + SBarInfoScript[SCRIPT_CUSTOM]->ParseSBarInfo(lump); + } + } + atterm(FreeSBarInfoScript); +} + +//SBarInfo Script Reader +void SBarInfo::ParseSBarInfo(int lump) +{ + gameType = gameinfo.gametype; + bool baseSet = false; + FScanner sc(lump); + sc.SetCMode(true); + while(sc.CheckToken(TK_Identifier) || sc.CheckToken(TK_Include)) + { + if(sc.TokenType == TK_Include) + { + sc.MustGetToken(TK_StringConst); + int lump = Wads.CheckNumForFullName(sc.String, true); + if (lump == -1) + sc.ScriptError("Lump '%s' not found", sc.String); + ParseSBarInfo(lump); + continue; + } + switch(sc.MustMatchString(SBarInfoTopLevel)) + { + case SBARINFO_BASE: + baseSet = true; + if(!sc.CheckToken(TK_None)) + sc.MustGetToken(TK_Identifier); + if(sc.Compare("Doom")) + { + int lump = Wads.CheckNumForFullName("sbarinfo/doom.txt", true); + if(lump == -1) + sc.ScriptError("Standard Doom Status Bar not found."); + ParseSBarInfo(lump); + } + else if(sc.Compare("Heretic")) + gameType = GAME_Heretic; + else if(sc.Compare("Hexen")) + gameType = GAME_Hexen; + else if(sc.Compare("Strife")) + gameType = GAME_Strife; + else if(sc.Compare("None")) + gameType = GAME_Any; + else + sc.ScriptError("Bad game name: %s", sc.String); + sc.MustGetToken(';'); + break; + case SBARINFO_HEIGHT: + sc.MustGetToken(TK_IntConst); + this->height = sc.Number; + sc.MustGetToken(';'); + break; + case SBARINFO_INTERPOLATEHEALTH: //mimics heretics interpolated health values. + if(sc.CheckToken(TK_True)) + { + interpolateHealth = true; + } + else + { + sc.MustGetToken(TK_False); + interpolateHealth = false; + } + if(sc.CheckToken(',')) //speed param + { + sc.MustGetToken(TK_IntConst); + this->interpolationSpeed = sc.Number; + } + sc.MustGetToken(';'); + break; + case SBARINFO_INTERPOLATEARMOR: //Since interpolatehealth is such a popular command + if(sc.CheckToken(TK_True)) + { + interpolateArmor = true; + } + else + { + sc.MustGetToken(TK_False); + interpolateArmor = false; + } + if(sc.CheckToken(',')) //speed + { + sc.MustGetToken(TK_IntConst); + this->armorInterpolationSpeed = sc.Number; + } + sc.MustGetToken(';'); + break; + case SBARINFO_COMPLETEBORDER: //draws the border instead of an HOM + if(sc.CheckToken(TK_True)) + { + completeBorder = true; + } + else + { + sc.MustGetToken(TK_False); + completeBorder = false; + } + sc.MustGetToken(';'); + break; + case SBARINFO_MONOSPACEFONTS: + if(sc.CheckToken(TK_True)) + { + sc.MustGetToken(','); + sc.MustGetToken(TK_StringConst); + spacingCharacter = sc.String[0]; + } + else + { + sc.MustGetToken(TK_False); + spacingCharacter = '\0'; + sc.MustGetToken(','); + sc.MustGetToken(TK_StringConst); //Don't tell anyone we're just ignoring this ;) + } + sc.MustGetToken(';'); + break; + case SBARINFO_LOWERHEALTHCAP: + if(sc.CheckToken(TK_False)) + { + lowerHealthCap = false; + } + else + { + sc.MustGetToken(TK_True); + lowerHealthCap = true; + } + sc.MustGetToken(';'); + break; + case SBARINFO_STATUSBAR: + { + if(!baseSet) //If the user didn't explicitly define a base, do so now. + gameType = GAME_Any; + int barNum = 0; + if(!sc.CheckToken(TK_None)) + { + sc.MustGetToken(TK_Identifier); + barNum = sc.MustMatchString(StatusBars); + } + this->huds[barNum] = new SBarInfoMainBlock(this); + if(barNum == STBAR_AUTOMAP) + { + automapbar = true; + } + this->huds[barNum]->Parse(sc, false); + break; + } + case SBARINFO_MUGSHOT: + { + sc.MustGetToken(TK_StringConst); + FMugShotState state(sc.String); + if(sc.CheckToken(',')) //first loop must be a comma + { + do + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("health")) + state.bUsesLevels = true; + else if(sc.Compare("health2")) + state.bUsesLevels = state.bHealth2 = true; + else if(sc.Compare("healthspecial")) + state.bUsesLevels = state.bHealthSpecial = true; + else if(sc.Compare("directional")) + state.bDirectional = true; + else + sc.ScriptError("Unknown MugShot state flag '%s'.", sc.String); + } + while(sc.CheckToken(',') || sc.CheckToken('|')); + } + ParseMugShotBlock(sc, state); + int index; + if((index = FindMugShotStateIndex(state.State)) != -1) //We already had this state, remove the old one. + { + MugShotStates.Delete(index); + } + MugShotStates.Push(state); + break; + } + case SBARINFO_CREATEPOPUP: + { + int pop = 0; + sc.MustGetToken(TK_Identifier); + if(sc.Compare("log")) + pop = 0; + else if(sc.Compare("keys")) + pop = 1; + else if(sc.Compare("status")) + pop = 2; + else + sc.ScriptError("Unkown popup: '%s'", sc.String); + Popup &popup = popups[pop]; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + popup.width = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + popup.height = sc.Number; + sc.MustGetToken(','); + if(!sc.CheckToken(TK_None)) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("slideinbottom")) + { + popup.transition = Popup::TRANSITION_SLIDEINBOTTOM; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + popup.speed = sc.Number; + } + else if(sc.Compare("fade")) + { + popup.transition = Popup::TRANSITION_FADE; + sc.MustGetToken(','); + sc.MustGetToken(TK_FloatConst); + popup.speed = fixed_t(FRACUNIT * (1.0 / (35.0 * sc.Float))); + sc.MustGetToken(','); + sc.MustGetToken(TK_FloatConst); + popup.speed2 = fixed_t(FRACUNIT * (1.0 / (35.0 * sc.Float))); + } + else + sc.ScriptError("Unkown transition type: '%s'", sc.String); + } + popup.init(); + sc.MustGetToken(';'); + break; + } + } + } +} + +void SBarInfo::ParseMugShotBlock(FScanner &sc, FMugShotState &state) +{ + sc.MustGetToken('{'); + while(!sc.CheckToken('}')) + { + FMugShotFrame frame; + bool multiframe = false; + if(sc.CheckToken('{')) + multiframe = true; + do + { + sc.MustGetToken(TK_Identifier); + if(strlen(sc.String) > 5) + sc.ScriptError("MugShot frames cannot exceed 5 characters."); + frame.Graphic.Push(sc.String); + } + while(multiframe && sc.CheckToken(',')); + if(multiframe) + sc.MustGetToken('}'); + bool negative = sc.CheckToken('-'); + sc.MustGetToken(TK_IntConst); + frame.Delay = (negative ? -1 : 1)*sc.Number; + sc.MustGetToken(';'); + state.Frames.Push(frame); + } +} + +int SBarInfo::newImage(const char *patchname) +{ + if(patchname[0] == '\0' || stricmp(patchname, "nullimage") == 0) + { + return -1; + } + for(unsigned int i = 0;i < this->Images.Size();i++) //did we already load it? + { + if(stricmp(this->Images[i], patchname) == 0) + { + return i; + } + } + return this->Images.Push(patchname); +} + +SBarInfo::SBarInfo() //make results more predicable +{ + Init(); +} + +SBarInfo::SBarInfo(int lumpnum) +{ + Init(); + ParseSBarInfo(lumpnum); +} + +void SBarInfo::Init() +{ + automapbar = false; + interpolateHealth = false; + interpolateArmor = false; + completeBorder = false; + lowerHealthCap = true; + interpolationSpeed = 8; + armorInterpolationSpeed = 8; + height = 0; + spacingCharacter = '\0'; + + for(unsigned int i = 0;i < NUMHUDS;i++) + huds[i] = new SBarInfoMainBlock(this); +} + +SBarInfo::~SBarInfo() +{ + for (size_t i = 0; i < NUMHUDS; ++i) + { + delete huds[i]; +// huds[i].commands.Clear(); + } +} + +//Popup +Popup::Popup() +{ + transition = TRANSITION_NONE; + height = 320; + width = 200; + speed = 0; + x = 320; + y = 200; + alpha = FRACUNIT; + opened = false; + moving = false; +} + +void Popup::init() +{ + x = width; + y = height; + if(transition == TRANSITION_SLIDEINBOTTOM) + { + x = 0; + } + else if(transition == TRANSITION_FADE) + { + alpha = 0; + x = 0; + y = 0; + } +} + +void Popup::tick() +{ + if(transition == TRANSITION_SLIDEINBOTTOM) + { + if(moving) + { + if(opened) + y -= clamp(height + (y - height), 1, speed); + else + y += clamp(height - y, 1, speed); + } + if(y != 0 && y != height) + moving = true; + else + moving = false; + } + else if(transition == TRANSITION_FADE) + { + if(moving) + { + if(opened) + alpha = clamp(alpha + speed, 0, FRACUNIT); + else + alpha = clamp(alpha - speed2, 0, FRACUNIT); + } + if(alpha == 0 || alpha == FRACUNIT) + moving = false; + else + moving = true; + } + else + { + if(opened) + { + y = 0; + x = 0; + } + else + { + y = height; + x = width; + } + moving = false; + } +} + +bool Popup::isDoneMoving() +{ + return !moving; +} + +int Popup::getXOffset() +{ + return x; +} + +int Popup::getYOffset() +{ + return y; +} + +int Popup::getAlpha(int maxAlpha) +{ + double a = (double) alpha / (double) FRACUNIT; + double b = (double) maxAlpha / (double) FRACUNIT; + return fixed_t((a * b) * FRACUNIT); +} + +void Popup::open() +{ + opened = true; + moving = true; +} + +void Popup::close() +{ + opened = false; + moving = true; +} + +//////////////////////////////////////////////////////////////////////////////// + +class DSBarInfo : public DBaseStatusBar +{ + DECLARE_CLASS(DSBarInfo, DBaseStatusBar) +public: + DSBarInfo (SBarInfo *script=NULL) : DBaseStatusBar(script->height), + ammo1(NULL), ammo2(NULL), ammocount1(0), ammocount2(0), armor(NULL), + pendingPopup(POP_None), currentPopup(POP_None), lastHud(0), + lastInventoryBar(NULL), lastPopup(NULL) + { + this->script = script; + + static const char *InventoryBarLumps[] = + { + "ARTIBOX", "SELECTBO", "INVCURS", "INVGEML1", + "INVGEML2", "INVGEMR1", "INVGEMR2", + "USEARTIA", "USEARTIB", "USEARTIC", "USEARTID", + }; + TArray patchnames; + patchnames.Resize(script->Images.Size()+10); + unsigned int i = 0; + for(i = 0;i < script->Images.Size();i++) + { + patchnames[i] = script->Images[i]; + } + for(i = 0;i < 10;i++) + { + patchnames[i+script->Images.Size()] = InventoryBarLumps[i]; + } + for (i = 0;i < numskins;i++) + { + AddFaceToImageCollection (&skins[i], &Images); + } + invBarOffset = script->Images.Size(); + Images.Init(&patchnames[0], patchnames.Size()); + } + + ~DSBarInfo () + { + Images.Uninit(); + } + + void Draw (EHudState state) + { + DBaseStatusBar::Draw(state); + int hud = STBAR_NORMAL; + if(state == HUD_StatusBar) + { + if(script->completeBorder) //Fill the statusbar with the border before we draw. + { + FTexture *b = TexMan[gameinfo.border->b]; + R_DrawBorder(viewwindowx, viewwindowy + viewheight + b->GetHeight(), viewwindowx + viewwidth, SCREENHEIGHT); + if(screenblocks == 10) + screen->FlatFill(viewwindowx, viewwindowy + viewheight, viewwindowx + viewwidth, viewwindowy + viewheight + b->GetHeight(), b, true); + } + if(script->automapbar && automapactive) + { + hud = STBAR_AUTOMAP; + } + else + { + hud = STBAR_NORMAL; + } + } + else if(state == HUD_Fullscreen) + { + hud = STBAR_FULLSCREEN; + } + else + { + hud = STBAR_NONE; + } + bool oldhud_scale = hud_scale; + if(script->huds[hud]->ForceScaled()) //scale the statusbar + { + SetScaled(true, true); + setsizeneeded = true; + if(script->huds[hud]->FullScreenOffsets()) + hud_scale = true; + } + + //prepare ammo counts + GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2); + armor = CPlayer->mo->FindInventory(); + if(hud != lastHud) + script->huds[hud]->Tick(NULL, this, true); + script->huds[hud]->Draw(NULL, this, 0, 0, FRACUNIT); + lastHud = hud; + if(CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR) && (state == HUD_StatusBar || state == HUD_Fullscreen)) + { + SBarInfoMainBlock *inventoryBar = state == HUD_StatusBar ? script->huds[STBAR_INVENTORY] : script->huds[STBAR_INVENTORYFULLSCREEN]; + if(inventoryBar != lastInventoryBar) + inventoryBar->Tick(NULL, this, true); + + // No overlay? Lets cancel it. + if(inventoryBar->NumCommands() == 0) + CPlayer->inventorytics = 0; + else + inventoryBar->Draw(NULL, this, 0, 0, FRACUNIT); + } + if(currentPopup != POP_None) + { + int popbar = 0; + if(currentPopup == POP_Log) + popbar = STBAR_POPUPLOG; + else if(currentPopup == POP_Keys) + popbar = STBAR_POPUPKEYS; + else if(currentPopup == POP_Status) + popbar = STBAR_POPUPSTATUS; + if(script->huds[popbar] != lastPopup) + { + lastPopup = script->huds[popbar]; + lastPopup->Tick(NULL, this, true); + } + + script->huds[popbar]->Draw(NULL, this, script->popups[currentPopup-1].getXOffset(), script->popups[currentPopup-1].getYOffset(), script->popups[currentPopup-1].getAlpha()); + } + else + lastPopup = NULL; + if(script->huds[hud]->ForceScaled() && script->huds[hud]->FullScreenOffsets()) + hud_scale = oldhud_scale; + } + + void NewGame () + { + if (CPlayer != NULL) + { + AttachToPlayer (CPlayer); + } + } + + void SetMugShotState (const char *state_name, bool wait_till_done, bool reset) + { + script->MugShot.SetState(state_name, wait_till_done, reset); + } + + void Tick () + { + DBaseStatusBar::Tick(); + + script->MugShot.Tick(CPlayer); + if(currentPopup != POP_None) + { + script->popups[currentPopup-1].tick(); + if(script->popups[currentPopup-1].opened == false && script->popups[currentPopup-1].isDoneMoving()) + { + currentPopup = pendingPopup; + if(currentPopup != POP_None) + script->popups[currentPopup-1].open(); + } + + lastPopup->Tick(NULL, this, false); + } + + script->huds[lastHud]->Tick(NULL, this, false); + if(lastInventoryBar != NULL && CPlayer->inventorytics > 0) + lastInventoryBar->Tick(NULL, this, false); + } + + void ReceivedWeapon(AWeapon *weapon) + { + script->MugShot.Grin(); + } + + // void DSBarInfo::FlashItem(const PClass *itemtype) - Is defined with CommandDrawSelectedInventory + void FlashItem(const PClass *itemtype); + + void ShowPop(int popnum) + { + DBaseStatusBar::ShowPop(popnum); + if(popnum != currentPopup) + { + pendingPopup = popnum; + } + else + pendingPopup = POP_None; + if(currentPopup != POP_None) + script->popups[currentPopup-1].close(); + else + { + currentPopup = pendingPopup; + pendingPopup = POP_None; + if(currentPopup != POP_None) + script->popups[currentPopup-1].open(); + } + } + + //draws an image with the specified flags + void DrawGraphic(FTexture* texture, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, bool translate=false, bool dim=false, int offsetflags=0, bool alphaMap=false, int forceWidth=-1, int forceHeight=-1, fixed_t cx=0, fixed_t cy=0, fixed_t cr=0, fixed_t cb=0, bool clearDontDraw=false) const + { + if (texture == NULL) + return; + + if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER) + { + x -= (texture->GetScaledWidth()/2)-texture->LeftOffset; + y -= (texture->GetScaledHeight()/2)-texture->TopOffset; + } + + x += xOffset; + y += yOffset; + int w, h; + if(!fullScreenOffsets) + { + fixed_t tmp = 0; + // I'll handle the conversion from fixed to int myself for more control + fixed_t fx = (x + ST_X).Coordinate() << FRACBITS; + fixed_t fy = (y + ST_Y).Coordinate() << FRACBITS; + fixed_t fw = (forceWidth <= -1 ? texture->GetScaledWidth() : forceWidth) << FRACBITS; + fixed_t fh = (forceHeight <= -1 ? texture->GetScaledHeight() : forceHeight) << FRACBITS; + fixed_t fcx = cx == 0 ? 0 : fx + cx - (texture->GetScaledLeftOffset() << FRACBITS); + fixed_t fcy = cy == 0 ? 0 : fy + cy - (texture->GetScaledTopOffset() << FRACBITS); + fixed_t fcr = fx + fw - cr; + fixed_t fcb = fy + fh - cb; + if(Scaled) + { + if(cx != 0 || cy != 0) + screen->VirtualToRealCoordsFixed(fcx, fcy, tmp, tmp, 320, 200, true); + if(cr != 0 || cb != 0 || clearDontDraw) + screen->VirtualToRealCoordsFixed(fcr, fcb, tmp, tmp, 320, 200, true); + screen->VirtualToRealCoordsFixed(fx, fy, fw, fh, 320, 200, true); + } + // Round to nearest + w = (fw + (FRACUNIT>>1)) >> FRACBITS; + h = (fh + (FRACUNIT>>1)) >> FRACBITS; + cr = cr != 0 ? fcr >> FRACBITS : INT_MAX; + cb = cb != 0 ? fcb >> FRACBITS : INT_MAX; + if(clearDontDraw) + screen->Clear(MAX(fx, fcx)>>FRACBITS, MAX(fy, fcy)>>FRACBITS, fcr>>FRACBITS, fcb>>FRACBITS, GPalette.BlackIndex, 0); + else + { + if(alphaMap) + { + screen->DrawTexture(texture, (fx >> FRACBITS), (fy >> FRACBITS), + DTA_DestWidth, w, + DTA_DestHeight, h, + DTA_ClipLeft, fcx>>FRACBITS, + DTA_ClipTop, fcy>>FRACBITS, + DTA_ClipRight, cr, + DTA_ClipBottom, cb, + DTA_Translation, translate ? GetTranslation() : 0, + DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, + DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, + DTA_Alpha, alpha, + DTA_AlphaChannel, alphaMap, + DTA_FillColor, 0, + TAG_DONE); + } + else + { + screen->DrawTexture(texture, (fx >> FRACBITS), (fy >> FRACBITS), + DTA_DestWidth, w, + DTA_DestHeight, h, + DTA_ClipLeft, fcx>>FRACBITS, + DTA_ClipTop, fcy>>FRACBITS, + DTA_ClipRight, cr, + DTA_ClipBottom, cb, + DTA_Translation, translate ? GetTranslation() : 0, + DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, + DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, + DTA_Alpha, alpha, + TAG_DONE); + } + } + } + else + { + int rx, ry, rcx=0, rcy=0, rcr=INT_MAX, rcb=INT_MAX; + ADJUST_RELCENTER(x,y,rx,ry) + + w = (forceWidth <= -1 ? texture->GetScaledWidth() : forceWidth); + h = (forceHeight <= -1 ? texture->GetScaledHeight() : forceHeight); + if(vid_fps && rx < 0 && ry >= 0) + ry += 10; + + // Check for clipping + if(cx != 0 || cy != 0 || cr != 0 || cb != 0) + { + rcx = cx == 0 ? 0 : rx+(cx>>FRACBITS); + rcy = cy == 0 ? 0 : ry+(cy>>FRACBITS); + rcr = cr == 0 ? INT_MAX : rx+w-(cr>>FRACBITS); + rcb = cb == 0 ? INT_MAX : ry+h-(cb>>FRACBITS); + // Fix the clipping for fullscreenoffsets. + if(ry < 0) + { + if(rcy != 0) + rcy = hud_scale ? SCREENHEIGHT + (rcy*CleanYfac) : SCREENHEIGHT + rcy; + if(rcb != INT_MAX) + rcb = hud_scale ? SCREENHEIGHT + (rcb*CleanYfac) : SCREENHEIGHT + rcb; + } + else if(hud_scale) + { + rcy *= CleanYfac; + if(rcb != INT_MAX) + rcb *= CleanYfac; + } + if(rx < 0) + { + if(rcx != 0) + rcx = hud_scale ? SCREENWIDTH + (rcx*CleanXfac) : SCREENWIDTH + rcx; + if(rcr != INT_MAX) + rcr = hud_scale ? SCREENWIDTH + (rcr*CleanXfac) : SCREENWIDTH + rcr; + } + else if(hud_scale) + { + rcx *= CleanXfac; + if(rcr != INT_MAX) + rcr *= CleanXfac; + } + } + + if(clearDontDraw) + { + screen->Clear(rcx, rcy, MIN(rcr, w*(hud_scale ? CleanXfac : 1)), MIN(rcb, h*(hud_scale ? CleanYfac : 1)), GPalette.BlackIndex, 0); + } + else + { + if(alphaMap) + { + screen->DrawTexture(texture, rx, ry, + DTA_DestWidth, w, + DTA_DestHeight, h, + DTA_ClipLeft, rcx, + DTA_ClipTop, rcy, + DTA_ClipRight, rcr, + DTA_ClipBottom, rcb, + DTA_Translation, translate ? GetTranslation() : 0, + DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, + DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, + DTA_HUDRules, HUD_Normal, + DTA_Alpha, alpha, + DTA_AlphaChannel, alphaMap, + DTA_FillColor, 0, + TAG_DONE); + } + else + { + screen->DrawTexture(texture, rx, ry, + DTA_DestWidth, w, + DTA_DestHeight, h, + DTA_ClipLeft, rcx, + DTA_ClipTop, rcy, + DTA_ClipRight, rcr, + DTA_ClipBottom, rcb, + DTA_Translation, translate ? GetTranslation() : 0, + DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, + DTA_CenterBottomOffset, (offsetflags & SBarInfoCommand::CENTER_BOTTOM) == SBarInfoCommand::CENTER_BOTTOM, + DTA_HUDRules, HUD_Normal, + DTA_Alpha, alpha, + TAG_DONE); + } + } + } + } + + void DrawString(FFont *font, const char* str, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing=0, bool drawshadow=false) const + { + x += spacing; + int ax = *x; + int ay = *y; + if(fullScreenOffsets) + { + ADJUST_RELCENTER(x,y,ax,ay) + } + while(*str != '\0') + { + if(*str == ' ') + { + ax += font->GetSpaceWidth(); + str++; + continue; + } + int width; + if(script->spacingCharacter == '\0') //No monospace? + width = font->GetCharWidth((int) *str); + else + width = font->GetCharWidth((int) script->spacingCharacter); + FTexture* character = font->GetChar((int) *str, &width); + if(character == NULL) //missing character. + { + str++; + continue; + } + if(script->spacingCharacter == '\0') //If we are monospaced lets use the offset + ax += (character->LeftOffset+1); //ignore x offsets since we adapt to character size + + int rx, ry, rw, rh; + rx = ax + xOffset; + ry = ay + yOffset; + rw = character->GetScaledWidth(); + rh = character->GetScaledHeight(); + if(!fullScreenOffsets) + { + rx += ST_X; + ry += ST_Y; + if(Scaled) + screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true); + } + else + { + if(vid_fps && ax < 0 && ay >= 0) + ry += 10; + } + if(drawshadow) + { + int salpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) HR_SHADOW / (double) FRACUNIT) * FRACUNIT); + if(!fullScreenOffsets) + { + screen->DrawTexture(character, rx+2, ry+2, + DTA_DestWidth, rw, + DTA_DestHeight, rh, + DTA_Alpha, salpha, + DTA_FillColor, 0, + TAG_DONE); + } + else + { + screen->DrawTexture(character, rx+2, ry+2, + DTA_DestWidth, rw, + DTA_DestHeight, rh, + DTA_Alpha, salpha, + DTA_HUDRules, HUD_Normal, + DTA_FillColor, 0, + TAG_DONE); + } + } + if(!fullScreenOffsets) + { + screen->DrawTexture(character, rx, ry, + DTA_DestWidth, rw, + DTA_DestHeight, rh, + DTA_Translation, font->GetColorTranslation(translation), + DTA_Alpha, alpha, + TAG_DONE); + } + else + { + screen->DrawTexture(character, rx, ry, + DTA_DestWidth, rw, + DTA_DestHeight, rh, + DTA_Translation, font->GetColorTranslation(translation), + DTA_Alpha, alpha, + DTA_HUDRules, HUD_Normal, + TAG_DONE); + } + if(script->spacingCharacter == '\0') + ax += width + spacing - (character->LeftOffset+1); + else //width gets changed at the call to GetChar() + ax += font->GetCharWidth((int) script->spacingCharacter) + spacing; + str++; + } + } + + FRemapTable* GetTranslation() const + { + if(gameinfo.gametype & GAME_Raven) + return translationtables[TRANSLATION_PlayersExtra][int(CPlayer - players)]; + return translationtables[TRANSLATION_Players][int(CPlayer - players)]; + } + + AAmmo *ammo1, *ammo2; + int ammocount1, ammocount2; + ABasicArmor *armor; + FImageCollection Images; + unsigned int invBarOffset; + +private: + SBarInfo *script; + int pendingPopup; + int currentPopup; + int lastHud; + SBarInfoMainBlock *lastInventoryBar; + SBarInfoMainBlock *lastPopup; +}; + +IMPLEMENT_CLASS(DSBarInfo); + +DBaseStatusBar *CreateCustomStatusBar (int script) +{ + if(SBarInfoScript[script] == NULL) + I_FatalError("Tried to create a status bar with no script!"); + return new DSBarInfo(SBarInfoScript[script]); +} + +#include "sbarinfo_commands.cpp" diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index ef36c50c5d..b10eb440bd 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -37,57 +37,24 @@ #define __SBarInfo_SBAR_H__ #include "tarray.h" -#include "v_collection.h" #define NUMHUDS 9 #define NUMPOPUPS 3 -class FBarTexture; class FScanner; -/** - * This class is used to help prevent errors that may occur from adding or - * subtracting from coordinates. - * - * In order to provide the maximum flexibility, coordinates are packed into - * an int with one bit reserved for relCenter. - */ -class SBarInfoCoordinate -{ - public: - SBarInfoCoordinate &Add(int add); - int Coordinate() const { return value; } - bool RelCenter() const { return relCenter; } - void Set(int coord, bool center) { value = coord; relCenter = center; } - void SetCoord(int coord) { value = coord; } - void SetRelCenter(bool center) { relCenter = center; } - - int operator* () const { return Coordinate(); } - SBarInfoCoordinate operator+ (int add) const { return SBarInfoCoordinate(*this).Add(add); } - SBarInfoCoordinate operator+ (const SBarInfoCoordinate &other) const { return SBarInfoCoordinate(*this).Add(other.Coordinate()); } - SBarInfoCoordinate operator- (int sub) const { return SBarInfoCoordinate(*this).Add(-sub); } - SBarInfoCoordinate operator- (const SBarInfoCoordinate &other) const { return SBarInfoCoordinate(*this).Add(-other.Coordinate()); } - void operator+= (int add) { Add(add); } - void operator-= (int sub) { Add(-sub); } - - protected: - unsigned relCenter:1; - int value:31; -}; - -struct SBarInfoCommand; //we need to be able to use this before it is defined. -struct MugShotState; +class SBarInfoMainBlock; //Popups! -enum PopupTransition -{ - TRANSITION_NONE, - TRANSITION_SLIDEINBOTTOM, - TRANSITION_FADE, -}; - struct Popup { + enum PopupTransition + { + TRANSITION_NONE, + TRANSITION_SLIDEINBOTTOM, + TRANSITION_FADE, + }; + PopupTransition transition; bool opened; bool moving; @@ -110,54 +77,10 @@ struct Popup int getAlpha(int maxAlpha=FRACUNIT); }; -//SBarInfo -struct SBarInfoBlock -{ - TArray commands; - bool forceScaled; - bool fullScreenOffsets; - int alpha; - - SBarInfoBlock(); -}; - -struct SBarInfoCommand -{ - SBarInfoCommand(); - ~SBarInfoCommand(); - void setString(FScanner &sc, const char* source, int strnum, int maxlength=-1, bool exact=false); - - int type; - int special; - union - { - int special2; - SBarInfoCoordinate sbcoord2; - }; - union - { - int special3; - SBarInfoCoordinate sbcoord3; - }; - int special4; - int flags; - SBarInfoCoordinate x; - SBarInfoCoordinate y; - int value; - int image_index; - FTextureID sprite_index; - FString string[2]; - FFont *font; - EColorRange translation; - EColorRange translation2; - EColorRange translation3; - SBarInfoBlock subBlock; //for type SBarInfo_CMD_GAMEMODE -}; - struct SBarInfo { TArray Images; - SBarInfoBlock huds[NUMHUDS]; + SBarInfoMainBlock *huds[NUMHUDS]; Popup popups[NUMPOPUPS]; bool automapbar; bool interpolateHealth; @@ -169,16 +92,13 @@ struct SBarInfo int armorInterpolationSpeed; int height; int gameType; + FMugShot MugShot; int GetGameType() { return gameType; } void ParseSBarInfo(int lump); - void ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block); void ParseMugShotBlock(FScanner &sc, FMugShotState &state); - void getCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y); //retrieves the next two arguments as x and y. - int getSignedInteger(FScanner &sc); //returns a signed integer. int newImage(const char* patchname); void Init(); - EColorRange GetTranslation(FScanner &sc, const char* translation); SBarInfo(); SBarInfo(int lumpnum); ~SBarInfo(); @@ -190,243 +110,4 @@ struct SBarInfo #define SCRIPT_DEFAULT 1 extern SBarInfo *SBarInfoScript[2]; -// Enums used between the parser and the display -enum //gametype flags -{ - GAMETYPE_SINGLEPLAYER = 1, - GAMETYPE_COOPERATIVE = 2, - GAMETYPE_DEATHMATCH = 4, - GAMETYPE_TEAMGAME = 8, -}; - -enum //drawimage flags -{ - DRAWIMAGE_PLAYERICON = 0x1, - DRAWIMAGE_AMMO1 = 0x2, - DRAWIMAGE_AMMO2 = 0x4, - DRAWIMAGE_INVENTORYICON = 0x8, - DRAWIMAGE_TRANSLATABLE = 0x10, - DRAWIMAGE_WEAPONSLOT = 0x20, - DRAWIMAGE_SWITCHABLE_AND = 0x40, - DRAWIMAGE_INVULNERABILITY = 0x80, - DRAWIMAGE_OFFSET_CENTER = 0x100, - DRAWIMAGE_OFFSET_CENTERBOTTOM = 0x200, - DRAWIMAGE_ARMOR = 0x800, - DRAWIMAGE_WEAPONICON = 0x1000, - DRAWIMAGE_SIGIL = 0x2000, - DRAWIMAGE_KEYSLOT = 0x4000, - DRAWIMAGE_HEXENARMOR = 0x8000, - - DRAWIMAGE_OFFSET = DRAWIMAGE_OFFSET_CENTER|DRAWIMAGE_OFFSET_CENTERBOTTOM, -}; - -enum //drawnumber flags -{ - DRAWNUMBER_HEALTH = 0x1, - DRAWNUMBER_ARMOR = 0x2, - DRAWNUMBER_AMMO1 = 0x4, - DRAWNUMBER_AMMO2 = 0x8, - DRAWNUMBER_AMMO = 0x10, - DRAWNUMBER_AMMOCAPACITY = 0x20, - DRAWNUMBER_FRAGS = 0x40, - DRAWNUMBER_INVENTORY = 0x80, - DRAWNUMBER_KILLS = 0x100, - DRAWNUMBER_MONSTERS = 0x200, - DRAWNUMBER_ITEMS = 0x400, - DRAWNUMBER_TOTALITEMS = 0x800, - DRAWNUMBER_SECRETS = 0x1000, - DRAWNUMBER_TOTALSECRETS = 0x2000, - DRAWNUMBER_ARMORCLASS = 0x4000, - DRAWNUMBER_GLOBALVAR = 0x8000, - DRAWNUMBER_GLOBALARRAY = 0x10000, - DRAWNUMBER_FILLZEROS = 0x20000, - DRAWNUMBER_WHENNOTZERO = 0x40000, - DRAWNUMBER_POWERUPTIME = 0x80000, - DRAWNUMBER_DRAWSHADOW = 0x100000, - DRAWNUMBER_AIRTIME = 0x200000, -}; - -enum //drawbar flags (will go into special2) -{ - DRAWBAR_HORIZONTAL = 1, - DRAWBAR_REVERSE = 2, - DRAWBAR_COMPAREDEFAULTS = 4, -}; - -enum //drawselectedinventory flags -{ - DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY = 0x1, - DRAWSELECTEDINVENTORY_ARTIFLASH = 0x2, - DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER = 0x4, - DRAWSELECTEDINVENTORY_CENTER = 0x8, - DRAWSELECTEDINVENTORY_CENTERBOTTOM = 0x10, - DRAWSELECTEDINVENTORY_DRAWSHADOW = 0x20, -}; - -enum //drawinventorybar flags -{ - DRAWINVENTORYBAR_ALWAYSSHOW = 0x1, - DRAWINVENTORYBAR_NOARTIBOX = 0x2, - DRAWINVENTORYBAR_NOARROWS = 0x4, - DRAWINVENTORYBAR_ALWAYSSHOWCOUNTER = 0x8, - DRAWINVENTORYBAR_TRANSLUCENT = 0x10, - DRAWINVENTORYBAR_VERTICAL = 0x20, -}; - -enum //drawgem flags -{ - DRAWGEM_WIGGLE = 1, - DRAWGEM_TRANSLATABLE = 2, - DRAWGEM_ARMOR = 4, - DRAWGEM_REVERSE = 8, -}; - -enum //drawshader flags -{ - DRAWSHADER_VERTICAL = 1, - DRAWSHADER_REVERSE = 2, -}; - -enum //drawmugshot flags -{ - DRAWMUGSHOT_XDEATHFACE = 0x1, - DRAWMUGSHOT_ANIMATEDGODMODE = 0x2, - DRAWMUGSHOT_DISABLEGRIN = 0x4, - DRAWMUGSHOT_DISABLEOUCH = 0x8, - DRAWMUGSHOT_DISABLEPAIN = 0x10, - DRAWMUGSHOT_DISABLERAMPAGE = 0x20, -}; - -enum //drawkeybar flags -{ - DRAWKEYBAR_VERTICAL = 0x1, - DRAWKEYBAR_REVERSEROWS = 0x2, -}; - -enum //event flags -{ - SBARINFOEVENT_NOT = 1, - SBARINFOEVENT_OR = 2, - SBARINFOEVENT_AND = 4, -}; - -enum //aspect ratios -{ - ASPECTRATIO_4_3 = 0, - ASPECTRATIO_16_9 = 1, - ASPECTRATIO_16_10 = 2, - ASPECTRATIO_5_4 = 4, -}; - -enum //Key words -{ - SBARINFO_BASE, - SBARINFO_HEIGHT, - SBARINFO_INTERPOLATEHEALTH, - SBARINFO_INTERPOLATEARMOR, - SBARINFO_COMPLETEBORDER, - SBARINFO_MONOSPACEFONTS, - SBARINFO_LOWERHEALTHCAP, - SBARINFO_STATUSBAR, - SBARINFO_MUGSHOT, - SBARINFO_CREATEPOPUP, -}; - -enum //Bar types -{ - STBAR_NONE, - STBAR_FULLSCREEN, - STBAR_NORMAL, - STBAR_AUTOMAP, - STBAR_INVENTORY, - STBAR_INVENTORYFULLSCREEN, - STBAR_POPUPLOG, - STBAR_POPUPKEYS, - STBAR_POPUPSTATUS, -}; - -enum //Bar key words -{ - SBARINFO_DRAWIMAGE, - SBARINFO_DRAWNUMBER, - SBARINFO_DRAWSWITCHABLEIMAGE, - SBARINFO_DRAWMUGSHOT, - SBARINFO_DRAWSELECTEDINVENTORY, - SBARINFO_DRAWINVENTORYBAR, - SBARINFO_DRAWBAR, - SBARINFO_DRAWGEM, - SBARINFO_DRAWSHADER, - SBARINFO_DRAWSTRING, - SBARINFO_DRAWKEYBAR, - SBARINFO_GAMEMODE, - SBARINFO_PLAYERCLASS, - SBARINFO_ASPECTRATIO, - SBARINFO_ISSELECTED, - SBARINFO_USESAMMO, - SBARINFO_USESSECONDARYAMMO, - SBARINFO_HASWEAPONPIECE, - SBARINFO_INVENTORYBARNOTVISIBLE, - SBARINFO_WEAPONAMMO, - SBARINFO_ININVENTORY, -}; - -//All this so I can change the mugshot state in ACS... -class FBarShader : public FTexture -{ -public: - FBarShader(bool vertical, bool reverse); - const BYTE *GetColumn(unsigned int column, const Span **spans_out); - const BYTE *GetPixels(); - void Unload(); -private: - BYTE Pixels[512]; - Span DummySpan[2]; -}; - -class DSBarInfo : public DBaseStatusBar -{ - DECLARE_CLASS(DSBarInfo, DBaseStatusBar) -public: - DSBarInfo(SBarInfo *script=NULL); - ~DSBarInfo(); - void Draw(EHudState state); - void NewGame(); - void AttachToPlayer(player_t *player); - void Tick(); - void ReceivedWeapon (AWeapon *weapon); - void FlashItem(const PClass *itemtype); - void ShowPop(int popnum); - void SetMugShotState(const char* stateName, bool waitTillDone=false, bool reset=false); -private: - void doCommands(SBarInfoBlock &block, int xOffset=0, int yOffset=0, int alpha=FRACUNIT); - void DrawGraphic(FTexture* texture, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, bool translate=false, bool dim=false, int offsetflags=0); - void DrawString(const char* str, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing=0, bool drawshadow=false); - void DrawNumber(int num, int len, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing=0, bool fillzeros=false, bool drawshadow=false); - void DrawFace(const char *defaultFace, int accuracy, int stateflags, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets); - int updateState(bool xdth, bool animatedgodmode); - void DrawInventoryBar(int type, int num, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, bool alwaysshow, - SBarInfoCoordinate counterx, SBarInfoCoordinate countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter, int bgalpha, bool vertical); - void DrawGem(FTexture* chain, FTexture* gem, int value, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, int padleft, int padright, int chainsize, - bool wiggle, bool translate); - FRemapTable* getTranslation(); - - SBarInfo *script; - FImageCollection Images; - FPlayerSkin *oldSkin; - FFont *drawingFont; - int oldHealth; - int oldArmor; - int mugshotHealth; - int chainWiggle; - int artiflash; - int pendingPopup; - int currentPopup; - unsigned int invBarOffset; - FBarShader shader_horz_normal; - 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_commands.cpp b/src/g_shared/sbarinfo_commands.cpp new file mode 100644 index 0000000000..bd1bd14784 --- /dev/null +++ b/src/g_shared/sbarinfo_commands.cpp @@ -0,0 +1,2574 @@ +/* +** sbarinfo_commands.cpp +** +** This is an extension to the sbarinfo.cpp file. This contains all of the +** commands. +**--------------------------------------------------------------------------- +** 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. +**--------------------------------------------------------------------------- +** +*/ + +// [BL] Do note that this file is included by sbarinfo.cpp. This is done so +// that all the code can be more or less in one spot. +// +// At the bottom of this file is a function that belongs to +// SBarInfoCommandFlowControl which creates the instances of the following +// classes. +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawImage : public SBarInfoCommand +{ + public: + CommandDrawImage(SBarInfo *script) : SBarInfoCommand(script), + translatable(false), type(NORMAL_IMAGE), image(-1), offset(static_cast (TOP|LEFT)), + texture(NULL), alpha(FRACUNIT) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if(texture == NULL) + return; + + statusBar->DrawGraphic(texture, imgx, imgy, block->XOffset(), block->YOffset(), alpha, block->FullScreenOffsets(), + translatable, false, offset); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + bool getImage = true; + if(sc.CheckToken(TK_Identifier)) + { + getImage = false; + if(sc.Compare("playericon")) + type = PLAYERICON; + else if(sc.Compare("ammoicon1")) + type = AMMO1; + else if(sc.Compare("ammoicon2")) + type = AMMO2; + else if(sc.Compare("armoricon")) + type = ARMOR; + else if(sc.Compare("weaponicon")) + type = WEAPONICON; + else if(sc.Compare("sigil")) + type = SIGIL; + else if(sc.Compare("hexenarmor")) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("armor")) + type = HEXENARMOR_ARMOR; + else if(sc.Compare("shield")) + type = HEXENARMOR_SHIELD; + else if(sc.Compare("helm")) + type = HEXENARMOR_HELM; + else if(sc.Compare("amulet")) + type = HEXENARMOR_AMULET; + else + sc.ScriptError("Unkown armor type: '%s'", sc.String); + sc.MustGetToken(','); + getImage = true; + } + else if(sc.Compare("translatable")) + { + translatable = true; + getImage = true; + } + else + { + type = INVENTORYICON; + const PClass* item = PClass::FindClass(sc.String); + if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + { + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + sprite = ((AInventory *)GetDefaultByType(item))->Icon; + image = -1; + } + } + if(getImage) + { + sc.MustGetToken(TK_StringConst); + image = script->newImage(sc.String); + sprite.SetInvalid(); + } + sc.MustGetToken(','); + GetCoordinates(sc, fullScreenOffsets, imgx, imgy); + if(sc.CheckToken(',')) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("center")) + offset = CENTER; + else if(sc.Compare("centerbottom")) + offset = static_cast (HMIDDLE|BOTTOM); + else + sc.ScriptError("'%s' is not a valid alignment.", sc.String); + } + sc.MustGetToken(';'); + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + texture = NULL; + alpha = block->Alpha(); + if(type == PLAYERICON) + texture = TexMan[statusBar->CPlayer->mo->ScoreIcon]; + else if(type == AMMO1) + { + if(statusBar->ammo1 != NULL) + texture = TexMan[statusBar->ammo1->Icon]; + } + else if(type == AMMO2) + { + if(statusBar->ammo2 != NULL) + texture = TexMan[statusBar->ammo2->Icon]; + } + else if(type == ARMOR) + { + if(statusBar->armor != NULL && statusBar->armor->Amount != 0) + texture = TexMan(statusBar->armor->Icon); + } + else if(type == WEAPONICON) + { + AWeapon *weapon = statusBar->CPlayer->ReadyWeapon; + if(weapon != NULL && weapon->Icon.isValid()) + { + texture = TexMan[weapon->Icon]; + } + } + else if(type == SIGIL) + { + AInventory *item = statusBar->CPlayer->mo->FindInventory(); + if (item != NULL) + texture = TexMan[item->Icon]; + } + else if(type == HEXENARMOR_ARMOR || type == HEXENARMOR_SHIELD || type == HEXENARMOR_AMULET || type == HEXENARMOR_ARMOR) + { + int armorType = type - HEXENARMOR_ARMOR; + + AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory(); + if (harmor != NULL) + { + if (harmor->Slots[armorType] > 0 && harmor->SlotsIncrement[armorType] > 0) + { + //combine the alpha values + alpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) MIN (OPAQUE, Scale(harmor->Slots[armorType], OPAQUE, harmor->SlotsIncrement[armorType])) / (double) OPAQUE) * FRACUNIT); + texture = statusBar->Images[image]; + } + else + return; + } + } + else if(type == INVENTORYICON) + texture = TexMan[sprite]; + else if(type == SELECTEDINVENTORYICON && statusBar->CPlayer->mo->InvSel != NULL) + texture = TexMan(statusBar->CPlayer->mo->InvSel->Icon); + else if(image >= 0) + texture = statusBar->Images[image]; + } + protected: + enum ImageType + { + PLAYERICON, + AMMO1, + AMMO2, + ARMOR, + WEAPONICON, + SIGIL, + HEXENARMOR_ARMOR, + HEXENARMOR_SHIELD, + HEXENARMOR_HELM, + HEXENARMOR_AMULET, + INVENTORYICON, + WEAPONSLOT, + SELECTEDINVENTORYICON, + + NORMAL_IMAGE + }; + + bool translatable; + ImageType type; + int image; + FTextureID sprite; + // I'm using imgx/imgy here so that I can inherit drawimage with drawnumber for some commands. + SBarInfoCoordinate imgx; + SBarInfoCoordinate imgy; + Offset offset; + + FTexture *texture; + int alpha; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawSwitchableImage : public CommandDrawImage +{ + private: + enum Operator + { + EQUAL, + LESS, + GREATER, + LESSOREQUAL, + GREATEROREQUAL, + NOTEQUAL + }; + + static void GetOperation(FScanner &sc, Operator &op, int &value) + { + if(sc.CheckToken(TK_Eq)) + op = EQUAL; + else if(sc.CheckToken('<')) + op = LESS; + else if(sc.CheckToken('>')) + op = GREATER; + else if(sc.CheckToken(TK_Leq)) + op = LESSOREQUAL; + else if(sc.CheckToken(TK_Geq)) + op = GREATEROREQUAL; + else if(sc.CheckToken(TK_Neq)) + op = NOTEQUAL; + else + { // Default + op = GREATER; + value = 0; + return; + } + sc.MustGetToken(TK_IntConst); + value = sc.Number; + } + static bool EvaluateOperation(const Operator &op, const int &value, const int &compare) + { + switch(op) + { + case EQUAL: + return compare == value; + case LESS: + return compare < value; + case GREATER: + default: + return compare > value; + case LESSOREQUAL: + return compare <= value; + case GREATEROREQUAL: + return compare >= value; + case NOTEQUAL: + return compare != value; + } + } + + public: + CommandDrawSwitchableImage(SBarInfo *script) : CommandDrawImage(script), + condition(INVENTORY), conditionAnd(false) + { + conditionalImage[0] = conditionalImage[1] = conditionalImage[2] = -1; + conditionalValue[0] = conditionalValue[1] = 0; + armorType[0] = armorType[1] = 0; + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("weaponslot")) + { + condition = WEAPONSLOT; + sc.MustGetToken(TK_IntConst); + conditionalValue[0] = sc.Number; + } + else if(sc.Compare("invulnerable")) + { + condition = INVULNERABILITY; + } + else if(sc.Compare("keyslot")) + { + condition = KEYSLOT; + sc.MustGetToken(TK_IntConst); + conditionalValue[0] = sc.Number; + } + else if(sc.Compare("armortype")) + { + condition = ARMORTYPE; + sc.MustGetToken(TK_Identifier); + armorType[0] = FName(sc.String).GetIndex(); + GetOperation(sc, conditionalOperator[0], conditionalValue[0]); + } + else + { + inventoryItem[0] = sc.String; + const PClass* item = PClass::FindClass(sc.String); + if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + { + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + GetOperation(sc, conditionalOperator[0], conditionalValue[0]); + } + if(sc.CheckToken(TK_AndAnd) && condition != INVULNERABILITY) + { + conditionAnd = true; + if(condition == KEYSLOT || condition == WEAPONSLOT) + { + sc.MustGetToken(TK_IntConst); + conditionalValue[1] = sc.Number; + } + else if(condition == ARMORTYPE) + { + sc.MustGetToken(TK_Identifier); + armorType[1] = FName(sc.String).GetIndex(); + GetOperation(sc, conditionalOperator[1], conditionalValue[1]); + } + else + { + sc.MustGetToken(TK_Identifier); + inventoryItem[1] = sc.String; + const PClass* item = PClass::FindClass(sc.String); + if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory + { + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + GetOperation(sc, conditionalOperator[1], conditionalValue[1]); + } + } + // [BL] I have word that MSVC++ wants this static_cast ;) Shut up MSVC! + for(unsigned int i = 0;i < static_cast (conditionAnd ? 3 : 1);i++) + { + sc.MustGetToken(','); + sc.MustGetToken(TK_StringConst); + conditionalImage[i] = script->newImage(sc.String); + } + sc.MustGetToken(','); + CommandDrawImage::Parse(sc, fullScreenOffsets); + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + // DrawSwitchable image allows 2 or 4 images to be supplied. + // drawAlt toggles these: + // 1 = first image + // 2 = second image + // 3 = thrid image + // 0 = last image + int drawAlt = 0; + if(condition == WEAPONSLOT) //weaponslots + { + drawAlt = 1; //draw off state until we know we have something. + for (int i = 0; i < statusBar->CPlayer->weapons.Slots[conditionalValue[0]].Size(); i++) + { + const PClass *weap = statusBar->CPlayer->weapons.Slots[conditionalValue[0]].GetWeapon(i); + if(weap == NULL) + { + continue; + } + else if(statusBar->CPlayer->mo->FindInventory(weap) != NULL) + { + drawAlt = 0; + break; + } + } + } + else if(condition == INVULNERABILITY) + { + if(statusBar->CPlayer->cheats&CF_GODMODE) + { + drawAlt = 1; + } + } + else if(condition == KEYSLOT) + { + bool found1 = false; + bool found2 = false; + drawAlt = 1; + + for(AInventory *item = statusBar->CPlayer->mo->Inventory;item != NULL;item = item->Inventory) + { + if(item->IsKindOf(RUNTIME_CLASS(AKey))) + { + int keynum = static_cast(item)->KeyNumber; + + if(keynum == conditionalValue[0]) + found1 = true; + if(conditionAnd && keynum == conditionalValue[1]) // two keys + found2 = true; + } + } + + if(conditionAnd) + { + if(found1 && found2) + drawAlt = 0; + else if(found1) + drawAlt = 2; + else if(found2) + drawAlt = 3; + } + else + { + if(found1) + drawAlt = 0; + } + } + else if(condition == ARMORTYPE) + { + ABasicArmor *armor = (ABasicArmor *) statusBar->CPlayer->mo->FindInventory(NAME_BasicArmor); + if(armor != NULL) + { + bool matches1 = armor->ArmorType.GetIndex() == armorType[0] && EvaluateOperation(conditionalOperator[0], conditionalValue[0], armor->Amount); + bool matches2 = armor->ArmorType.GetIndex() == armorType[1] && EvaluateOperation(conditionalOperator[1], conditionalValue[1], armor->Amount); + + drawAlt = 1; + if(conditionAnd) + { + if(matches1 && matches2) + drawAlt = 0; + else if(matches2) + drawAlt = 3; + else if(matches1) + drawAlt = 2; + } + else if(matches1) + drawAlt = 0; + } + } + else //check the inventory items and draw selected sprite + { + AInventory* item = statusBar->CPlayer->mo->FindInventory(PClass::FindClass(inventoryItem[0])); + if(item == NULL || !EvaluateOperation(conditionalOperator[0], conditionalValue[0], item->Amount)) + drawAlt = 1; + if(conditionAnd) + { + item = statusBar->CPlayer->mo->FindInventory(PClass::FindClass(inventoryItem[1])); + bool secondCondition = item != NULL && EvaluateOperation(conditionalOperator[1], conditionalValue[1], item->Amount); + if((item != NULL && secondCondition) && drawAlt == 0) //both + { + drawAlt = 0; + } + else if((item != NULL && secondCondition) && drawAlt == 1) //2nd + { + drawAlt = 3; + } + else if((item == NULL || !secondCondition) && drawAlt == 0) //1st + { + drawAlt = 2; + } + } + } + if(drawAlt != 0) //draw 'off' image + { + texture = statusBar->Images[conditionalImage[drawAlt-1]]; + return; + } + CommandDrawImage::Tick(block, statusBar, hudChanged); + } + + private: + enum Condition + { + WEAPONSLOT, + INVULNERABILITY, + KEYSLOT, + ARMORTYPE, + + INVENTORY + }; + + Condition condition; + bool conditionAnd; + int conditionalImage[3]; + int conditionalValue[2]; + Operator conditionalOperator[2]; + FString inventoryItem[2]; + int armorType[2]; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawString : public SBarInfoCommand +{ + public: + CommandDrawString(SBarInfo *script) : SBarInfoCommand(script), + shadow(false), spacing(0), font(NULL), translation(CR_UNTRANSLATED) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + statusBar->DrawString(font, str.GetChars(), x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), translation, spacing, shadow); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + font = V_GetFont(sc.String); + if(font == NULL) + sc.ScriptError("Unknown font '%s'.", sc.String); + sc.MustGetToken(','); + translation = GetTranslation(sc); + sc.MustGetToken(','); + sc.MustGetToken(TK_StringConst); + str = sc.String; + sc.MustGetToken(','); + GetCoordinates(sc, fullScreenOffsets, x, y); + if(sc.CheckToken(',')) //spacing + { + sc.MustGetToken(TK_IntConst); + spacing = sc.Number; + } + sc.MustGetToken(';'); + + if(script->spacingCharacter == '\0') + x -= static_cast (font->StringWidth(str)+(spacing * str.Len())); + else //monospaced, so just multiplay the character size + x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); + } + protected: + bool shadow; + int spacing; + FFont *font; + EColorRange translation; + SBarInfoCoordinate x; + SBarInfoCoordinate y; + FString str; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawNumber : public CommandDrawString +{ + public: + CommandDrawNumber(SBarInfo *script) : CommandDrawString(script), + fillZeros(false), whenNotZero(false), interpolationSpeed(0), drawValue(0), + length(3), lowValue(-1), lowTranslation(CR_UNTRANSLATED), highValue(-1), + highTranslation(CR_UNTRANSLATED), value(CONSTANT), valueArgument(0), + inventoryItem(NULL) + { + } + + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_IntConst); + length = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_Identifier); + font = V_GetFont(sc.String); + if(font == NULL) + sc.ScriptError("Unknown font '%s'.", sc.String); + sc.MustGetToken(','); + normalTranslation = GetTranslation(sc); + sc.MustGetToken(','); + if(sc.CheckToken(TK_IntConst)) + { + value = CONSTANT; + valueArgument = sc.Number; + sc.MustGetToken(','); + } + else + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("health")) + value = HEALTH; + else if(sc.Compare("armor")) + value = ARMOR; + else if(sc.Compare("ammo1")) + value = AMMO1; + else if(sc.Compare("ammo2")) + value = AMMO2; + else if(sc.Compare("ammo")) //request the next string to be an ammo type + { + value = AMMO; + sc.MustGetToken(TK_Identifier); + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + { + sc.ScriptError("'%s' is not a type of ammo.", sc.String); + } + } + else if(sc.Compare("ammocapacity")) + { + value = AMMOCAPACITY; + sc.MustGetToken(TK_Identifier); + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + { + sc.ScriptError("'%s' is not a type of ammo.", sc.String); + } + } + else if(sc.Compare("frags")) + value = FRAGS; + else if(sc.Compare("kills")) + value = KILLS; + else if(sc.Compare("monsters")) + value = MONSTERS; + else if(sc.Compare("items")) + value = ITEMS; + else if(sc.Compare("totalitems")) + value = TOTALITEMS; + else if(sc.Compare("secrets")) + value = SECRETS; + else if(sc.Compare("totalsecrets")) + value = TOTALSECRETS; + else if(sc.Compare("armorclass")) + value = ARMORCLASS; + else if(sc.Compare("airtime")) + value = AIRTIME; + else if(sc.Compare("globalvar")) + { + value = GLOBALVAR; + sc.MustGetToken(TK_IntConst); + if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) + sc.ScriptError("Global variable number out of range: %d", sc.Number); + valueArgument = sc.Number; + } + else if(sc.Compare("globalarray")) //acts like variable[playernumber()] + { + value = GLOBALARRAY; + sc.MustGetToken(TK_IntConst); + if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) + sc.ScriptError("Global variable number out of range: %d", sc.Number); + valueArgument = sc.Number; + } + else if(sc.Compare("poweruptime")) + { + value = POWERUPTIME; + sc.MustGetToken(TK_Identifier); + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem)) + { + sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); + } + } + else + { + value = INVENTORY; + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of ammo + { + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + } + sc.MustGetToken(','); + } + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("fillzeros")) + fillZeros = true; + else if(sc.Compare("whennotzero")) + whenNotZero = true; + else if(sc.Compare("drawshadow")) + shadow = true; + else if(sc.Compare("interpolate")) + { + sc.MustGetToken('('); + sc.MustGetToken(TK_IntConst); + interpolationSpeed = sc.Number; + sc.MustGetToken(')'); + } + else + sc.ScriptError("Unknown flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + GetCoordinates(sc, fullScreenOffsets, startX, y); + if(sc.CheckToken(',')) + { + bool needsComma = false; + if(sc.CheckToken(TK_IntConst)) //font spacing + { + spacing = sc.Number; + needsComma = true; + } + if(!needsComma || sc.CheckToken(',')) //2nd coloring for "low-on" value + { + lowTranslation = GetTranslation(sc); + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + lowValue = sc.Number; + if(sc.CheckToken(',')) //3rd coloring for "high-on" value + { + highTranslation = GetTranslation(sc); + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + highValue = sc.Number; + } + } + } + sc.MustGetToken(';'); + + if(value == HEALTH) + interpolationSpeed = script->interpolateHealth ? script->interpolationSpeed : interpolationSpeed; + else if(value == ARMOR) + interpolationSpeed = script->interpolateArmor ? script->armorInterpolationSpeed : interpolationSpeed; + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + int num = valueArgument; + switch(value) + { + case HEALTH: + num = statusBar->CPlayer->mo->health; + if(script->lowerHealthCap && num < 0) //health shouldn't display negatives + num = 0; + if(script->interpolateHealth) + interpolationSpeed = script->interpolationSpeed; + break; + case ARMOR: + num = statusBar->armor != NULL ? statusBar->armor->Amount : 0; + if(script->interpolateArmor) + interpolationSpeed = script->armorInterpolationSpeed; + break; + case AMMO1: + if(statusBar->ammo1 == NULL) //no ammo, do not draw + { + str = ""; + return; + } + num = statusBar->ammocount1; + break; + case AMMO2: + if(statusBar->ammo2 == NULL) //no ammo, do not draw + { + str = ""; + return; + } + num = statusBar->ammocount2; + break; + case AMMO: + { + AInventory* item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + if(item != NULL) + num = item->Amount; + else + num = 0; + break; + } + case AMMOCAPACITY: + { + AInventory* item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + if(item != NULL) + num = item->MaxAmount; + else + num = ((AInventory *)GetDefaultByType(inventoryItem))->MaxAmount; + break; + } + case FRAGS: + num = statusBar->CPlayer->fragcount; + break; + case KILLS: + num = level.killed_monsters; + break; + case MONSTERS: + num = level.total_monsters; + break; + case ITEMS: + num = level.found_items; + break; + case TOTALITEMS: + num = level.total_items; + break; + case SECRETS: + num = level.found_secrets; + break; + case TOTALSECRETS: + num = level.total_secrets; + break; + case ARMORCLASS: + { + AHexenArmor *harmor = statusBar->CPlayer->mo->FindInventory(); + if(harmor != NULL) + { + num = harmor->Slots[0] + harmor->Slots[1] + + harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; + } + //Hexen counts basic armor also so we should too. + if(statusBar->armor != NULL) + { + num += statusBar->armor->SavePercent; + } + num /= (5*FRACUNIT); + break; + } + case GLOBALVAR: + num = ACS_GlobalVars[valueArgument]; + break; + case GLOBALARRAY: + num = ACS_GlobalArrays[valueArgument][consoleplayer]; + break; + case POWERUPTIME: + { + //Get the PowerupType and check to see if the player has any in inventory. + const PClass* powerupType = ((APowerupGiver*) GetDefaultByType(inventoryItem))->PowerupType; + APowerup* powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType); + if(powerup != NULL) + num = powerup->EffectTics / TICRATE + 1; + break; + } + case INVENTORY: + { + AInventory* item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + if(item != NULL) + num = item->Amount; + else + num = 0; + break; + } + case AIRTIME: + { + if(statusBar->CPlayer->mo->waterlevel < 3) + num = level.airsupply/TICRATE; + else + num = clamp((statusBar->CPlayer->air_finished - level.time + (TICRATE-1))/TICRATE, 0, INT_MAX); + break; + } + case SELECTEDINVENTORY: + if(statusBar->CPlayer->mo->InvSel != NULL) + num = statusBar->CPlayer->mo->InvSel->Amount; + break; + default: break; + } + if(interpolationSpeed != 0 && (!hudChanged || level.time == 1)) + { + if(num < drawValue) + drawValue -= clamp((drawValue - num) >> 2, 1, interpolationSpeed); + else if(drawValue < num) + drawValue += clamp((num - drawValue) >> 2, 1, interpolationSpeed); + } + else + drawValue = num; + if(whenNotZero && drawValue == 0) + { + str = ""; + return; + } + + translation = normalTranslation; + if(lowValue != -1 && drawValue <= lowValue) //low + translation = lowTranslation; + else if(highValue != -1 && drawValue >= highValue) //high + translation = highTranslation; + + x = startX; + + // 10^9 is a largest we can hold in a 32-bit int. So if we go any larger we have to toss out the positions limit. + int maxval = length <= 9 ? (int) ceil(pow(10., length))-1 : INT_MAX; + if(!fillZeros || length == 1) + drawValue = clamp(drawValue, -maxval, maxval); + else //The community wanted negatives to take the last digit, but we can only do this if there is room + drawValue = clamp(drawValue, length <= 9 ? (int) -(ceil(pow(10., length-1))-1) : INT_MIN, maxval); + str.Format("%d", drawValue); + if(fillZeros) + { + if(drawValue < 0) //We don't want the negative just yet + str.Format("%d", -drawValue); + while(str.Len() < (unsigned int) length) + { + if(drawValue < 0 && str.Len() == (unsigned int) (length-1)) + str.Insert(0, "-"); + else + str.Insert(0, "0"); + } + } + if(script->spacingCharacter == '\0') + x -= static_cast (font->StringWidth(str)+(spacing * str.Len())); + else //monospaced, so just multiplay the character size + x -= static_cast ((font->GetCharWidth((int) script->spacingCharacter) + spacing) * str.Len()); + } + protected: + enum ValueType + { + HEALTH, + ARMOR, + AMMO1, + AMMO2, + AMMO, + AMMOCAPACITY, + FRAGS, + INVENTORY, + KILLS, + MONSTERS, + ITEMS, + TOTALITEMS, + SECRETS, + TOTALSECRETS, + ARMORCLASS, + GLOBALVAR, + GLOBALARRAY, + POWERUPTIME, + AIRTIME, + SELECTEDINVENTORY, + + CONSTANT + }; + + bool fillZeros; + bool whenNotZero; + + int interpolationSpeed; + int drawValue; + + int length; + int lowValue; + EColorRange lowTranslation; + int highValue; + EColorRange highTranslation; + EColorRange normalTranslation; + ValueType value; + int valueArgument; + const PClass *inventoryItem; + + SBarInfoCoordinate startX; + + friend class CommandDrawInventoryBar; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawMugShot : public SBarInfoCommand +{ + public: + CommandDrawMugShot(SBarInfo *script) : SBarInfoCommand(script), + accuracy(5), stateFlags(FMugShot::STANDARD) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + FTexture *face = script->MugShot.GetFace(statusBar->CPlayer, defaultFace, accuracy, stateFlags); + if (face != NULL) + statusBar->DrawGraphic(face, x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + if(sc.CheckToken(TK_StringConst)) + { + defaultFace = sc.String; + if(defaultFace.Len() > 3) + sc.ScriptError("Default can not be longer than 3 characters."); + sc.MustGetToken(','); + } + sc.MustGetToken(TK_IntConst); //accuracy + if(sc.Number < 1 || sc.Number > 9) + sc.ScriptError("Expected a number between 1 and 9, got %d instead.", sc.Number); + accuracy = sc.Number; + sc.MustGetToken(','); + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("xdeathface")) + stateFlags = static_cast (stateFlags|FMugShot::XDEATHFACE); + else if(sc.Compare("animatedgodmode")) + stateFlags = static_cast (stateFlags|FMugShot::ANIMATEDGODMODE); + else if(sc.Compare("disablegrin")) + stateFlags = static_cast (stateFlags|FMugShot::DISABLEGRIN); + else if(sc.Compare("disableouch")) + stateFlags = static_cast (stateFlags|FMugShot::DISABLEOUCH); + else if(sc.Compare("disablepain")) + stateFlags = static_cast (stateFlags|FMugShot::DISABLEPAIN); + else if(sc.Compare("disablerampage")) + stateFlags = static_cast (stateFlags|FMugShot::DISABLERAMPAGE); + else + sc.ScriptError("Unknown flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + + GetCoordinates(sc, fullScreenOffsets, x, y); + sc.MustGetToken(';'); + } + + protected: + FString defaultFace; //Deprecated + + int accuracy; + FMugShot::StateFlags stateFlags; + SBarInfoCoordinate x; + SBarInfoCoordinate y; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private CommandDrawImage, private CommandDrawNumber +{ + public: + CommandDrawSelectedInventory(SBarInfo *script) : SBarInfoCommandFlowControl(script), + CommandDrawImage(script), CommandDrawNumber(script), alternateOnEmpty(false), + artiflash(false), alwaysShowCounter(false) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if(statusBar->CPlayer->mo->InvSel != NULL && !(level.flags & LEVEL_NOINVENTORYBAR)) + { + if(artiflash && artiflashTick) + { + statusBar->DrawGraphic(statusBar->Images[ARTIFLASH_OFFSET+(4-artiflashTick)], imgx, imgy, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), + translatable, false, offset); + } + else + CommandDrawImage::Draw(block, statusBar); + if(alwaysShowCounter || statusBar->CPlayer->mo->InvSel->Amount != 1) + CommandDrawNumber::Draw(block, statusBar); + } + else if(alternateOnEmpty) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + type = SELECTEDINVENTORYICON; + value = SELECTEDINVENTORY; + while(true) //go until we get a font (non-flag) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("alternateonempty")) + alternateOnEmpty = true; + else if(sc.Compare("artiflash")) + artiflash = true; + else if(sc.Compare("alwaysshowcounter")) + alwaysShowCounter = true; + else if(sc.Compare("center")) + offset = CENTER; + else if(sc.Compare("centerbottom")) + offset = static_cast (HMIDDLE|BOTTOM); + else if(sc.Compare("drawshadow")) + shadow = true; + else + { + font = V_GetFont(sc.String); + if(font == NULL) + sc.ScriptError("Unknown font '%s'.", sc.String); + sc.MustGetToken(','); + break; + } + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + CommandDrawImage::GetCoordinates(sc, fullScreenOffsets, imgx, imgy); + startX = imgx + 30; + y = imgy + 24; + translation = CR_GOLD; + if(sc.CheckToken(',')) //more font information + { + CommandDrawNumber::GetCoordinates(sc, fullScreenOffsets, startX, y); + if(sc.CheckToken(',')) + { + translation = CommandDrawNumber::GetTranslation(sc); + if(sc.CheckToken(',')) + { + sc.MustGetToken(TK_IntConst); + spacing = sc.Number; + } + } + } + if(alternateOnEmpty) + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + else + sc.MustGetToken(';'); + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + if(artiflashTick > 0) + artiflashTick--; + + CommandDrawImage::Tick(block, statusBar, hudChanged); + CommandDrawNumber::Tick(block, statusBar, hudChanged); + } + + static void Flash() { artiflashTick = 4; } + protected: + bool alternateOnEmpty; + bool artiflash; + bool alwaysShowCounter; + + static int artiflashTick; +}; +int CommandDrawSelectedInventory::artiflashTick = 4; + +void DSBarInfo::FlashItem(const PClass *itemtype) +{ + CommandDrawSelectedInventory::Flash(); +} + +//////////////////////////////////////////////////////////////////////////////// + +class CommandGameMode : public SBarInfoCommandFlowControl +{ + public: + CommandGameMode(SBarInfo *script) : SBarInfoCommandFlowControl(script), + modes(static_cast (0)) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if((!multiplayer && (modes & SINGLEPLAYER)) || + (deathmatch && (modes & DEATHMATCH)) || + (multiplayer && !deathmatch && (modes & COOPERATIVE)) || + (teamplay && (modes & TEAMGAME))) + { + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + do + { + sc.MustGetToken(TK_Identifier); + modes |= static_cast (1<CPlayer->ReadyWeapon != NULL && (statusBar->CPlayer->ReadyWeapon->AmmoType1 != NULL || statusBar->CPlayer->ReadyWeapon->AmmoType2 != NULL)) ^ negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + if(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("not")) + negate = true; + else + sc.ScriptError("Expected 'not', but got '%s' instead.", sc.String); + } + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + protected: + bool negate; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandUsesSecondaryAmmo : public CommandUsesAmmo +{ + public: + CommandUsesSecondaryAmmo(SBarInfo *script) : CommandUsesAmmo(script) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if((statusBar->CPlayer->ReadyWeapon != NULL && statusBar->CPlayer->ReadyWeapon->AmmoType2 != NULL && statusBar->CPlayer->ReadyWeapon->AmmoType1 != statusBar->CPlayer->ReadyWeapon->AmmoType2) ^ negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandInventoryBarNotVisible : public SBarInfoCommandFlowControl +{ + public: + CommandInventoryBarNotVisible(SBarInfo *script) : SBarInfoCommandFlowControl(script) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if(statusBar->CPlayer->inventorytics <= 0 || (level.flags & LEVEL_NOINVENTORYBAR)) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandAspectRatio : public SBarInfoCommandFlowControl +{ + public: + CommandAspectRatio(SBarInfo *script) : SBarInfoCommandFlowControl(script), + ratio(ASPECTRATIO_4_3) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == ratio) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_StringConst); + if(sc.Compare("4:3")) + ratio = ASPECTRATIO_4_3; + else if(sc.Compare("16:9")) + ratio = ASPECTRATIO_16_9; + else if(sc.Compare("16:10")) + ratio = ASPECTRATIO_16_10; + else if(sc.Compare("5:4")) + ratio = ASPECTRATIO_5_4; + else + sc.ScriptError("Unkown aspect ratio: %s", sc.String); + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + protected: + enum Ratio + { + ASPECTRATIO_4_3 = 0, + ASPECTRATIO_16_9 = 1, + ASPECTRATIO_16_10 = 2, + ASPECTRATIO_5_4 = 4 + }; + + Ratio ratio; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawShader : public SBarInfoCommand +{ + public: + CommandDrawShader(SBarInfo *script) : SBarInfoCommand(script), + vertical(false), reverse(false), width(1), height(1) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + statusBar->DrawGraphic(&shaders[(vertical<<1) + reverse], x, y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, true, width, height); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_IntConst); + width = sc.Number; + if(sc.Number < 1) + sc.ScriptError("Width must be greater than 1."); + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + height = sc.Number; + if(sc.Number < 1) + sc.ScriptError("Height must be greater than 1."); + sc.MustGetToken(','); + sc.MustGetToken(TK_Identifier); + if(sc.Compare("vertical")) + vertical = true; + else if(!sc.Compare("horizontal")) + sc.ScriptError("Unknown direction '%s'.", sc.String); + sc.MustGetToken(','); + if(sc.CheckToken(TK_Identifier)) + { + if(!sc.Compare("reverse")) + { + sc.ScriptError("Exspected 'reverse', got '%s' instead.", sc.String); + } + reverse = true; + sc.MustGetToken(','); + } + GetCoordinates(sc, fullScreenOffsets, x, y); + sc.MustGetToken(';'); + } + protected: + bool vertical; + bool reverse; + unsigned int width; + unsigned int height; + SBarInfoCoordinate x; + SBarInfoCoordinate y; + private: + class FBarShader : public FTexture + { + public: + FBarShader(bool vertical, bool reverse) + { + int i; + + Width = vertical ? 2 : 256; + Height = vertical ? 256 : 2; + CalcBitSize(); + + // Fill the column/row with shading values. + // Vertical shaders have have minimum alpha at the top + // and maximum alpha at the bottom, unless flipped by + // setting reverse to true. Horizontal shaders are just + // the opposite. + if (vertical) + { + if (!reverse) + { + for (i = 0; i < 256; ++i) + { + Pixels[i] = i; + Pixels[256+i] = i; + } + } + else + { + for (i = 0; i < 256; ++i) + { + Pixels[i] = 255 - i; + Pixels[256+i] = 255 -i; + } + } + } + else + { + if (!reverse) + { + for (i = 0; i < 256; ++i) + { + Pixels[i*2] = 255 - i; + Pixels[i*2+1] = 255 - i; + } + } + else + { + for (i = 0; i < 256; ++i) + { + Pixels[i*2] = i; + Pixels[i*2+1] = i; + } + } + } + DummySpan[0].TopOffset = 0; + DummySpan[0].Length = vertical ? 256 : 2; + DummySpan[1].TopOffset = 0; + DummySpan[1].Length = 0; + } + const BYTE *GetColumn(unsigned int column, const Span **spans_out) + { + if (spans_out != NULL) + { + *spans_out = DummySpan; + } + return Pixels + ((column & WidthMask) << HeightBits); + } + const BYTE *GetPixels() { return Pixels; } + void Unload() {} + private: + BYTE Pixels[512]; + Span DummySpan[2]; + }; + + static FBarShader shaders[4]; +}; + +CommandDrawShader::FBarShader CommandDrawShader::shaders[4] = +{ + FBarShader(false, false), FBarShader(false, true), + FBarShader(true, false), FBarShader(true, true) +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawInventoryBar : public SBarInfoCommand +{ + public: + CommandDrawInventoryBar(SBarInfo *script) : SBarInfoCommand(script), + style(GAME_Doom), size(7), alwaysShow(false), noArtibox(false), + noArrows(false), alwaysShowCounter(false), translucent(false), + vertical(false), counters(NULL), font(NULL), translation(CR_GOLD), + fontSpacing(0) + { + } + ~CommandDrawInventoryBar() + { + if(counters != NULL) + { + for(unsigned int i = 0;i < size;i++) + delete counters[i]; + delete[] counters; + } + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + int spacing = 0; + if(!vertical) + spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; + else + spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; + + int bgalpha = block->Alpha(); + if(translucent) + bgalpha = fixed_t((((double) block->Alpha() / (double) FRACUNIT) * ((double) HX_SHADOW / (double) FRACUNIT)) * FRACUNIT); + + AInventory *item; + unsigned int i = 0; + // If the player has no artifacts, don't draw the bar + statusBar->CPlayer->mo->InvFirst = statusBar->ValidateInvFirst(size); + if(statusBar->CPlayer->mo->InvFirst != NULL || alwaysShow) + { + for(item = statusBar->CPlayer->mo->InvFirst, i = 0; item != NULL && i < size; item = item->NextInv(), ++i) + { + SBarInfoCoordinate rx = x + (!vertical ? i*spacing : 0); + SBarInfoCoordinate ry = y + (vertical ? i*spacing : 0); + if(!noArtibox) + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgARTIBOX], rx, ry, block->XOffset(), block->YOffset(), bgalpha, block->FullScreenOffsets()); + + if(style != GAME_Strife) //Strife draws the cursor before the icons + statusBar->DrawGraphic(TexMan(item->Icon), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->Amount <= 0); + if(item == statusBar->CPlayer->mo->InvSel) + { + if(style == GAME_Heretic) + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry+29, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + else if(style == GAME_Hexen) + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry-1, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + else if(style == GAME_Strife) + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgCURSOR], rx-6, ry-2, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + else + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgSELECTBOX], rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + } + if(style == GAME_Strife) + statusBar->DrawGraphic(TexMan(item->Icon), rx, ry, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, item->Amount <= 0); + if(counters != NULL && (alwaysShowCounter || item->Amount != 1)) + { + counters[i]->valueArgument = item->Amount; + counters[i]->Draw(block, statusBar); + } + } + for (; i < size && !noArtibox; ++i) + statusBar->DrawGraphic(statusBar->Images[statusBar->invBarOffset + imgARTIBOX], x + (!vertical ? (i*spacing) : 0), y + (vertical ? (i*spacing) : 0), block->XOffset(), block->YOffset(), bgalpha, block->FullScreenOffsets()); + + // Is there something to the left? + if (!noArrows && statusBar->CPlayer->mo->FirstInv() != statusBar->CPlayer->mo->InvFirst) + { + int offset = style != GAME_Strife ? -12 : 14; + statusBar->DrawGraphic(statusBar->Images[!(gametic & 4) ? + statusBar->invBarOffset + imgINVLFGEM1 : statusBar->invBarOffset + imgINVLFGEM2], x + (!vertical ? offset : 0), y + (vertical ? offset : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + } + // Is there something to the right? + if (!noArrows && item != NULL) + { + int offset = style != GAME_Strife ? size*31+2 : size*35-4; + statusBar->DrawGraphic(statusBar->Images[!(gametic & 4) ? + statusBar->invBarOffset + imgINVRTGEM1 : statusBar->invBarOffset + imgINVRTGEM2], x + (!vertical ? offset : 0), y + (vertical ? offset : 0), block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + } + } + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("Doom")) + style = GAME_Doom; + else if(sc.Compare("Heretic")) + style = GAME_Heretic; + else if(sc.Compare("Hexen")) + style = GAME_Hexen; + else if(sc.Compare("Strife")) + style = GAME_Strife; + else + sc.ScriptError("Unknown style '%s'.", sc.String); + + sc.MustGetToken(','); + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("alwaysshow")) + alwaysShow = true; + else if(sc.Compare("noartibox")) + noArtibox = true; + else if(sc.Compare("noarrows")) + noArrows = true; + else if(sc.Compare("alwaysshowcounter")) + alwaysShowCounter = true; + else if(sc.Compare("translucent")) + translucent = true; + else if(sc.Compare("vertical")) + vertical = true; + else + sc.ScriptError("Unknown flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + sc.MustGetToken(TK_IntConst); + size = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_Identifier); + font = V_GetFont(sc.String); + if(font == NULL) + sc.ScriptError("Unknown font '%s'.", sc.String); + + sc.MustGetToken(','); + GetCoordinates(sc, fullScreenOffsets, x, y); + counterX = x + 26; + counterY = y + 22; + if(sc.CheckToken(',')) //more font information + { + GetCoordinates(sc, fullScreenOffsets, counterX, counterY); + if(sc.CheckToken(',')) + { + translation = GetTranslation(sc); + if(sc.CheckToken(',')) + { + sc.MustGetToken(TK_IntConst); + fontSpacing = sc.Number; + } + } + } + sc.MustGetToken(';'); + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + // Make the counters if need be. + if(counters == NULL) + { + int spacing = 0; + if(!vertical) + spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledWidth() - 1; + else + spacing = (style != GAME_Strife) ? statusBar->Images[statusBar->invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : statusBar->Images[statusBar->invBarOffset + imgCURSOR]->GetScaledHeight() - 1; + counters = new CommandDrawNumber*[size]; + + for(unsigned int i = 0;i < size;i++) + { + counters[i] = new CommandDrawNumber(script); + + counters[i]->startX = counterX + (!vertical ? spacing*i : 0); + counters[i]->y = counterY + (vertical ? spacing*i : 0); + counters[i]->normalTranslation = translation; + counters[i]->font = font; + counters[i]->spacing = fontSpacing; + counters[i]->whenNotZero = !alwaysShowCounter; + counters[i]->drawValue = counters[i]->value = CommandDrawNumber::CONSTANT; + counters[i]->length = 3; + } + } + + for(unsigned int i = 0;i < size;i++) + counters[i]->Tick(block, statusBar, hudChanged); + } + protected: + int style; + unsigned int size; + bool alwaysShow; + bool noArtibox; + bool noArrows; + bool alwaysShowCounter; + bool translucent; + bool vertical; + SBarInfoCoordinate x; + SBarInfoCoordinate y; + CommandDrawNumber* *counters; + private: + // This information will be transferred to counters as soon as possible. + FFont *font; + SBarInfoCoordinate counterX; + SBarInfoCoordinate counterY; + EColorRange translation; + int fontSpacing; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawKeyBar : public SBarInfoCommand +{ + public: + CommandDrawKeyBar(SBarInfo *script) : SBarInfoCommand(script), + number(3), vertical(false), reverseRows(false), iconSize(-1), + rowIconSize(-1), keyOffset(0), rowSize(0) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + AInventory *item = statusBar->CPlayer->mo->Inventory; + if(item == NULL) + return; + int slotOffset = 0; + int rowOffset = 0; + int rowWidth = 0; + for(unsigned int i = 0;i < number+keyOffset;i++) + { + while(!item->Icon.isValid() || !item->IsKindOf(RUNTIME_CLASS(AKey))) + { + item = item->Inventory; + if(item == NULL) + return; + } + if(i >= keyOffset) //Should we start drawing? + { + if(!vertical) + { + statusBar->DrawGraphic(TexMan[item->Icon], x+slotOffset, y+rowOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? TexMan[item->Icon]->GetScaledHeight()+2 : rowIconSize; + } + else + { + statusBar->DrawGraphic(TexMan[item->Icon], x+rowOffset, y+slotOffset, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + rowWidth = rowIconSize == -1 ? TexMan[item->Icon]->GetScaledWidth()+2 : rowIconSize; + } + + // If cmd.special is -1 then the slot size is auto detected + if(iconSize == -1) + { + if(!vertical) + slotOffset += TexMan[item->Icon]->GetScaledWidth() + 2; + else + slotOffset += TexMan[item->Icon]->GetScaledHeight() + 2; + } + else + slotOffset += iconSize; + + if(rowSize > 0 && (i % rowSize == rowSize-1)) + { + if(reverseRows) + rowOffset -= rowWidth; + else + rowOffset += rowWidth; + rowWidth = 0; + slotOffset = 0; + } + } + + item = item->Inventory; + if(item == NULL) + return; + } + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_IntConst); + number = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_Identifier); + if(sc.Compare("vertical")) + vertical = true; + else if(!sc.Compare("horizontal")) + sc.ScriptError("Unknown direction '%s'.", sc.String); + sc.MustGetToken(','); + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("reverserows")) + reverseRows = true; + else + sc.ScriptError("Unknown flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + if(sc.CheckToken(TK_Auto)) + iconSize = -1; + else + { + sc.MustGetToken(TK_IntConst); + iconSize = sc.Number; + } + sc.MustGetToken(','); + GetCoordinates(sc, fullScreenOffsets, x, y); + if(sc.CheckToken(',')) + { + //key offset + sc.MustGetToken(TK_IntConst); + keyOffset = sc.Number; + if(sc.CheckToken(',')) + { + //max per row/column + sc.MustGetToken(TK_IntConst); + rowSize = sc.Number; + sc.MustGetToken(','); + //row/column spacing (opposite of previous) + if(sc.CheckToken(TK_Auto)) + rowIconSize = -1; + else + { + sc.MustGetToken(TK_IntConst); + rowIconSize = sc.Number; + } + } + } + sc.MustGetToken(';'); + } + protected: + unsigned int number; + bool vertical; + bool reverseRows; + int iconSize; + int rowIconSize; + unsigned int keyOffset; + unsigned int rowSize; + SBarInfoCoordinate x; + SBarInfoCoordinate y; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawBar : public SBarInfoCommand +{ + public: + CommandDrawBar(SBarInfo *script) : SBarInfoCommand(script), + border(0), horizontal(false), reverse(false), foreground(-1), background(-1), + type(HEALTH), inventoryItem(NULL), interpolationSpeed(0), drawValue(0) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if(foreground == -1 || statusBar->Images[foreground] == NULL) + return; //don't draw anything. + assert(statusBar->Images[foreground] != NULL); + + FTexture *fg = statusBar->Images[foreground]; + FTexture *bg = (background != -1) ? statusBar->Images[background] : NULL; + + if(border != 0) + { + //Draw the whole foreground + statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + } + else + { + // Draw background + if (bg != NULL && bg->GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) + statusBar->DrawGraphic(bg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + else + statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, false, -1, -1, 0, 0, 0, 0, true); + } + + // {cx, cy, cr, cb} + fixed_t clip[4] = {0, 0, 0, 0}; + + fixed_t sizeOfImage = (horizontal ? fg->GetScaledWidth()-border*2 : fg->GetScaledHeight()-border*2)<GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) + statusBar->DrawGraphic(bg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, false, -1, -1, clip[0], clip[1], clip[2], clip[3]); + else + statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, false, -1, -1, clip[0], clip[1], clip[2], clip[3], true); + } + else + statusBar->DrawGraphic(fg, this->x, this->y, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), false, false, 0, false, -1, -1, clip[0], clip[1], clip[2], clip[3]); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_StringConst); + foreground = script->newImage(sc.String); + sc.MustGetToken(','); + sc.MustGetToken(TK_StringConst); + background = script->newImage(sc.String); + sc.MustGetToken(','); + sc.MustGetToken(TK_Identifier); + if(sc.Compare("health")) + { + type = HEALTH; + if(sc.CheckToken(TK_Identifier)) //comparing reference + { + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + } + else if(sc.Compare("armor")) + { + type = ARMOR; + if(sc.CheckToken(TK_Identifier)) + { + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(inventoryItem)) //must be a kind of inventory + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + } + else if(sc.Compare("ammo1")) + type = AMMO1; + else if(sc.Compare("ammo2")) + type = AMMO2; + else if(sc.Compare("ammo")) //request the next string to be an ammo type + { + sc.MustGetToken(TK_Identifier); + type = AMMO; + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + { + sc.ScriptError("'%s' is not a type of ammo.", sc.String); + } + } + else if(sc.Compare("frags")) + type = FRAGS; + else if(sc.Compare("kills")) + type = KILLS; + else if(sc.Compare("items")) + type = ITEMS; + else if(sc.Compare("secrets")) + type = SECRETS; + else if(sc.Compare("airtime")) + type = AIRTIME; + else if(sc.Compare("poweruptime")) + { + type = POWERUPTIME; + sc.MustGetToken(TK_Identifier); + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(inventoryItem)) + { + sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); + } + } + else + { + type = INVENTORY; + inventoryItem = PClass::FindClass(sc.String); + if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) + { + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + } + sc.MustGetToken(','); + sc.MustGetToken(TK_Identifier); + if(sc.Compare("horizontal")) + horizontal = true; + else if(!sc.Compare("vertical")) + sc.ScriptError("Unknown direction '%s'.", sc.String); + sc.MustGetToken(','); + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("reverse")) + reverse = true; + else if(sc.Compare("interpolate")) + { + sc.MustGetToken('('); + sc.MustGetToken(TK_IntConst); + interpolationSpeed = sc.Number; + sc.MustGetToken(')'); + } + else + sc.ScriptError("Unkown flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + GetCoordinates(sc, fullScreenOffsets, x, y); + if(sc.CheckToken(',')) //border + { + sc.MustGetToken(TK_IntConst); + border = sc.Number; + } + sc.MustGetToken(';'); + + if(type == HEALTH) + interpolationSpeed = script->interpolateHealth ? script->interpolationSpeed : interpolationSpeed; + else if(type == ARMOR) + interpolationSpeed = script->interpolateArmor ? script->armorInterpolationSpeed : interpolationSpeed; + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + fixed_t value = 0; + int max = 0; + switch(type) + { + case HEALTH: + value = statusBar->CPlayer->mo->health; + if(value < 0) //health shouldn't display negatives + value = 0; + + if(inventoryItem != NULL) + { + AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); //max comparer + if(item != NULL) + max = item->Amount; + else + max = 0; + } + else //default to the class's health + max = statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->stamina; + break; + case ARMOR: + value = statusBar->armor != NULL ? statusBar->armor->Amount : 0; + if(inventoryItem != NULL) + { + AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + if(item != NULL) + max = item->Amount; + else + max = 0; + } + else + max = 100; + break; + case AMMO1: + value = statusBar->ammocount1; + if(statusBar->ammo1 == NULL) //no ammo, draw as empty + { + value = 0; + max = 1; + } + else + max = statusBar->ammo1->MaxAmount; + break; + case AMMO2: + value = statusBar->ammocount2; + if(statusBar->ammo2 == NULL) //no ammo, draw as empty + { + value = 0; + max = 1; + } + else + max = statusBar->ammo2->MaxAmount; + break; + case AMMO: + { + AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + if(item != NULL) + { + value = item->Amount; + max = item->MaxAmount; + } + else + value = 0; + break; + } + case FRAGS: + value = statusBar->CPlayer->fragcount; + max = fraglimit; + break; + case KILLS: + value = level.killed_monsters; + max = level.total_monsters; + break; + case ITEMS: + value = level.found_items; + max = level.total_items; + break; + case SECRETS: + value = level.found_secrets; + max = level.total_secrets; + break; + case INVENTORY: + { + AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + if(item != NULL) + { + value = item->Amount; + max = item->MaxAmount; + } + else + value = 0; + break; + } + case AIRTIME: + value = clamp(statusBar->CPlayer->air_finished - level.time, 0, INT_MAX); + max = level.airsupply; + break; + case POWERUPTIME: + { + //Get the PowerupType and check to see if the player has any in inventory. + APowerupGiver *powerupGiver = (APowerupGiver*) GetDefaultByType(inventoryItem); + const PClass *powerupType = powerupGiver->PowerupType; + APowerup *powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType); + if(powerup != NULL && powerupType != NULL && powerupGiver != NULL) + { + value = powerup->EffectTics + 1; + if(powerupGiver->EffectTics == 0) //if 0 we need to get the default from the powerup + max = ((APowerup*) GetDefaultByType(powerupType))->EffectTics + 1; + else + max = powerupGiver->EffectTics + 1; + } + break; + } + default: return; + } + + if(border != 0) + value = max - value; //invert since the new drawing method requires drawing the bg on the fg. + if(max != 0 && value > 0) + { + value = (value << FRACBITS) / max; + if(value > FRACUNIT) + value = FRACUNIT; + } + else if(border != 0 && max == 0 && value <= 0) + value = FRACUNIT; + else + value = 0; + if(interpolationSpeed != 0 && (!hudChanged || level.time == 1)) + { + if(value < drawValue) + drawValue -= clamp((drawValue - value) >> 2, 1, FixedDiv(interpolationSpeed<((value - drawValue) >> 2, 1, FixedDiv(interpolationSpeed<CPlayer->ReadyWeapon != NULL) + { + const PClass *readyWeapon = statusBar->CPlayer->ReadyWeapon->GetClass(); + if(((weapon[1] != NULL) && + ((negate && (weapon[0] != readyWeapon && weapon[1] != readyWeapon)) || + (!negate && (weapon[0] == readyWeapon || weapon[1] == readyWeapon)))) || + ((weapon[1] == NULL) && + ((!negate && weapon[0] == readyWeapon) || (negate && weapon[0] != readyWeapon)))) + { + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + } + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + //Using StringConst instead of Identifieres is deperecated! + if(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("not")) + { + negate = true; + if(!sc.CheckToken(TK_StringConst)) + sc.MustGetToken(TK_Identifier); + } + } + else + sc.MustGetToken(TK_StringConst); + for(int i = 0;i < 2;i++) + { + weapon[i] = PClass::FindClass(sc.String); + if(weapon[i] == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon[i])) + sc.ScriptError("'%s' is not a type of weapon.", sc.String); + + if(sc.CheckToken(',')) + { + if(!sc.CheckToken(TK_StringConst)) + sc.MustGetToken(TK_Identifier); + } + else + break; + } + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + protected: + bool negate; + const PClass *weapon[2]; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandPlayerClass : public SBarInfoCommandFlowControl +{ + public: + CommandPlayerClass(SBarInfo *script) : SBarInfoCommandFlowControl(script) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if(statusBar->CPlayer->cls == NULL) + return; //No class so we can not continue + + int spawnClass = statusBar->CPlayer->cls->ClassIndex; + for(unsigned int i = 0;i < classes.Size();i++) + { + if(classes[i] == spawnClass) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + do + { + bool foundClass = false; + for(unsigned int c = 0;c < PlayerClasses.Size();c++) + { + if(stricmp(sc.String, PlayerClasses[c].Type->Meta.GetMetaString(APMETA_DisplayName)) == 0) + { + foundClass = true; + classes.Push(PlayerClasses[c].Type->ClassIndex); + break; + } + } + if(!foundClass) + sc.ScriptError("Unkown PlayerClass '%s'.", sc.String); + if(!sc.CheckToken(',')) + break; + } + while(sc.CheckToken(TK_Identifier)); + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + protected: + TArray classes; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandHasWeaponPiece : public SBarInfoCommandFlowControl +{ + public: + CommandHasWeaponPiece(SBarInfo *script) : SBarInfoCommandFlowControl(script), + weapon(NULL), piece(1) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + for(AInventory *inv = statusBar->CPlayer->mo->Inventory;inv != NULL;inv=inv->Inventory) + { + if(inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder))) + { + AWeaponHolder *hold = static_cast(inv); + if(hold->PieceWeapon == weapon) + { + if(hold->PieceMask & (1 << (piece-1))) + SBarInfoCommandFlowControl::Draw(block, statusBar); + break; + } + } + } + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + weapon = PClass::FindClass(sc.String); + if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon + sc.ScriptError("%s is not a kind of weapon.", sc.String); + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + if(sc.Number < 1) + sc.ScriptError("Weapon piece number can not be less than 1."); + piece = sc.Number; + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + protected: + const PClass *weapon; + unsigned int piece; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandDrawGem : public SBarInfoCommand +{ + public: + CommandDrawGem(SBarInfo *script) : SBarInfoCommand(script), + wiggle(false), translatable(false), armor(false), reverse(false), + chain(-1), gem(-1), leftPadding(0), rightPadding(0), chainSize(1), + interpolationSpeed(0), drawValue(0), goalValue(0), chainWiggle(0) + { + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + FTexture *chainImg = statusBar->Images[chain]; + FTexture *gemImg = statusBar->Images[gem]; + if(chainImg == NULL) + return; + + SBarInfoCoordinate drawY = y; + if(wiggle && drawValue != goalValue) // Should only wiggle when the value doesn't equal what is being drawn. + drawY += chainWiggle; + int chainWidth = chainImg->GetWidth(); + int offset = (int) (((double) (chainWidth-leftPadding-rightPadding)/100)*drawValue); + statusBar->DrawGraphic(chainImg, x+(offset%chainSize), drawY, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets()); + if(gemImg != NULL) + statusBar->DrawGraphic(gemImg, x+leftPadding+offset, drawY, block->XOffset(), block->YOffset(), block->Alpha(), block->FullScreenOffsets(), translatable); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("wiggle")) + wiggle = true; + else if(sc.Compare("translatable")) + translatable = true; + else if(sc.Compare("armor")) + armor = true; + else if(sc.Compare("interpolate")) + { + sc.MustGetToken('('); + sc.MustGetToken(TK_IntConst); + interpolationSpeed = sc.Number; + sc.MustGetToken(')'); + } + else if(sc.Compare("reverse")) + reverse = true; + else + sc.ScriptError("Unknown drawgem flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + sc.MustGetToken(TK_StringConst); //chain + chain = script->newImage(sc.String); + sc.MustGetToken(','); + sc.MustGetToken(TK_StringConst); //gem + gem = script->newImage(sc.String); + sc.MustGetToken(','); + bool negative = sc.CheckToken('-'); + sc.MustGetToken(TK_IntConst); + leftPadding = (negative ? -1 : 1) * sc.Number; + sc.MustGetToken(','); + negative = sc.CheckToken('-'); + sc.MustGetToken(TK_IntConst); + rightPadding = (negative ? -1 : 1) * sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + if(sc.Number < 0) + sc.ScriptError("Chain size must be a positive number."); + chainSize = sc.Number; + sc.MustGetToken(','); + GetCoordinates(sc, fullScreenOffsets, x, y); + sc.MustGetToken(';'); + + if(!armor) + interpolationSpeed = script->interpolateHealth ? script->interpolationSpeed : interpolationSpeed; + else + interpolationSpeed = script->interpolateArmor ? script->armorInterpolationSpeed : interpolationSpeed; + } + void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) + { + goalValue = armor ? statusBar->armor->Amount : statusBar->CPlayer->mo->health; + int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->stamina; + if(max != 0 && goalValue > 0) + { + goalValue = (goalValue*100)/max; + if(goalValue > 100) + goalValue = 100; + } + else + goalValue = 0; + + goalValue = reverse ? 100 - goalValue : goalValue; + + if(interpolationSpeed != 0 && (!hudChanged || level.time == 1)) // At the start force an animation + { + if(goalValue < drawValue) + drawValue -= clamp((drawValue - goalValue) >> 2, 1, interpolationSpeed); + else if(drawValue < goalValue) + drawValue += clamp((goalValue - drawValue) >> 2, 1, interpolationSpeed); + } + else + drawValue = goalValue; + + if(wiggle && level.time & 1) + chainWiggle = pr_chainwiggle() & 1; + } + protected: + bool wiggle; + bool translatable; + bool armor; + bool reverse; + int chain; + int gem; + int leftPadding; + int rightPadding; + unsigned int chainSize; + SBarInfoCoordinate x; + SBarInfoCoordinate y; + + int interpolationSpeed; + int drawValue; + int goalValue; + private: + int chainWiggle; + static FRandom pr_chainwiggle; +}; +FRandom CommandDrawGem::pr_chainwiggle; //use the same method of chain wiggling as heretic. + +//////////////////////////////////////////////////////////////////////////////// + +class CommandWeaponAmmo : public SBarInfoCommandFlowControl +{ + public: + CommandWeaponAmmo(SBarInfo *script) : SBarInfoCommandFlowControl(script), + conditionAnd(false), negate(false) + { + ammo[0] = NULL; + ammo[1] = NULL; + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + if(statusBar->CPlayer->ReadyWeapon != NULL) + { + const PClass *AmmoType1 = statusBar->CPlayer->ReadyWeapon->AmmoType1; + const PClass *AmmoType2 = statusBar->CPlayer->ReadyWeapon->AmmoType2; + bool usesammo1 = (AmmoType1 != NULL); + bool usesammo2 = (AmmoType2 != NULL); + if(!negate && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble. + { + SBarInfoCommandFlowControl::Draw(block, statusBar); + return; + } + //Or means only 1 ammo type needs to match and means both need to match. + if(ammo[1] != NULL) + { + bool match1 = ((usesammo1 && (AmmoType1 == ammo[0] || AmmoType1 == ammo[1])) || !usesammo1); + bool match2 = ((usesammo2 && (AmmoType2 == ammo[0] || AmmoType2 == ammo[1])) || !usesammo2); + if((!conditionAnd && (match1 || match2)) || (conditionAnd && (match1 && match2))) + { + if(!negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + else if(negate) + { + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + } + else //Every thing here could probably be one long if statement but then it would be more confusing. + { + if((usesammo1 && (AmmoType1 == ammo[0])) || (usesammo2 && (AmmoType2 == ammo[0]))) + { + if(!negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + else if(negate) + { + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + } + } + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("not")) + { + negate = true; + sc.MustGetToken(TK_Identifier); + } + for(int i = 0;i < 2;i++) + { + ammo[i] = PClass::FindClass(sc.String); + if(ammo[i] == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo[i])) //must be a kind of ammo + sc.ScriptError("'%s' is not a type of ammo.", sc.String); + + if(sc.CheckToken(TK_OrOr)) + { + conditionAnd = false; + sc.MustGetToken(TK_Identifier); + } + else if(sc.CheckToken(TK_AndAnd)) + { + conditionAnd = true; + sc.MustGetToken(TK_Identifier); + } + else + break; + } + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + protected: + bool conditionAnd; + bool negate; + const PClass *ammo[2]; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class CommandInInventory : public SBarInfoCommandFlowControl +{ + public: + CommandInInventory(SBarInfo *script) : SBarInfoCommandFlowControl(script), + conditionAnd(false), negate(false) + { + item[0] = item[1] = NULL; + amount[0] = amount[1] = 0; + } + + void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) + { + AInventory *invItem[2] = { statusBar->CPlayer->mo->FindInventory(item[0]), statusBar->CPlayer->mo->FindInventory(item[1]) }; + if (invItem[0] != NULL && amount[0] > 0 && invItem[0]->Amount < amount[0]) invItem[0] = NULL; + if (invItem[1] != NULL && amount[1] > 0 && invItem[1]->Amount < amount[1]) invItem[1] = NULL; + if(invItem[1] != NULL && conditionAnd) + { + if((invItem[0] != NULL && invItem[1] != NULL) && !negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + else if((invItem[0] == NULL || invItem[1] == NULL) && negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + else if(invItem[1] != NULL && !conditionAnd) + { + if((invItem[0] != NULL || invItem[1] != NULL) && !negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + else if((invItem[0] == NULL && invItem[1] == NULL) && negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + else if((invItem[0] != NULL) && !negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + else if((invItem[0] == NULL) && negate) + SBarInfoCommandFlowControl::Draw(block, statusBar); + } + void Parse(FScanner &sc, bool fullScreenOffsets) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("not")) + { + negate = true; + sc.MustGetToken(TK_Identifier); + } + for(int i = 0;i < 2;i++) + { + item[i] = PClass::FindClass(sc.String); + if(item[i] == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item[i])) + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + + if (sc.CheckToken(',')) + { + sc.MustGetNumber(); + amount[i] = sc.Number; + } + + if(sc.CheckToken(TK_OrOr)) + { + conditionAnd = false; + sc.MustGetToken(TK_Identifier); + } + else if(sc.CheckToken(TK_AndAnd)) + { + conditionAnd = true; + sc.MustGetToken(TK_Identifier); + } + else + break; + } + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + } + protected: + bool conditionAnd; + bool negate; + const PClass *item[2]; + int amount[2]; +}; + +//////////////////////////////////////////////////////////////////////////////// + +static const char *SBarInfoCommandNames[] = +{ + "drawimage", "drawnumber", "drawswitchableimage", + "drawmugshot", "drawselectedinventory", + "drawinventorybar", "drawbar", "drawgem", + "drawshader", "drawstring", "drawkeybar", + "gamemode", "playerclass", "aspectratio", + "isselected", "usesammo", "usessecondaryammo", + "hasweaponpiece", "inventorybarnotvisible", + "weaponammo", "ininventory", + NULL +}; + +enum SBarInfoCommands +{ + SBARINFO_DRAWIMAGE, SBARINFO_DRAWNUMBER, SBARINFO_DRAWSWITCHABLEIMAGE, + SBARINFO_DRAWMUGSHOT, SBARINFO_DRAWSELECTEDINVENTORY, + SBARINFO_DRAWINVENTORYBAR, SBARINFO_DRAWBAR, SBARINFO_DRAWGEM, + SBARINFO_DRAWSHADER, SBARINFO_DRAWSTRING, SBARINFO_DRAWKEYBAR, + SBARINFO_GAMEMODE, SBARINFO_PLAYERCLASS, SBARINFO_ASPECTRATIO, + SBARINFO_ISSELECTED, SBARINFO_USESAMMO, SBARINFO_USESSECONDARYAMMO, + SBARINFO_HASWEAPONPIECE, SBARINFO_INVENTORYBARNOTVISIBLE, + SBARINFO_WEAPONAMMO, SBARINFO_ININVENTORY, +}; + +SBarInfoCommand *SBarInfoCommandFlowControl::NextCommand(FScanner &sc) +{ + if(sc.CheckToken(TK_Identifier)) + { + switch(sc.MatchString(SBarInfoCommandNames)) + { + default: break; + case SBARINFO_DRAWIMAGE: return new CommandDrawImage(script); + case SBARINFO_DRAWSWITCHABLEIMAGE: return new CommandDrawSwitchableImage(script); + case SBARINFO_DRAWSTRING: return new CommandDrawString(script); + case SBARINFO_DRAWNUMBER: return new CommandDrawNumber(script); + case SBARINFO_DRAWMUGSHOT: return new CommandDrawMugShot(script); + case SBARINFO_DRAWSELECTEDINVENTORY: return reinterpret_cast (new CommandDrawSelectedInventory(script)); + case SBARINFO_DRAWSHADER: return new CommandDrawShader(script); + case SBARINFO_DRAWINVENTORYBAR: return new CommandDrawInventoryBar(script); + case SBARINFO_DRAWKEYBAR: return new CommandDrawKeyBar(script); + case SBARINFO_DRAWBAR: return new CommandDrawBar(script); + case SBARINFO_DRAWGEM: return new CommandDrawGem(script); + case SBARINFO_GAMEMODE: return new CommandGameMode(script); + case SBARINFO_USESAMMO: return new CommandUsesAmmo(script); + case SBARINFO_USESSECONDARYAMMO: return new CommandUsesSecondaryAmmo(script); + case SBARINFO_INVENTORYBARNOTVISIBLE: return new CommandInventoryBarNotVisible(script); + case SBARINFO_ASPECTRATIO: return new CommandAspectRatio(script); + case SBARINFO_ISSELECTED: return new CommandIsSelected(script); + case SBARINFO_PLAYERCLASS: return new CommandPlayerClass(script); + case SBARINFO_HASWEAPONPIECE: return new CommandHasWeaponPiece(script); + case SBARINFO_WEAPONAMMO: return new CommandWeaponAmmo(script); + case SBARINFO_ININVENTORY: return new CommandInInventory(script); + } + + sc.ScriptError("Unknown command '%s'.\n", sc.String); + return NULL; + } + + sc.MustGetToken('}'); + return NULL; +} diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp deleted file mode 100644 index 0a986fbbb5..0000000000 --- a/src/g_shared/sbarinfo_display.cpp +++ /dev/null @@ -1,1765 +0,0 @@ -/* -** sbarinfo_display.cpp -** -** Contains all functions required for the display of custom statusbars. -** -**--------------------------------------------------------------------------- -** 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 "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 "sbarinfo.h" -#include "gi.h" -#include "r_translate.h" -#include "r_main.h" -#include "a_weaponpiece.h" -#include "a_strifeglobal.h" -#include "g_level.h" -#include "v_palette.h" -#include "p_acs.h" - -static FRandom pr_chainwiggle; //use the same method of chain wiggling as heretic. - -#define ST_RAMPAGETIME (TICRATE*2) -#define ARTIFLASH_OFFSET (invBarOffset+6) - -EXTERN_CVAR(Int, fraglimit) -EXTERN_CVAR(Int, screenblocks) -EXTERN_CVAR(Bool, vid_fps) -EXTERN_CVAR(Bool, hud_scale) - -enum -{ - imgARTIBOX, - imgSELECTBOX, - imgCURSOR, - imgINVLFGEM1, - imgINVLFGEM2, - imgINVRTGEM1, - imgINVRTGEM2, -}; - -#define ADJUST_RELCENTER(x, y, outX, outY) \ - if(x.RelCenter()) \ - outX = *x + SCREENWIDTH/(hud_scale ? CleanXfac*2 : 2); \ - else \ - outX = *x; \ - if(y.RelCenter()) \ - outY = *y + SCREENHEIGHT/(hud_scale ? CleanYfac*2 : 2); \ - else \ - outY = *y; - -//////////////////////////////////////////////////////////////////////////////// - -SBarInfoCoordinate &SBarInfoCoordinate::Add(int add) -{ - value += add; - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// - -//Used for shading -FBarShader::FBarShader(bool vertical, bool reverse) //make an alpha map -{ - int i; - - Width = vertical ? 2 : 256; - Height = vertical ? 256 : 2; - CalcBitSize(); - - // Fill the column/row with shading values. - // Vertical shaders have have minimum alpha at the top - // and maximum alpha at the bottom, unless flipped by - // setting reverse to true. Horizontal shaders are just - // the opposite. - if (vertical) - { - if (!reverse) - { - for (i = 0; i < 256; ++i) - { - Pixels[i] = i; - Pixels[256+i] = i; - } - } - else - { - for (i = 0; i < 256; ++i) - { - Pixels[i] = 255 - i; - Pixels[256+i] = 255 -i; - } - } - } - else - { - if (!reverse) - { - for (i = 0; i < 256; ++i) - { - Pixels[i*2] = 255 - i; - Pixels[i*2+1] = 255 - i; - } - } - else - { - for (i = 0; i < 256; ++i) - { - Pixels[i*2] = i; - Pixels[i*2+1] = i; - } - } - } - DummySpan[0].TopOffset = 0; - DummySpan[0].Length = vertical ? 256 : 2; - DummySpan[1].TopOffset = 0; - DummySpan[1].Length = 0; -} - -const BYTE *FBarShader::GetColumn(unsigned int column, const Span **spans_out) -{ - if (spans_out != NULL) - { - *spans_out = DummySpan; - } - return Pixels + ((column & WidthMask) << HeightBits); -} - -const BYTE *FBarShader::GetPixels() -{ - return Pixels; -} - -void FBarShader::Unload() -{ -} - -//SBarInfo Display -DSBarInfo::DSBarInfo (SBarInfo *script) : DBaseStatusBar(script->height), - shader_horz_normal(false, false), - shader_horz_reverse(false, true), - shader_vert_normal(true, false), - shader_vert_reverse(true, true) -{ - this->script = script; - - static const char *InventoryBarLumps[] = - { - "ARTIBOX", "SELECTBO", "INVCURS", "INVGEML1", - "INVGEML2", "INVGEMR1", "INVGEMR2", - "USEARTIA", "USEARTIB", "USEARTIC", "USEARTID", - }; - TArray patchnames; - patchnames.Resize(script->Images.Size()+10); - unsigned int i = 0; - for(i = 0;i < script->Images.Size();i++) - { - patchnames[i] = script->Images[i]; - } - for(i = 0;i < 10;i++) - { - patchnames[i+script->Images.Size()] = InventoryBarLumps[i]; - } - for (i = 0;i < numskins;i++) - { - AddFaceToImageCollection (&skins[i], &Images); - } - invBarOffset = script->Images.Size(); - Images.Init(&patchnames[0], patchnames.Size()); - drawingFont = V_GetFont("ConFont"); - oldHealth = 0; - oldArmor = 0; - chainWiggle = 0; - artiflash = 4; - currentPopup = POP_None; - pendingPopup = POP_None; -} - -DSBarInfo::~DSBarInfo () -{ - Images.Uninit(); -} - -void DSBarInfo::Draw (EHudState state) -{ - DBaseStatusBar::Draw(state); - int hud = STBAR_NORMAL; - if(state == HUD_StatusBar) - { - if(script->completeBorder) //Fill the statusbar with the border before we draw. - { - FTexture *b = TexMan[gameinfo.border->b]; - R_DrawBorder(viewwindowx, viewwindowy + viewheight + b->GetHeight(), viewwindowx + viewwidth, SCREENHEIGHT); - if(screenblocks == 10) - screen->FlatFill(viewwindowx, viewwindowy + viewheight, viewwindowx + viewwidth, viewwindowy + viewheight + b->GetHeight(), b, true); - } - if(script->automapbar && automapactive) - { - hud = STBAR_AUTOMAP; - } - else - { - hud = STBAR_NORMAL; - } - } - else if(state == HUD_Fullscreen) - { - hud = STBAR_FULLSCREEN; - } - else - { - hud = STBAR_NONE; - } - bool oldhud_scale = hud_scale; - if(script->huds[hud].forceScaled) //scale the statusbar - { - SetScaled(true, true); - setsizeneeded = true; - if(script->huds[hud].fullScreenOffsets) - hud_scale = true; - } - doCommands(script->huds[hud], 0, 0, script->huds[hud].alpha); - if(CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR)) - { - if(state == HUD_StatusBar) - { - // No overlay? Lets cancel it. - if(script->huds[STBAR_INVENTORY].commands.Size() == 0) - CPlayer->inventorytics = 0; - else - doCommands(script->huds[STBAR_INVENTORY], 0, 0, script->huds[STBAR_INVENTORY].alpha); - } - else if(state == HUD_Fullscreen) - { - if(script->huds[STBAR_INVENTORYFULLSCREEN].commands.Size() == 0) - CPlayer->inventorytics = 0; - else - doCommands(script->huds[STBAR_INVENTORYFULLSCREEN], 0, 0, script->huds[STBAR_INVENTORYFULLSCREEN].alpha); - } - } - if(currentPopup != POP_None) - { - int popbar = 0; - if(currentPopup == POP_Log) - popbar = STBAR_POPUPLOG; - else if(currentPopup == POP_Keys) - popbar = STBAR_POPUPKEYS; - else if(currentPopup == POP_Status) - popbar = STBAR_POPUPSTATUS; - doCommands(script->huds[popbar], script->popups[currentPopup-1].getXOffset(), script->popups[currentPopup-1].getYOffset(), - script->popups[currentPopup-1].getAlpha(script->huds[popbar].alpha)); - } - if(script->huds[hud].forceScaled && script->huds[hud].fullScreenOffsets) - hud_scale = oldhud_scale; -} - -void DSBarInfo::NewGame () -{ - if (CPlayer != NULL) - { - AttachToPlayer (CPlayer); - } -} - -void DSBarInfo::AttachToPlayer (player_t *player) -{ - DBaseStatusBar::AttachToPlayer(player); -// MugShot.CurrentState = NULL; -} - -void DSBarInfo::SetMugShotState (const char *state_name, bool wait_till_done, bool reset) -{ - MugShot.SetState(state_name, wait_till_done, reset); -} - -void DSBarInfo::Tick () -{ - DBaseStatusBar::Tick(); - if(level.time & 1) - chainWiggle = pr_chainwiggle() & 1; - if(!script->interpolateHealth) - { - oldHealth = CPlayer->health; - } - else - { - int health = script->lowerHealthCap ? CPlayer->health : CPlayer->mo->health; - if(oldHealth > health) - { - oldHealth -= clamp((oldHealth - health), 1, script->interpolationSpeed); - } - else if(oldHealth < CPlayer->health) - { - oldHealth += clamp((health - oldHealth), 1, script->interpolationSpeed); - } - } - AInventory *armor = CPlayer->mo != NULL? CPlayer->mo->FindInventory() : NULL; - if(armor == NULL) - { - oldArmor = 0; - } - else - { - if(!script->interpolateArmor) - { - oldArmor = armor->Amount; - } - else - { - if(oldArmor > armor->Amount) - { - oldArmor -= clamp((oldArmor - armor->Amount) >> 2, 1, script->armorInterpolationSpeed); - } - else if(oldArmor < armor->Amount) - { - oldArmor += clamp((armor->Amount - oldArmor) >> 2, 1, script->armorInterpolationSpeed); - } - } - } - if(artiflash) - { - artiflash--; - } - - MugShot.Tick(CPlayer); - if(currentPopup != POP_None) - { - script->popups[currentPopup-1].tick(); - if(script->popups[currentPopup-1].opened == false && script->popups[currentPopup-1].isDoneMoving()) - { - currentPopup = pendingPopup; - if(currentPopup != POP_None) - script->popups[currentPopup-1].open(); - } - } -} - -void DSBarInfo::ReceivedWeapon(AWeapon *weapon) -{ - MugShot.bEvilGrin = true; -} - -void DSBarInfo::FlashItem(const PClass *itemtype) -{ - artiflash = 4; -} - -void DSBarInfo::ShowPop(int popnum) -{ - DBaseStatusBar::ShowPop(popnum); - if(popnum != currentPopup) - { - pendingPopup = popnum; - } - else - pendingPopup = POP_None; - if(currentPopup != POP_None) - script->popups[currentPopup-1].close(); - else - { - currentPopup = pendingPopup; - pendingPopup = POP_None; - if(currentPopup != POP_None) - script->popups[currentPopup-1].open(); - } -} - -void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset, int alpha) -{ - //prepare ammo counts - AAmmo *ammo1, *ammo2; - int ammocount1, ammocount2; - GetCurrentAmmo(ammo1, ammo2, ammocount1, ammocount2); - ABasicArmor *armor = CPlayer->mo->FindInventory(); - int health = CPlayer->mo->health; - int armorAmount = armor != NULL ? armor->Amount : 0; - if(script->interpolateHealth) - { - health = oldHealth; - } - if(script->interpolateArmor) - { - armorAmount = oldArmor; - } - for(unsigned int i = 0;i < block.commands.Size();i++) - { - SBarInfoCommand& cmd = block.commands[i]; - switch(cmd.type) //read and execute all the commands - { - case SBARINFO_DRAWSWITCHABLEIMAGE: //draw the alt image if we don't have the item else this is like a normal drawimage - { - // DrawSwitchable image allows 2 or 4 images to be supplied. - // drawAlt toggles these: - // 1 = first image - // 2 = second image - // 3 = thrid image - // 0 = last image - int drawAlt = 0; - if((cmd.flags & DRAWIMAGE_WEAPONSLOT)) //weaponslots - { - drawAlt = 1; //draw off state until we know we have something. - for (int i = 0; i < CPlayer->weapons.Slots[cmd.value].Size(); i++) - { - const PClass *weap = CPlayer->weapons.Slots[cmd.value].GetWeapon(i); - if(weap == NULL) - { - continue; - } - else if(CPlayer->mo->FindInventory(weap) != NULL) - { - drawAlt = 0; - break; - } - } - } - else if((cmd.flags & DRAWIMAGE_INVULNERABILITY)) - { - if(CPlayer->cheats&CF_GODMODE) - { - drawAlt = 1; - } - } - else if(cmd.flags & DRAWIMAGE_KEYSLOT) - { - bool found1 = false; - bool found2 = false; - drawAlt = 1; - - for(AInventory *item = CPlayer->mo->Inventory;item != NULL;item = item->Inventory) - { - if(item->IsKindOf(RUNTIME_CLASS(AKey))) - { - int keynum = static_cast(item)->KeyNumber; - - if(keynum == cmd.value) - found1 = true; - if(cmd.flags & DRAWIMAGE_SWITCHABLE_AND && keynum == cmd.special4) // two keys - found2 = true; - } - } - - if(cmd.flags & DRAWIMAGE_SWITCHABLE_AND) - { - if(found1 && found2) - drawAlt = 0; - else if(found1) - drawAlt = 2; - else if(found2) - drawAlt = 3; - } - else - { - if(found1) - drawAlt = 0; - } - } - else //check the inventory items and draw selected sprite - { - AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); - if(item == NULL || item->Amount == 0) - drawAlt = 1; - if((cmd.flags & DRAWIMAGE_SWITCHABLE_AND)) - { - item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[1])); - if((item != NULL && item->Amount != 0) && drawAlt == 0) //both - { - drawAlt = 0; - } - else if((item != NULL && item->Amount != 0) && drawAlt == 1) //2nd - { - drawAlt = 3; - } - else if((item == NULL || item->Amount == 0) && drawAlt == 0) //1st - { - drawAlt = 2; - } - } - } - if(drawAlt != 0) //draw 'off' image - { - if(cmd.special != -1 && drawAlt == 1) - DrawGraphic(Images[cmd.special], cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, !!(cmd.flags & DRAWIMAGE_TRANSLATABLE), false, !!(cmd.flags & DRAWIMAGE_OFFSET)); - else if(cmd.special2 != -1 && drawAlt == 2) - DrawGraphic(Images[cmd.special2], cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, !!(cmd.flags & DRAWIMAGE_TRANSLATABLE), false, !!(cmd.flags & DRAWIMAGE_OFFSET)); - else if(cmd.special3 != -1 && drawAlt == 3) - DrawGraphic(Images[cmd.special3], cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, !!(cmd.flags & DRAWIMAGE_TRANSLATABLE), false, (cmd.flags & DRAWIMAGE_OFFSET)); - break; - } - } - case SBARINFO_DRAWIMAGE: - { - FTexture *texture = NULL; - if((cmd.flags & DRAWIMAGE_PLAYERICON)) - texture = TexMan[CPlayer->mo->ScoreIcon]; - else if((cmd.flags & DRAWIMAGE_AMMO1)) - { - if(ammo1 != NULL) - texture = TexMan[ammo1->Icon]; - } - else if((cmd.flags & DRAWIMAGE_AMMO2)) - { - if(ammo2 != NULL) - texture = TexMan[ammo2->Icon]; - } - else if((cmd.flags & DRAWIMAGE_ARMOR)) - { - if(armor != NULL && armor->Amount != 0) - texture = TexMan(armor->Icon); - } - else if((cmd.flags & DRAWIMAGE_WEAPONICON)) - { - AWeapon *weapon = CPlayer->ReadyWeapon; - if(weapon != NULL && weapon->Icon.isValid()) - { - texture = TexMan[weapon->Icon]; - } - } - else if(cmd.flags & DRAWIMAGE_SIGIL) - { - AInventory *item = CPlayer->mo->FindInventory(); - if (item != NULL) - texture = TexMan[item->Icon]; - } - else if(cmd.flags & DRAWIMAGE_HEXENARMOR) - { - AHexenArmor *harmor = CPlayer->mo->FindInventory(); - if (harmor != NULL) - { - if (harmor->Slots[cmd.value] > 0 && harmor->SlotsIncrement[cmd.value] > 0) - { - //combine the alpha values - alpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) MIN (OPAQUE, Scale(harmor->Slots[cmd.value], OPAQUE, harmor->SlotsIncrement[cmd.value])) / (double) OPAQUE) * FRACUNIT); - texture = Images[cmd.image_index]; - } - else - break; - } - } - else if((cmd.flags & DRAWIMAGE_INVENTORYICON)) - texture = TexMan[cmd.sprite_index]; - else if(cmd.image_index >= 0) - texture = Images[cmd.image_index]; - - // if we reach here with DRAWIMAGE_HEXENARMOR set we know we want it to be dim. - DrawGraphic(texture, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, !!(cmd.flags & DRAWIMAGE_TRANSLATABLE), false, (cmd.flags & (DRAWIMAGE_OFFSET_CENTER|DRAWIMAGE_OFFSET_CENTERBOTTOM))); - break; - } - case SBARINFO_DRAWNUMBER: - { - int value = cmd.value; - if(drawingFont != cmd.font) - { - drawingFont = cmd.font; - } - if(cmd.flags & DRAWNUMBER_HEALTH) - { - value = health; - if(script->lowerHealthCap && value < 0) //health shouldn't display negatives - { - value = 0; - } - } - else if(cmd.flags & DRAWNUMBER_ARMOR) - { - value = armorAmount; - } - else if(cmd.flags & DRAWNUMBER_AMMO1) - { - value = ammocount1; - if(ammo1 == NULL) //no ammo, do not draw - { - continue; - } - } - else if(cmd.flags & DRAWNUMBER_AMMO2) - { - value = ammocount2; - if(ammo2 == NULL) //no ammo, do not draw - { - continue; - } - } - else if(cmd.flags & DRAWNUMBER_AMMO) - { - const PClass* ammo = PClass::FindClass(cmd.string[0]); - AInventory* item = CPlayer->mo->FindInventory(ammo); - if(item != NULL) - { - value = item->Amount; - } - else - { - value = 0; - } - } - else if(cmd.flags & DRAWNUMBER_AMMOCAPACITY) - { - const PClass* ammo = PClass::FindClass(cmd.string[0]); - AInventory* item = CPlayer->mo->FindInventory(ammo); - if(item != NULL) - { - value = item->MaxAmount; - } - else - { - value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount; - } - } - else if(cmd.flags & DRAWNUMBER_FRAGS) - value = CPlayer->fragcount; - else if(cmd.flags & DRAWNUMBER_KILLS) - value = level.killed_monsters; - else if(cmd.flags & DRAWNUMBER_MONSTERS) - value = level.total_monsters; - else if(cmd.flags & DRAWNUMBER_ITEMS) - value = level.found_items; - else if(cmd.flags & DRAWNUMBER_TOTALITEMS) - value = level.total_items; - else if(cmd.flags & DRAWNUMBER_SECRETS) - value = level.found_secrets; - else if(cmd.flags & DRAWNUMBER_TOTALSECRETS) - value = level.total_secrets; - else if(cmd.flags & DRAWNUMBER_ARMORCLASS) - { - AHexenArmor *harmor = CPlayer->mo->FindInventory(); - if(harmor != NULL) - { - value = harmor->Slots[0] + harmor->Slots[1] + - harmor->Slots[2] + harmor->Slots[3] + harmor->Slots[4]; - } - //Hexen counts basic armor also so we should too. - if(armor != NULL) - { - value += armor->SavePercent; - } - value /= (5*FRACUNIT); - } - else if(cmd.flags & DRAWNUMBER_GLOBALVAR) - value = ACS_GlobalVars[cmd.value]; - else if(cmd.flags & DRAWNUMBER_GLOBALARRAY) - value = ACS_GlobalArrays[cmd.value][consoleplayer]; - else if(cmd.flags & DRAWNUMBER_POWERUPTIME) - { - //Get the PowerupType and check to see if the player has any in inventory. - const PClass* powerupType = ((APowerupGiver*) GetDefaultByType(PClass::FindClass(cmd.string[0])))->PowerupType; - APowerup* powerup = (APowerup*) CPlayer->mo->FindInventory(powerupType); - if(powerup != NULL) - { - value = powerup->EffectTics / TICRATE + 1; - } - } - else if(cmd.flags & DRAWNUMBER_INVENTORY) - { - AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); - if(item != NULL) - { - value = item->Amount; - } - else - { - value = 0; - } - } - else if(cmd.flags & DRAWNUMBER_AIRTIME) - { - if(CPlayer->mo->waterlevel < 3) - value = level.airsupply/TICRATE; - else - value = clamp((CPlayer->air_finished - level.time + (TICRATE-1))/TICRATE, 0, INT_MAX); - } - bool fillzeros = !!(cmd.flags & DRAWNUMBER_FILLZEROS); - bool drawshadow = !!(cmd.flags & DRAWNUMBER_DRAWSHADOW); - EColorRange translation = cmd.translation; - if(cmd.special3 != -1 && value <= cmd.special3) //low - translation = cmd.translation2; - else if(cmd.special4 != -1 && value >= cmd.special4) //high - translation = cmd.translation3; - if((cmd.flags & DRAWNUMBER_WHENNOTZERO) && value == 0) - break; - DrawNumber(value, cmd.special, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, translation, cmd.special2, fillzeros, drawshadow); - break; - } - case SBARINFO_DRAWMUGSHOT: - { - bool xdth = false; - bool animatedgodmode = false; - if(cmd.flags & DRAWMUGSHOT_XDEATHFACE) - xdth = true; - if(cmd.flags & DRAWMUGSHOT_ANIMATEDGODMODE) - animatedgodmode = true; - int stateflags = cmd.flags & (DRAWMUGSHOT_XDEATHFACE | DRAWMUGSHOT_ANIMATEDGODMODE | DRAWMUGSHOT_DISABLEGRIN | DRAWMUGSHOT_DISABLEOUCH | DRAWMUGSHOT_DISABLEPAIN | DRAWMUGSHOT_DISABLERAMPAGE); - DrawFace(cmd.string[0], cmd.special, stateflags, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets); - break; - } - case SBARINFO_DRAWSELECTEDINVENTORY: - if(CPlayer->mo->InvSel != NULL && !(level.flags & LEVEL_NOINVENTORYBAR)) - { - int offsetflags = (cmd.flags & DRAWSELECTEDINVENTORY_CENTER) ? DRAWIMAGE_OFFSET_CENTER : 0; - offsetflags |= (cmd.flags & DRAWSELECTEDINVENTORY_CENTERBOTTOM) ? DRAWIMAGE_OFFSET_CENTERBOTTOM : 0; - if((cmd.flags & DRAWSELECTEDINVENTORY_ARTIFLASH) && artiflash) - { - DrawGraphic(Images[ARTIFLASH_OFFSET+(4-artiflash)], cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, false, CPlayer->mo->InvSel->Amount <= 0, offsetflags); - } - else - { - DrawGraphic(TexMan(CPlayer->mo->InvSel->Icon), cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, false, CPlayer->mo->InvSel->Amount <= 0, offsetflags); - } - if((cmd.flags & DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER) || CPlayer->mo->InvSel->Amount != 1) - { - if(drawingFont != cmd.font) - { - drawingFont = cmd.font; - } - DrawNumber(CPlayer->mo->InvSel->Amount, 3, cmd.sbcoord2, cmd.sbcoord3, xOffset, yOffset, alpha, block.fullScreenOffsets, cmd.translation, cmd.special4, false, !!(cmd.flags & DRAWSELECTEDINVENTORY_DRAWSHADOW)); - } - } - else if((cmd.flags & DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY)) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - break; - case SBARINFO_DRAWINVENTORYBAR: - { - bool alwaysshow = false; - bool artibox = true; - bool noarrows = false; - bool alwaysshowcounter = false; - bool vertical = false; - int bgalpha = alpha; - if((cmd.flags & DRAWINVENTORYBAR_ALWAYSSHOW)) - alwaysshow = true; - if((cmd.flags & DRAWINVENTORYBAR_NOARTIBOX)) - artibox = false; - if((cmd.flags & DRAWINVENTORYBAR_NOARROWS)) - noarrows = true; - if((cmd.flags & DRAWINVENTORYBAR_ALWAYSSHOWCOUNTER)) - alwaysshowcounter = true; - if(cmd.flags & DRAWINVENTORYBAR_TRANSLUCENT) - bgalpha = fixed_t((((double) alpha / (double) FRACUNIT) * ((double) HX_SHADOW / (double) FRACUNIT)) * FRACUNIT); - if((cmd.flags & DRAWINVENTORYBAR_VERTICAL)) - vertical = true; - if(drawingFont != cmd.font) - { - drawingFont = cmd.font; - } - DrawInventoryBar(cmd.special, cmd.value, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, alwaysshow, cmd.sbcoord2, cmd.sbcoord3, cmd.translation, artibox, noarrows, alwaysshowcounter, bgalpha, vertical); - break; - } - case SBARINFO_DRAWBAR: - { - if(cmd.image_index == -1 || Images[cmd.image_index] == NULL) - break; //don't draw anything. - bool horizontal = !!((cmd.special2 & DRAWBAR_HORIZONTAL)); - bool reverse = !!((cmd.special2 & DRAWBAR_REVERSE)); - fixed_t value = 0; - int max = 0; - if(cmd.flags == DRAWNUMBER_HEALTH) - { - value = health; - if(value < 0) //health shouldn't display negatives - { - value = 0; - } - if(!(cmd.special2 & DRAWBAR_COMPAREDEFAULTS)) - { - AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); //max comparer - if(item != NULL) - { - max = item->Amount; - } - else - { - max = 0; - } - } - else //default to the class's health - { - max = CPlayer->mo->GetMaxHealth() + CPlayer->stamina; - } - } - else if(cmd.flags == DRAWNUMBER_ARMOR) - { - value = armorAmount; - if(!((cmd.special2 & DRAWBAR_COMPAREDEFAULTS) == DRAWBAR_COMPAREDEFAULTS)) - { - AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); //max comparer - if(item != NULL) - { - max = item->Amount; - } - else - { - max = 0; - } - } - else //default to 100 - { - max = 100; - } - } - else if(cmd.flags == DRAWNUMBER_AMMO1) - { - value = ammocount1; - if(ammo1 == NULL) //no ammo, draw as empty - { - value = 0; - max = 1; - } - else - max = ammo1->MaxAmount; - } - else if(cmd.flags == DRAWNUMBER_AMMO2) - { - value = ammocount2; - if(ammo2 == NULL) //no ammo, draw as empty - { - value = 0; - max = 1; - } - else - max = ammo2->MaxAmount; - } - else if(cmd.flags == DRAWNUMBER_AMMO) - { - const PClass* ammo = PClass::FindClass(cmd.string[0]); - AInventory* item = CPlayer->mo->FindInventory(ammo); - if(item != NULL) - { - value = item->Amount; - max = item->MaxAmount; - } - else - { - value = 0; - } - } - else if(cmd.flags == DRAWNUMBER_FRAGS) - { - value = CPlayer->fragcount; - max = fraglimit; - } - else if(cmd.flags == DRAWNUMBER_KILLS) - { - value = level.killed_monsters; - max = level.total_monsters; - } - else if(cmd.flags == DRAWNUMBER_ITEMS) - { - value = level.found_items; - max = level.total_items; - } - else if(cmd.flags == DRAWNUMBER_SECRETS) - { - value = level.found_secrets; - max = level.total_secrets; - } - else if(cmd.flags == DRAWNUMBER_INVENTORY) - { - AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); - if(item != NULL) - { - value = item->Amount; - max = item->MaxAmount; - } - else - { - value = 0; - } - } - else if(cmd.flags & DRAWNUMBER_POWERUPTIME) - { - //Get the PowerupType and check to see if the player has any in inventory. - APowerupGiver* powerupGiver = (APowerupGiver*) GetDefaultByType(PClass::FindClass(cmd.string[0])); - const PClass* powerupType = powerupGiver->PowerupType; - APowerup* powerup = (APowerup*) CPlayer->mo->FindInventory(powerupType); - if(powerup != NULL && powerupType != NULL && powerupGiver != NULL) - { - value = powerup->EffectTics + 1; - if(powerupGiver->EffectTics == 0) //if 0 we need to get the default from the powerup - max = ((APowerup*) GetDefaultByType(powerupType))->EffectTics + 1; - else - max = powerupGiver->EffectTics + 1; - } - } - else if(cmd.flags & DRAWNUMBER_AIRTIME) - { - value = clamp(CPlayer->air_finished - level.time, 0, INT_MAX); - max = level.airsupply; - } - if(cmd.special3 != 0) - value = max - value; //invert since the new drawing method requires drawing the bg on the fg. - if(max != 0 && value > 0) - { - value = (value << FRACBITS) / max; - if(value > FRACUNIT) - value = FRACUNIT; - } - else if(cmd.special3 != 0 && max == 0 && value <= 0) - { - value = FRACUNIT; - } - else - { - value = 0; - } - assert(Images[cmd.image_index] != NULL); - - FTexture *fg = Images[cmd.image_index]; - FTexture *bg = (cmd.special != -1) ? Images[cmd.special] : NULL; - int x, y, w, h; - int cx, cy, cw, ch, cr, cb; - - // These still need to be caclulated for the clear call. - if(!block.fullScreenOffsets) - { - // Calc real screen coordinates for bar - x = *(cmd.x + ST_X + xOffset) << FRACBITS; - y = *(cmd.y + ST_Y + yOffset) << FRACBITS; - w = fg->GetScaledWidth() << FRACBITS; - h = fg->GetScaledHeight() << FRACBITS; - if (Scaled) - { - screen->VirtualToRealCoordsFixed(x, y, w, h, 320, 200, true); - } - x >>= FRACBITS; - y >>= FRACBITS; - w = (w + FRACUNIT/2) >> FRACBITS; - h = (h + FRACUNIT/2) >> FRACBITS; - } - else - { - ADJUST_RELCENTER(cmd.x,cmd.y,x,y) - - x += xOffset; - y += yOffset; - w = fg->GetScaledWidth(); - h = fg->GetScaledHeight(); - - if(vid_fps && x < 0 && y >= 0) - y += 10; - } - - if(cmd.special3 != 0) - { - //Draw the whole foreground - DrawGraphic(fg, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets); - } - else - { - // Draw background - if (bg != NULL && bg->GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) - { - DrawGraphic(bg, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets); - } - else - { - int clx = x; - int cly = y; - int clw = x + w; - int clh = y + h; - if(block.fullScreenOffsets) - { - clx = x < 0 ? SCREENWIDTH + x : x; - cly = y < 0 ? SCREENHEIGHT + y : y; - clw = clx+w > SCREENWIDTH ? SCREENWIDTH-clx : clx+w; - clh = cly+h > SCREENHEIGHT ? SCREENHEIGHT-cly : cly+h; - } - screen->Clear(clx, cly, clw, clh, GPalette.BlackIndex, 0); - } - } - - if(!block.fullScreenOffsets) - { - // Calc clipping rect for background - cx = *(cmd.x + ST_X + cmd.special3 + xOffset) << FRACBITS; - cy = *(cmd.y + ST_Y + cmd.special3 + yOffset) << FRACBITS; - cw = (fg->GetScaledWidth() - fg->GetScaledLeftOffset() - cmd.special3 * 2) << FRACBITS; - ch = (fg->GetScaledHeight() - fg->GetScaledTopOffset() - cmd.special3 * 2) << FRACBITS; - if (Scaled) - { - screen->VirtualToRealCoordsFixed(cx, cy, cw, ch, 320, 200, true); - } - cx >>= FRACBITS; - cy >>= FRACBITS; - cw = (cw + FRACUNIT/2) >> FRACBITS; - ch = (ch + FRACUNIT/2) >> FRACBITS; - } - else - { - ADJUST_RELCENTER(cmd.x,cmd.y,cx,cy) - - cx += cmd.special3 + xOffset; - cy += cmd.special3 + yOffset; - cw = fg->GetScaledWidth() - fg->GetScaledLeftOffset() - cmd.special3 * 2; - ch = fg->GetScaledHeight() - fg->GetScaledTopOffset() - cmd.special3 * 2; - if(vid_fps && x < 0 && y >= 0) - y += 10; - } - - if (horizontal) - { - if ((cmd.special3 != 0 && reverse) || (cmd.special3 == 0 && !reverse)) - { // left to right - cr = cx + FixedMul(cw, value); - } - else - { // right to left - cr = cx + cw; - cx += FixedMul(cw, FRACUNIT - value); - } - cb = cy + ch; - } - else - { - if ((cmd.special3 != 0 && reverse) || (cmd.special3 == 0 && !reverse)) - { // bottom to top - cb = cy + ch; - cy += FixedMul(ch, FRACUNIT - value); - } - else - { // top to bottom - cb = cy + FixedMul(ch, value); - } - cr = cx + cw; - } - // Fix the clipping for fullscreenoffsets. - if(block.fullScreenOffsets && y < 0) - { - cy = hud_scale ? SCREENHEIGHT + (cy*CleanYfac) : SCREENHEIGHT + cy; - cb = hud_scale ? SCREENHEIGHT + (cb*CleanYfac) : SCREENHEIGHT + cb; - } - else if(block.fullScreenOffsets && hud_scale) - { - cy *= CleanYfac; - cb *= CleanYfac; - } - if(block.fullScreenOffsets && x < 0) - { - cx = hud_scale ? SCREENWIDTH + (cx*CleanXfac) : SCREENWIDTH + cx; - cr = hud_scale ? SCREENWIDTH + (cr*CleanXfac) : SCREENWIDTH + cr; - } - else if(block.fullScreenOffsets && hud_scale) - { - cx *= CleanXfac; - cr *= CleanXfac; - } - - // Draw background - if(cmd.special3 != 0) - { - if (bg != NULL && bg->GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) - { - if(!block.fullScreenOffsets) - { - screen->DrawTexture(bg, x, y, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, cx, - DTA_ClipTop, cy, - DTA_ClipRight, cr, - DTA_ClipBottom, cb, - DTA_Alpha, alpha, - TAG_DONE); - } - else - { - screen->DrawTexture(bg, x, y, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, cx, - DTA_ClipTop, cy, - DTA_ClipRight, cr, - DTA_ClipBottom, cb, - DTA_Alpha, alpha, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - } - } - else - { - screen->Clear(cx, cy, cr, cb, GPalette.BlackIndex, 0); - } - } - else - { - if(!block.fullScreenOffsets) - { - screen->DrawTexture(fg, x, y, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, cx, - DTA_ClipTop, cy, - DTA_ClipRight, cr, - DTA_ClipBottom, cb, - DTA_Alpha, alpha, - TAG_DONE); - } - else - { - screen->DrawTexture(fg, x, y, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, cx, - DTA_ClipTop, cy, - DTA_ClipRight, cr, - DTA_ClipBottom, cb, - DTA_Alpha, alpha, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - } - } - break; - } - case SBARINFO_DRAWGEM: - { - int value = (cmd.flags & DRAWGEM_ARMOR) ? armorAmount : health; - int max = (cmd.flags & DRAWGEM_ARMOR) ? 100 : CPlayer->mo->GetMaxHealth() + CPlayer->stamina; - bool wiggle = false; - bool translate = !!(cmd.flags & DRAWGEM_TRANSLATABLE); - if(max != 0 || value < 0) - { - value = (value*100)/max; - if(value > 100) - value = 100; - } - else - { - value = 0; - } - value = (cmd.flags & DRAWGEM_REVERSE) ? 100 - value : value; - if(health != CPlayer->health) - { - wiggle = !!(cmd.flags & DRAWGEM_WIGGLE); - } - DrawGem(Images[cmd.special], Images[cmd.image_index], value, cmd.x, cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, cmd.special2, cmd.special3, cmd.special4+1, wiggle, translate); - break; - } - case SBARINFO_DRAWSHADER: - { - FBarShader *const shaders[4] = - { - &shader_horz_normal, &shader_horz_reverse, - &shader_vert_normal, &shader_vert_reverse - }; - bool vertical = !!(cmd.flags & DRAWSHADER_VERTICAL); - bool reverse = !!(cmd.flags & DRAWSHADER_REVERSE); - SBarInfoCoordinate x = cmd.x + xOffset; - SBarInfoCoordinate y = cmd.y + yOffset; - int w = cmd.special; - int h = cmd.special2; - if(!block.fullScreenOffsets) - { - x += ST_X; - y += ST_Y; - if(Scaled) - { - int tmpX = *x; - int tmpY = *y; - screen->VirtualToRealCoordsInt(tmpX, tmpY, w, h, 320, 200, true); - x.SetCoord(tmpX); - y.SetCoord(tmpY); - } - } - else - { - if(vid_fps && *x < 0 && *y >= 0) - y += 10; - } - if(!block.fullScreenOffsets) - { - screen->DrawTexture (shaders[(vertical << 1) + reverse], *x, *y, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_Alpha, alpha, - DTA_AlphaChannel, true, - DTA_FillColor, 0, - TAG_DONE); - } - else - { - int rx, ry; - ADJUST_RELCENTER(x,y,rx,ry) - - screen->DrawTexture (shaders[(vertical << 1) + reverse], rx, ry, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_Alpha, alpha, - DTA_AlphaChannel, true, - DTA_FillColor, 0, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - } - break; - } - case SBARINFO_DRAWSTRING: - if(drawingFont != cmd.font) - { - drawingFont = cmd.font; - } - DrawString(cmd.string[0], cmd.x - drawingFont->StringWidth(cmd.string[0]), cmd.y, xOffset, yOffset, alpha, block.fullScreenOffsets, cmd.translation, cmd.special); - break; - case SBARINFO_DRAWKEYBAR: - { - bool vertical = !!(cmd.flags & DRAWKEYBAR_VERTICAL); - AInventory *item = CPlayer->mo->Inventory; - if(item == NULL) - break; - int slotOffset = 0; - int rowOffset = 0; - int rowWidth = 0; - for(int i = 0;i < cmd.value+cmd.special2;i++) - { - while(!item->Icon.isValid() || !item->IsKindOf(RUNTIME_CLASS(AKey))) - { - item = item->Inventory; - if(item == NULL) - goto FinishDrawKeyBar; - } - if(i >= cmd.special2) //Should we start drawing? - { - if(!vertical) - { - DrawGraphic(TexMan[item->Icon], cmd.x+slotOffset, cmd.y+rowOffset, xOffset, yOffset, alpha, block.fullScreenOffsets); - rowWidth = cmd.special4 == -1 ? TexMan[item->Icon]->GetScaledHeight()+2 : cmd.special4; - } - else - { - DrawGraphic(TexMan[item->Icon], cmd.x+rowOffset, cmd.y+slotOffset, xOffset, yOffset, alpha, block.fullScreenOffsets); - rowWidth = cmd.special4 == -1 ? TexMan[item->Icon]->GetScaledWidth()+2 : cmd.special4; - } - - // If cmd.special is -1 then the slot size is auto detected - if(cmd.special == -1) - { - if(!vertical) - slotOffset += TexMan[item->Icon]->GetScaledWidth() + 2; - else - slotOffset += TexMan[item->Icon]->GetScaledHeight() + 2; - } - else - slotOffset += cmd.special; - - if(cmd.special3 > 0 && (i % cmd.special3 == cmd.special3-1)) - { - if(cmd.flags & DRAWKEYBAR_REVERSEROWS) - rowOffset -= rowWidth; - else - rowOffset += rowWidth; - rowWidth = 0; - slotOffset = 0; - } - } - - item = item->Inventory; - if(item == NULL) - break; - } - FinishDrawKeyBar: - break; - } - case SBARINFO_GAMEMODE: - if(((cmd.flags & GAMETYPE_SINGLEPLAYER) && !multiplayer) || - ((cmd.flags & GAMETYPE_DEATHMATCH) && deathmatch) || - ((cmd.flags & GAMETYPE_COOPERATIVE) && multiplayer && !deathmatch) || - ((cmd.flags & GAMETYPE_TEAMGAME) && teamplay)) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - break; - case SBARINFO_PLAYERCLASS: - { - if(CPlayer->cls == NULL) break; //No class so we can not continue - int spawnClass = CPlayer->cls->ClassIndex; - if(cmd.special == spawnClass || cmd.special2 == spawnClass || cmd.special3 == spawnClass) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - break; - } - case SBARINFO_ASPECTRATIO: - if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == cmd.value) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - break; - case SBARINFO_ISSELECTED: - if(CPlayer->ReadyWeapon != NULL) - { - const PClass *weapon1 = PClass::FindClass(cmd.string[0]); - const PClass *weapon2 = PClass::FindClass(cmd.string[1]); - if(weapon2 != NULL) - { - if((cmd.flags & SBARINFOEVENT_NOT) && (weapon1 != CPlayer->ReadyWeapon->GetClass() && weapon2 != CPlayer->ReadyWeapon->GetClass())) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - else if(!(cmd.flags & SBARINFOEVENT_NOT) && (weapon1 == CPlayer->ReadyWeapon->GetClass() || weapon2 == CPlayer->ReadyWeapon->GetClass())) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - else - { - if(!(cmd.flags & SBARINFOEVENT_NOT) && weapon1 == CPlayer->ReadyWeapon->GetClass()) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - else if((cmd.flags & SBARINFOEVENT_NOT) && weapon1 != CPlayer->ReadyWeapon->GetClass()) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - } - break; - case SBARINFO_USESAMMO: - if ((CPlayer->ReadyWeapon != NULL && (CPlayer->ReadyWeapon->AmmoType1 != NULL || CPlayer->ReadyWeapon->AmmoType2 != NULL)) ^ - !!(cmd.flags & SBARINFOEVENT_NOT)) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - break; - case SBARINFO_USESSECONDARYAMMO: - if((CPlayer->ReadyWeapon != NULL && CPlayer->ReadyWeapon->AmmoType2 != NULL && CPlayer->ReadyWeapon->AmmoType2 != CPlayer->ReadyWeapon->AmmoType1 && !(cmd.flags & SBARINFOEVENT_NOT)) || - ((CPlayer->ReadyWeapon == NULL || CPlayer->ReadyWeapon->AmmoType2 == NULL || CPlayer->ReadyWeapon->AmmoType2 == CPlayer->ReadyWeapon->AmmoType1) && cmd.flags & SBARINFOEVENT_NOT)) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - break; - case SBARINFO_HASWEAPONPIECE: - { - AInventory *inv; - AWeaponHolder *hold; - const PClass *weapon = PClass::FindClass(cmd.string[0]); - for(inv = CPlayer->mo->Inventory;inv != NULL;inv=inv->Inventory) - { - if(inv->IsKindOf(RUNTIME_CLASS(AWeaponHolder))) - { - hold = static_cast(inv); - if(hold->PieceWeapon == weapon) - { - if(hold->PieceMask & (1 << (cmd.value-1))) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - break; - } - } - } - break; - } - case SBARINFO_INVENTORYBARNOTVISIBLE: - if(CPlayer->inventorytics <= 0 || (level.flags & LEVEL_NOINVENTORYBAR)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - break; - case SBARINFO_WEAPONAMMO: - if(CPlayer->ReadyWeapon != NULL) - { - const PClass *AmmoType1 = CPlayer->ReadyWeapon->AmmoType1; - const PClass *AmmoType2 = CPlayer->ReadyWeapon->AmmoType2; - const PClass *IfAmmo1 = PClass::FindClass(cmd.string[0]); - const PClass *IfAmmo2 = (cmd.flags & SBARINFOEVENT_OR) || (cmd.flags & SBARINFOEVENT_AND) ? - PClass::FindClass(cmd.string[1]) : NULL; - bool usesammo1 = (AmmoType1 != NULL); - bool usesammo2 = (AmmoType2 != NULL); - if(!(cmd.flags & SBARINFOEVENT_NOT) && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble. - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - break; - } - //Or means only 1 ammo type needs to match and means both need to match. - if((cmd.flags & SBARINFOEVENT_OR) || (cmd.flags & SBARINFOEVENT_AND)) - { - bool match1 = ((usesammo1 && (AmmoType1 == IfAmmo1 || AmmoType1 == IfAmmo2)) || !usesammo1); - bool match2 = ((usesammo2 && (AmmoType2 == IfAmmo1 || AmmoType2 == IfAmmo2)) || !usesammo2); - if(((cmd.flags & SBARINFOEVENT_OR) && (match1 || match2)) || ((cmd.flags & SBARINFOEVENT_AND) && (match1 && match2))) - { - if(!(cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - else if(cmd.flags & SBARINFOEVENT_NOT) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - } - else //Every thing here could probably be one long if statement but then it would be more confusing. - { - if((usesammo1 && (AmmoType1 == IfAmmo1)) || (usesammo2 && (AmmoType2 == IfAmmo1))) - { - if(!(cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - else if(cmd.flags & SBARINFOEVENT_NOT) - { - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - } - } - break; - case SBARINFO_ININVENTORY: - { - AInventory *item1 = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); - AInventory *item2 = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[1])); - if (item1 != NULL && cmd.special2 > 0 && item1->Amount < cmd.special2) item1 = NULL; - if (item2 != NULL && cmd.special3 > 0 && item2->Amount < cmd.special3) item2 = NULL; - if(cmd.flags & SBARINFOEVENT_AND) - { - if((item1 != NULL && item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - else if((item1 == NULL || item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - else if(cmd.flags & SBARINFOEVENT_OR) - { - if((item1 != NULL || item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - else if((item1 == NULL && item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - } - else if((item1 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - else if((item1 == NULL) && (cmd.flags & SBARINFOEVENT_NOT)) - doCommands(cmd.subBlock, xOffset, yOffset, alpha); - break; - } - } - } -} - -//draws an image with the specified flags -void DSBarInfo::DrawGraphic(FTexture* texture, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, - bool translate, bool dim, int offsetflags) //flags -{ - if (texture == NULL) - return; - - if(offsetflags & DRAWIMAGE_OFFSET_CENTER) - { - x -= (texture->GetScaledWidth()/2)-texture->LeftOffset; - y -= (texture->GetScaledHeight()/2)-texture->TopOffset; - } - - x += xOffset; - y += yOffset; - int w, h; - if(!fullScreenOffsets) - { - // I'll handle the conversion from fixed to int myself for more control - fixed_t fx = (x + ST_X).Coordinate() << FRACBITS; - fixed_t fy = (y + ST_Y).Coordinate() << FRACBITS; - fixed_t fw = texture->GetScaledWidth() << FRACBITS; - fixed_t fh = texture->GetScaledHeight() << FRACBITS; - if(Scaled) - screen->VirtualToRealCoordsFixed(fx, fy, fw, fh, 320, 200, true); - // Round to nearest - w = (fw + (FRACUNIT>>1)) >> FRACBITS; - h = (fh + (FRACUNIT>>1)) >> FRACBITS; - screen->DrawTexture(texture, (fx >> FRACBITS), (fy >> FRACBITS), - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_Translation, translate ? getTranslation() : 0, - DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, - DTA_CenterBottomOffset, (offsetflags & DRAWIMAGE_OFFSET_CENTERBOTTOM), - DTA_Alpha, alpha, - TAG_DONE); - } - else - { - int rx, ry; - ADJUST_RELCENTER(x,y,rx,ry) - - w = texture->GetScaledWidth(); - h = texture->GetScaledHeight(); - if(vid_fps && rx < 0 && ry >= 0) - ry += 10; - screen->DrawTexture(texture, rx, ry, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_Translation, translate ? getTranslation() : 0, - DTA_ColorOverlay, dim ? DIM_OVERLAY : 0, - DTA_CenterBottomOffset, (offsetflags & DRAWIMAGE_OFFSET_CENTERBOTTOM), - DTA_HUDRules, HUD_Normal, - DTA_Alpha, alpha, - TAG_DONE); - } -} - -void DSBarInfo::DrawString(const char* str, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing, bool drawshadow) -{ - x += spacing; - int ax = *x; - int ay = *y; - if(fullScreenOffsets) - { - ADJUST_RELCENTER(x,y,ax,ay) - } - while(*str != '\0') - { - if(*str == ' ') - { - ax += drawingFont->GetSpaceWidth(); - str++; - continue; - } - int width; - if(script->spacingCharacter == '\0') //No monospace? - width = drawingFont->GetCharWidth((int) *str); - else - width = drawingFont->GetCharWidth((int) script->spacingCharacter); - FTexture* character = drawingFont->GetChar((int) *str, &width); - if(character == NULL) //missing character. - { - str++; - continue; - } - if(script->spacingCharacter == '\0') //If we are monospaced lets use the offset - ax += (character->LeftOffset+1); //ignore x offsets since we adapt to character size - - int rx, ry, rw, rh; - rx = ax + xOffset; - ry = ay + yOffset; - rw = character->GetScaledWidth(); - rh = character->GetScaledHeight(); - if(!fullScreenOffsets) - { - rx += ST_X; - ry += ST_Y; - if(Scaled) - screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true); - } - else - { - if(vid_fps && ax < 0 && ay >= 0) - ry += 10; - } - if(drawshadow) - { - int salpha = fixed_t(((double) alpha / (double) FRACUNIT) * ((double) HR_SHADOW / (double) FRACUNIT) * FRACUNIT); - if(!fullScreenOffsets) - { - screen->DrawTexture(character, rx+2, ry+2, - DTA_DestWidth, rw, - DTA_DestHeight, rh, - DTA_Alpha, salpha, - DTA_FillColor, 0, - TAG_DONE); - } - else - { - screen->DrawTexture(character, rx+2, ry+2, - DTA_DestWidth, rw, - DTA_DestHeight, rh, - DTA_Alpha, salpha, - DTA_HUDRules, HUD_Normal, - DTA_FillColor, 0, - TAG_DONE); - } - } - if(!fullScreenOffsets) - { - screen->DrawTexture(character, rx, ry, - DTA_DestWidth, rw, - DTA_DestHeight, rh, - DTA_Translation, drawingFont->GetColorTranslation(translation), - DTA_Alpha, alpha, - TAG_DONE); - } - else - { - screen->DrawTexture(character, rx, ry, - DTA_DestWidth, rw, - DTA_DestHeight, rh, - DTA_Translation, drawingFont->GetColorTranslation(translation), - DTA_Alpha, alpha, - DTA_HUDRules, HUD_Normal, - TAG_DONE); - } - if(script->spacingCharacter == '\0') - ax += width + spacing - (character->LeftOffset+1); - else //width gets changed at the call to GetChar() - ax += drawingFont->GetCharWidth((int) script->spacingCharacter) + spacing; - str++; - } -} - -//draws the specified number up to len digits -void DSBarInfo::DrawNumber(int num, int len, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, EColorRange translation, int spacing, bool fillzeros, bool drawshadow) -{ - FString value; - // 10^9 is a largest we can hold in a 32-bit int. So if we go any larger we have to toss out the positions limit. - int maxval = len <= 9 ? (int) ceil(pow(10., len))-1 : INT_MAX; - if(!fillzeros || len == 1) - num = clamp(num, -maxval, maxval); - else //The community wanted negatives to take the last digit, but we can only do this if there is room - num = clamp(num, len <= 9 ? (int) -(ceil(pow(10., len-1))-1) : INT_MIN, maxval); - value.Format("%d", num); - if(fillzeros) - { - if(num < 0) //We don't want the negative just yet - value.Format("%d", -num); - while(fillzeros && value.Len() < (unsigned int) len) - { - if(num < 0 && value.Len() == (unsigned int) (len-1)) - value.Insert(0, "-"); - else - value.Insert(0, "0"); - } - } - if(script->spacingCharacter == '\0') - x -= int(drawingFont->StringWidth(value)+(spacing * value.Len())); - else //monospaced, so just multiplay the character size - x -= int((drawingFont->GetCharWidth((int) script->spacingCharacter) + spacing) * value.Len()); - DrawString(value, x, y, xOffset, yOffset, alpha, fullScreenOffsets, translation, spacing, drawshadow); -} - -//draws the mug shot -void DSBarInfo::DrawFace(const char *defaultFace, int accuracy, int stateflags, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets) -{ - FTexture *face = MugShot.GetFace(CPlayer, defaultFace, accuracy, stateflags); - if (face != NULL) - { - DrawGraphic(face, x, y, xOffset, yOffset, alpha, fullScreenOffsets); - } -} - -void DSBarInfo::DrawInventoryBar(int type, int num, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, bool alwaysshow, - SBarInfoCoordinate counterx, SBarInfoCoordinate countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter, int bgalpha, bool vertical) -{ //yes, there is some Copy & Paste here too - AInventory *item; - int i; - int spacing = 0; - if(!vertical) - spacing = (type != GAME_Strife) ? Images[invBarOffset + imgARTIBOX]->GetScaledWidth() + 1 : Images[invBarOffset + imgCURSOR]->GetScaledWidth() - 1; - else - spacing = (type != GAME_Strife) ? Images[invBarOffset + imgARTIBOX]->GetScaledHeight() + 1 : Images[invBarOffset + imgCURSOR]->GetScaledHeight() - 1; - - // If the player has no artifacts, don't draw the bar - CPlayer->mo->InvFirst = ValidateInvFirst(num); - if(CPlayer->mo->InvFirst != NULL || alwaysshow) - { - for(item = CPlayer->mo->InvFirst, i = 0; item != NULL && i < num; item = item->NextInv(), ++i) - { - SBarInfoCoordinate rx = x + (!vertical ? i*spacing : 0); - SBarInfoCoordinate ry = y + (vertical ? i*spacing : 0); - if(drawArtiboxes) - { - DrawGraphic(Images[invBarOffset + imgARTIBOX], rx, ry, xOffset, yOffset, bgalpha, fullScreenOffsets); - } - if(type != GAME_Strife) //Strife draws the cursor before the icons - DrawGraphic(TexMan(item->Icon), rx, ry, xOffset, yOffset, alpha, fullScreenOffsets, false, item->Amount <= 0); - if(item == CPlayer->mo->InvSel) - { - if(type == GAME_Heretic) - { - DrawGraphic(Images[invBarOffset + imgSELECTBOX], rx, ry+29, xOffset, yOffset, alpha, fullScreenOffsets); - } - else if(type == GAME_Hexen) - { - DrawGraphic(Images[invBarOffset + imgSELECTBOX], rx, ry-1, xOffset, yOffset, alpha, fullScreenOffsets); - } - else if(type == GAME_Strife) - { - DrawGraphic(Images[invBarOffset + imgCURSOR], rx-6, ry-2, xOffset, yOffset, alpha, fullScreenOffsets); - } - else - { - DrawGraphic(Images[invBarOffset + imgSELECTBOX], rx, ry, xOffset, yOffset, alpha, fullScreenOffsets); - } - } - if(type == GAME_Strife) - DrawGraphic(TexMan(item->Icon), rx, ry, xOffset, yOffset, alpha, fullScreenOffsets, false, item->Amount <= 0); - if(alwaysshowcounter || item->Amount != 1) - { - DrawNumber(item->Amount, 3, counterx+(!vertical ? i*spacing : 0), countery+(vertical ? i*spacing : 0), xOffset, yOffset, alpha, fullScreenOffsets, translation); - } - } - for (; i < num && drawArtiboxes; ++i) - { - DrawGraphic(Images[invBarOffset + imgARTIBOX], x + (!vertical ? (i*spacing) : 0), y + (vertical ? (i*spacing) : 0), xOffset, yOffset, bgalpha, fullScreenOffsets); - } - // Is there something to the left? - if (!noArrows && CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) - { - int offset = type != GAME_Strife ? -12 : 14; - DrawGraphic(Images[!(gametic & 4) ? - invBarOffset + imgINVLFGEM1 : invBarOffset + imgINVLFGEM2], x + (!vertical ? offset : 0), y + (vertical ? offset : 0), xOffset, yOffset, alpha, fullScreenOffsets); - } - // Is there something to the right? - if (!noArrows && item != NULL) - { - int offset = type != GAME_Strife ? num*31+2 : num*35-4; - DrawGraphic(Images[!(gametic & 4) ? - invBarOffset + imgINVRTGEM1 : invBarOffset + imgINVRTGEM2], x + (!vertical ? offset : 0), y + (vertical ? offset : 0), xOffset, yOffset, alpha, fullScreenOffsets); - } - } -} - -//draws heretic/hexen style life gems -void DSBarInfo::DrawGem(FTexture* chain, FTexture* gem, int value, SBarInfoCoordinate x, SBarInfoCoordinate y, int xOffset, int yOffset, int alpha, bool fullScreenOffsets, int padleft, int padright, int chainsize, - bool wiggle, bool translate) -{ - if(chain == NULL) - return; - if(value > 100) - value = 100; - else if(value < 0) - value = 0; - if(wiggle) - y += chainWiggle; - int chainWidth = chain->GetWidth(); - int offset = (int) (((double) (chainWidth-padleft-padright)/100)*value); - DrawGraphic(chain, x+(offset%chainsize), y, xOffset, yOffset, alpha, fullScreenOffsets); - if(gem != NULL) - DrawGraphic(gem, x+padleft+offset, y, xOffset, yOffset, alpha, fullScreenOffsets, translate); -} - -FRemapTable* DSBarInfo::getTranslation() -{ - if(gameinfo.gametype & GAME_Raven) - return translationtables[TRANSLATION_PlayersExtra][int(CPlayer - players)]; - return translationtables[TRANSLATION_Players][int(CPlayer - players)]; -} - -IMPLEMENT_CLASS(DSBarInfo); - -DBaseStatusBar *CreateCustomStatusBar (int script) -{ - if(SBarInfoScript[script] == NULL) - I_FatalError("Tried to create a status bar with no script!"); - return new DSBarInfo(SBarInfoScript[script]); -} - -DBaseStatusBar *CreateDoomStatusBar () -{ - return new DSBarInfo(SBarInfoScript[1]); -} diff --git a/src/g_shared/sbarinfo_parser.cpp b/src/g_shared/sbarinfo_parser.cpp deleted file mode 100644 index b6130826b6..0000000000 --- a/src/g_shared/sbarinfo_parser.cpp +++ /dev/null @@ -1,1622 +0,0 @@ -/* -** sbarinfo_parser.cpp -** -** Reads custom status bar definitions. -** -**--------------------------------------------------------------------------- -** 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 "doomtype.h" -#include "doomstat.h" -#include "sc_man.h" -#include "v_font.h" -#include "w_wad.h" -#include "d_player.h" -#include "sbar.h" -#include "sbarinfo.h" -#include "templates.h" -#include "m_random.h" -#include "gi.h" -#include "i_system.h" -#include "g_level.h" -#include "p_acs.h" - -SBarInfo *SBarInfoScript[2] = {NULL,NULL}; - -static const char *SBarInfoTopLevel[] = -{ - "base", - "height", - "interpolatehealth", - "interpolatearmor", - "completeborder", - "monospacefonts", - "lowerhealthcap", - "statusbar", - "mugshot", - "createpopup", - NULL -}; - -static const char *StatusBars[] = -{ - "none", - "fullscreen", - "normal", - "automap", - "inventory", - "inventoryfullscreen", - "popuplog", - "popupkeys", - "popupstatus", - NULL -}; - -static const char *SBarInfoRoutineLevel[] = -{ - "drawimage", - "drawnumber", - "drawswitchableimage", - "drawmugshot", - "drawselectedinventory", - "drawinventorybar", - "drawbar", - "drawgem", - "drawshader", - "drawstring", - "drawkeybar", - "gamemode", - "playerclass", - "aspectratio", - "isselected", - "usesammo", - "usessecondaryammo", - "hasweaponpiece", - "inventorybarnotvisible", - "weaponammo", //event - "ininventory", - NULL -}; - -static void FreeSBarInfoScript() -{ - for(int i = 0;i < 2;i++) - { - if (SBarInfoScript[i] != NULL) - { - delete SBarInfoScript[i]; - SBarInfoScript[i] = NULL; - } - } -} - -void SBarInfo::Load() -{ - if(gameinfo.statusbar.IsNotEmpty()) - { - int lump = Wads.CheckNumForFullName(gameinfo.statusbar, true); - if(lump != -1) - { - Printf ("ParseSBarInfo: Loading default status bar definition.\n"); - if(SBarInfoScript[SCRIPT_DEFAULT] == NULL) - SBarInfoScript[SCRIPT_DEFAULT] = new SBarInfo(lump); - else - SBarInfoScript[SCRIPT_DEFAULT]->ParseSBarInfo(lump); - } - } - - if(Wads.CheckNumForName("SBARINFO") != -1) - { - Printf ("ParseSBarInfo: Loading custom status bar definition.\n"); - int lastlump, lump; - lastlump = 0; - while((lump = Wads.FindLump("SBARINFO", &lastlump)) != -1) - { - if(SBarInfoScript[SCRIPT_CUSTOM] == NULL) - SBarInfoScript[SCRIPT_CUSTOM] = new SBarInfo(lump); - else //We now have to load multiple SBarInfo Lumps so the 2nd time we need to use this method instead. - SBarInfoScript[SCRIPT_CUSTOM]->ParseSBarInfo(lump); - } - } - atterm(FreeSBarInfoScript); -} - -//SBarInfo Script Reader -void SBarInfo::ParseSBarInfo(int lump) -{ - gameType = gameinfo.gametype; - bool baseSet = false; - FScanner sc(lump); - sc.SetCMode(true); - while(sc.CheckToken(TK_Identifier) || sc.CheckToken(TK_Include)) - { - if(sc.TokenType == TK_Include) - { - sc.MustGetToken(TK_StringConst); - int lump = Wads.CheckNumForFullName(sc.String, true); - if (lump == -1) - sc.ScriptError("Lump '%s' not found", sc.String); - ParseSBarInfo(lump); - continue; - } - switch(sc.MustMatchString(SBarInfoTopLevel)) - { - case SBARINFO_BASE: - baseSet = true; - if(!sc.CheckToken(TK_None)) - sc.MustGetToken(TK_Identifier); - if(sc.Compare("Doom")) - { - int lump = Wads.CheckNumForFullName("sbarinfo/doom.txt", true); - if(lump == -1) - sc.ScriptError("Standard Doom Status Bar not found."); - ParseSBarInfo(lump); - } - else if(sc.Compare("Heretic")) - gameType = GAME_Heretic; - else if(sc.Compare("Hexen")) - gameType = GAME_Hexen; - else if(sc.Compare("Strife")) - gameType = GAME_Strife; - else if(sc.Compare("None")) - gameType = GAME_Any; - else - sc.ScriptError("Bad game name: %s", sc.String); - sc.MustGetToken(';'); - break; - case SBARINFO_HEIGHT: - sc.MustGetToken(TK_IntConst); - this->height = sc.Number; - sc.MustGetToken(';'); - break; - case SBARINFO_INTERPOLATEHEALTH: //mimics heretics interpolated health values. - if(sc.CheckToken(TK_True)) - { - interpolateHealth = true; - } - else - { - sc.MustGetToken(TK_False); - interpolateHealth = false; - } - if(sc.CheckToken(',')) //speed param - { - sc.MustGetToken(TK_IntConst); - this->interpolationSpeed = sc.Number; - } - sc.MustGetToken(';'); - break; - case SBARINFO_INTERPOLATEARMOR: //Since interpolatehealth is such a popular command - if(sc.CheckToken(TK_True)) - { - interpolateArmor = true; - } - else - { - sc.MustGetToken(TK_False); - interpolateArmor = false; - } - if(sc.CheckToken(',')) //speed - { - sc.MustGetToken(TK_IntConst); - this->armorInterpolationSpeed = sc.Number; - } - sc.MustGetToken(';'); - break; - case SBARINFO_COMPLETEBORDER: //draws the border instead of an HOM - if(sc.CheckToken(TK_True)) - { - completeBorder = true; - } - else - { - sc.MustGetToken(TK_False); - completeBorder = false; - } - sc.MustGetToken(';'); - break; - case SBARINFO_MONOSPACEFONTS: - if(sc.CheckToken(TK_True)) - { - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - spacingCharacter = sc.String[0]; - } - else - { - sc.MustGetToken(TK_False); - spacingCharacter = '\0'; - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); //Don't tell anyone we're just ignoring this ;) - } - sc.MustGetToken(';'); - break; - case SBARINFO_LOWERHEALTHCAP: - if(sc.CheckToken(TK_False)) - { - lowerHealthCap = false; - } - else - { - sc.MustGetToken(TK_True); - lowerHealthCap = true; - } - sc.MustGetToken(';'); - break; - case SBARINFO_STATUSBAR: - { - if(!baseSet) //If the user didn't explicitly define a base, do so now. - gameType = GAME_Any; - int barNum = 0; - if(!sc.CheckToken(TK_None)) - { - sc.MustGetToken(TK_Identifier); - barNum = sc.MustMatchString(StatusBars); - } - this->huds[barNum] = SBarInfoBlock(); - if(sc.CheckToken(',')) - { - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("forcescaled")) - { - this->huds[barNum].forceScaled = true; - } - else if(sc.Compare("fullscreenoffsets")) - { - this->huds[barNum].fullScreenOffsets = true; - } - else - { - sc.ScriptError("Unkown flag '%s'.", sc.String); - } - if(!sc.CheckToken('|') && !sc.CheckToken(',')) - goto FinishStatusBar; //No more args so we must skip over anything else and go to the end. - } - sc.MustGetToken(TK_FloatConst); - this->huds[barNum].alpha = fixed_t(FRACUNIT * sc.Float); - } - FinishStatusBar: - sc.MustGetToken('{'); - if(barNum == STBAR_AUTOMAP) - { - automapbar = true; - } - ParseSBarInfoBlock(sc, this->huds[barNum]); - break; - } - case SBARINFO_MUGSHOT: - { - sc.MustGetToken(TK_StringConst); - FMugShotState state(sc.String); - if(sc.CheckToken(',')) //first loop must be a comma - { - do - { - sc.MustGetToken(TK_Identifier); - if(sc.Compare("health")) - state.bUsesLevels = true; - else if(sc.Compare("health2")) - state.bUsesLevels = state.bHealth2 = true; - else if(sc.Compare("healthspecial")) - state.bUsesLevels = state.bHealthSpecial = true; - else if(sc.Compare("directional")) - state.bDirectional = true; - else - sc.ScriptError("Unknown MugShot state flag '%s'.", sc.String); - } - while(sc.CheckToken(',') || sc.CheckToken('|')); - } - ParseMugShotBlock(sc, state); - int index; - if((index = FindMugShotStateIndex(state.State)) != -1) //We already had this state, remove the old one. - { - MugShotStates.Delete(index); - } - MugShotStates.Push(state); - break; - } - case SBARINFO_CREATEPOPUP: - { - int pop = 0; - sc.MustGetToken(TK_Identifier); - if(sc.Compare("log")) - pop = 0; - else if(sc.Compare("keys")) - pop = 1; - else if(sc.Compare("status")) - pop = 2; - else - sc.ScriptError("Unkown popup: '%s'", sc.String); - Popup &popup = popups[pop]; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - popup.width = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - popup.height = sc.Number; - sc.MustGetToken(','); - if(!sc.CheckToken(TK_None)) - { - sc.MustGetToken(TK_Identifier); - if(sc.Compare("slideinbottom")) - { - popup.transition = TRANSITION_SLIDEINBOTTOM; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - popup.speed = sc.Number; - } - else if(sc.Compare("fade")) - { - popup.transition = TRANSITION_FADE; - sc.MustGetToken(','); - sc.MustGetToken(TK_FloatConst); - popup.speed = fixed_t(FRACUNIT * (1.0 / (35.0 * sc.Float))); - sc.MustGetToken(','); - sc.MustGetToken(TK_FloatConst); - popup.speed2 = fixed_t(FRACUNIT * (1.0 / (35.0 * sc.Float))); - } - else - sc.ScriptError("Unkown transition type: '%s'", sc.String); - } - popup.init(); - sc.MustGetToken(';'); - break; - } - } - } -} - -void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block) -{ - while(sc.CheckToken(TK_Identifier)) - { - SBarInfoCommand cmd; - - switch(cmd.type = sc.MustMatchString(SBarInfoRoutineLevel)) - { - case SBARINFO_DRAWSWITCHABLEIMAGE: - sc.MustGetToken(TK_Identifier); - if(sc.Compare("weaponslot")) - { - cmd.flags = DRAWIMAGE_WEAPONSLOT; - sc.MustGetToken(TK_IntConst); - cmd.value = sc.Number; - } - else if(sc.Compare("invulnerable")) - { - cmd.flags = DRAWIMAGE_INVULNERABILITY; - } - else if(sc.Compare("keyslot")) - { - cmd.flags = DRAWIMAGE_KEYSLOT; - sc.MustGetToken(TK_IntConst); - cmd.value = sc.Number; - } - else - { - cmd.setString(sc, sc.String, 0); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - } - if(sc.CheckToken(TK_AndAnd)) - { - cmd.flags |= DRAWIMAGE_SWITCHABLE_AND; - if(cmd.flags & DRAWIMAGE_KEYSLOT) - { - sc.MustGetToken(TK_IntConst); - cmd.special4 = sc.Number; - } - else - { - sc.MustGetToken(TK_Identifier); - cmd.setString(sc, sc.String, 1); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - } - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - cmd.special = newImage(sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - cmd.special2 = newImage(sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - cmd.special3 = newImage(sc.String); - sc.MustGetToken(','); - } - else - { - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - cmd.special = newImage(sc.String); - sc.MustGetToken(','); - } - case SBARINFO_DRAWIMAGE: - { - bool getImage = true; - if(sc.CheckToken(TK_Identifier)) - { - getImage = false; - if(sc.Compare("playericon")) - cmd.flags |= DRAWIMAGE_PLAYERICON; - else if(sc.Compare("ammoicon1")) - cmd.flags |= DRAWIMAGE_AMMO1; - else if(sc.Compare("ammoicon2")) - cmd.flags |= DRAWIMAGE_AMMO2; - else if(sc.Compare("armoricon")) - cmd.flags |= DRAWIMAGE_ARMOR; - else if(sc.Compare("weaponicon")) - cmd.flags |= DRAWIMAGE_WEAPONICON; - else if(sc.Compare("sigil")) - cmd.flags |= DRAWIMAGE_SIGIL; - else if(sc.Compare("hexenarmor")) - { - cmd.flags = DRAWIMAGE_HEXENARMOR; - sc.MustGetToken(TK_Identifier); - if(sc.Compare("armor")) - cmd.value = 0; - else if(sc.Compare("shield")) - cmd.value = 1; - else if(sc.Compare("helm")) - cmd.value = 2; - else if(sc.Compare("amulet")) - cmd.value = 3; - else - sc.ScriptError("Unkown armor type: '%s'", sc.String); - sc.MustGetToken(','); - getImage = true; - } - else if(sc.Compare("translatable")) - { - cmd.flags |= DRAWIMAGE_TRANSLATABLE; - getImage = true; - } - else - { - //sc.CheckToken(TK_Identifier); - cmd.flags |= DRAWIMAGE_INVENTORYICON; - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of Inventory - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - cmd.sprite_index = ((AInventory *)GetDefaultByType(item))->Icon; - cmd.image_index = -1; - } - } - if(getImage) - { - sc.MustGetToken(TK_StringConst); - cmd.image_index = newImage(sc.String); - cmd.sprite_index.SetInvalid(); - } - sc.MustGetToken(','); - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - if(sc.CheckToken(',')) - { - sc.MustGetToken(TK_Identifier); - if(sc.Compare("center")) - cmd.flags |= DRAWIMAGE_OFFSET_CENTER; - else if(sc.Compare("centerbottom")) - cmd.flags |= DRAWIMAGE_OFFSET_CENTERBOTTOM; - else - sc.ScriptError("'%s' is not a valid alignment.", sc.String); - } - sc.MustGetToken(';'); - break; - } - case SBARINFO_DRAWNUMBER: - cmd.special4 = cmd.special3 = -1; - sc.MustGetToken(TK_IntConst); - cmd.special = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); - cmd.font = V_GetFont(sc.String); - if(cmd.font == NULL) - sc.ScriptError("Unknown font '%s'.", sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); - cmd.translation = this->GetTranslation(sc, sc.String); - sc.MustGetToken(','); - if(sc.CheckToken(TK_IntConst)) - { - cmd.value = sc.Number; - sc.MustGetToken(','); - } - else - { - sc.MustGetToken(TK_Identifier); - if(sc.Compare("health")) - cmd.flags = DRAWNUMBER_HEALTH; - else if(sc.Compare("armor")) - cmd.flags = DRAWNUMBER_ARMOR; - else if(sc.Compare("ammo1")) - cmd.flags = DRAWNUMBER_AMMO1; - else if(sc.Compare("ammo2")) - cmd.flags = DRAWNUMBER_AMMO2; - else if(sc.Compare("ammo")) //request the next string to be an ammo type - { - sc.MustGetToken(TK_Identifier); - cmd.setString(sc, sc.String, 0); - cmd.flags = DRAWNUMBER_AMMO; - const PClass* ammo = PClass::FindClass(sc.String); - if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo - { - sc.ScriptError("'%s' is not a type of ammo.", sc.String); - } - } - else if(sc.Compare("ammocapacity")) - { - sc.MustGetToken(TK_Identifier); - cmd.setString(sc, sc.String, 0); - cmd.flags = DRAWNUMBER_AMMOCAPACITY; - const PClass* ammo = PClass::FindClass(sc.String); - if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo - { - sc.ScriptError("'%s' is not a type of ammo.", sc.String); - } - } - else if(sc.Compare("frags")) - cmd.flags = DRAWNUMBER_FRAGS; - else if(sc.Compare("kills")) - cmd.flags |= DRAWNUMBER_KILLS; - else if(sc.Compare("monsters")) - cmd.flags |= DRAWNUMBER_MONSTERS; - else if(sc.Compare("items")) - cmd.flags |= DRAWNUMBER_ITEMS; - else if(sc.Compare("totalitems")) - cmd.flags |= DRAWNUMBER_TOTALITEMS; - else if(sc.Compare("secrets")) - cmd.flags |= DRAWNUMBER_SECRETS; - else if(sc.Compare("totalsecrets")) - cmd.flags |= DRAWNUMBER_TOTALSECRETS; - else if(sc.Compare("armorclass")) - cmd.flags |= DRAWNUMBER_ARMORCLASS; - else if(sc.Compare("airtime")) - cmd.flags |= DRAWNUMBER_AIRTIME; - else if(sc.Compare("globalvar")) - { - cmd.flags |= DRAWNUMBER_GLOBALVAR; - sc.MustGetToken(TK_IntConst); - if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) - sc.ScriptError("Global variable number out of range: %d", sc.Number); - cmd.value = sc.Number; - } - else if(sc.Compare("globalarray")) //acts like variable[playernumber()] - { - cmd.flags |= DRAWNUMBER_GLOBALARRAY; - sc.MustGetToken(TK_IntConst); - if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS) - sc.ScriptError("Global variable number out of range: %d", sc.Number); - cmd.value = sc.Number; - } - else if(sc.Compare("poweruptime")) - { - cmd.flags |= DRAWNUMBER_POWERUPTIME; - sc.MustGetToken(TK_Identifier); - cmd.setString(sc, sc.String, 0); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(item)) - { - sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); - } - } - else - { - cmd.flags = DRAWNUMBER_INVENTORY; - cmd.setString(sc, sc.String, 0); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of ammo - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - } - sc.MustGetToken(','); - } - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("fillzeros")) - cmd.flags |= DRAWNUMBER_FILLZEROS; - else if(sc.Compare("whennotzero")) - cmd.flags |= DRAWNUMBER_WHENNOTZERO; - else if(sc.Compare("drawshadow")) - cmd.flags |= DRAWNUMBER_DRAWSHADOW; - else - sc.ScriptError("Unknown flag '%s'.", sc.String); - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - if(sc.CheckToken(',')) - { - bool needsComma = false; - if(sc.CheckToken(TK_IntConst)) //font spacing - { - cmd.special2 = sc.Number; - needsComma = true; - } - if(!needsComma || sc.CheckToken(',')) //2nd coloring for "low-on" value - { - sc.MustGetToken(TK_Identifier); - cmd.translation2 = this->GetTranslation(sc, sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - cmd.special3 = sc.Number; - if(sc.CheckToken(',')) //3rd coloring for "high-on" value - { - sc.MustGetToken(TK_Identifier); - cmd.translation3 = this->GetTranslation(sc, sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - cmd.special4 = sc.Number; - } - } - } - sc.MustGetToken(';'); - break; - case SBARINFO_DRAWMUGSHOT: - if(sc.CheckToken(TK_StringConst)) - { - cmd.setString(sc, sc.String, 0, 3, true); - sc.MustGetToken(','); - } - sc.MustGetToken(TK_IntConst); //accuracy - if(sc.Number < 1 || sc.Number > 9) - sc.ScriptError("Expected a number between 1 and 9, got %d instead.", sc.Number); - cmd.special = sc.Number; - sc.MustGetToken(','); - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("xdeathface")) - cmd.flags |= DRAWMUGSHOT_XDEATHFACE; - else if(sc.Compare("animatedgodmode")) - cmd.flags |= DRAWMUGSHOT_ANIMATEDGODMODE; - else if(sc.Compare("disablegrin")) - cmd.flags |= DRAWMUGSHOT_DISABLEGRIN; - else if(sc.Compare("disableouch")) - cmd.flags |= DRAWMUGSHOT_DISABLEOUCH; - else if(sc.Compare("disablepain")) - cmd.flags |= DRAWMUGSHOT_DISABLEPAIN; - else if(sc.Compare("disablerampage")) - cmd.flags |= DRAWMUGSHOT_DISABLERAMPAGE; - else - sc.ScriptError("Unknown flag '%s'.", sc.String); - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - sc.MustGetToken(';'); - break; - case SBARINFO_DRAWSELECTEDINVENTORY: - { - bool alternateonempty = false; - while(true) //go until we get a font (non-flag) - { - sc.MustGetToken(TK_Identifier); - if(sc.Compare("alternateonempty")) - { - alternateonempty = true; - cmd.flags |= DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY; - } - else if(sc.Compare("artiflash")) - { - cmd.flags |= DRAWSELECTEDINVENTORY_ARTIFLASH; - } - else if(sc.Compare("alwaysshowcounter")) - { - cmd.flags |= DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER; - } - else if(sc.Compare("center")) - { - cmd.flags |= DRAWSELECTEDINVENTORY_CENTER; - } - else if(sc.Compare("centerbottom")) - { - cmd.flags |= DRAWSELECTEDINVENTORY_CENTERBOTTOM; - } - else if(sc.Compare("drawshadow")) - { - cmd.flags |= DRAWSELECTEDINVENTORY_DRAWSHADOW; - } - else - { - cmd.font = V_GetFont(sc.String); - if(cmd.font == NULL) - sc.ScriptError("Unknown font '%s'.", sc.String); - sc.MustGetToken(','); - break; - } - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - cmd.sbcoord2 = cmd.x + 30; - cmd.sbcoord3 = cmd.y + 24; - cmd.translation = CR_GOLD; - if(sc.CheckToken(',')) //more font information - { - this->getCoordinates(sc, block.fullScreenOffsets, cmd.sbcoord2, cmd.sbcoord3); - if(sc.CheckToken(',')) - { - sc.MustGetToken(TK_Identifier); - cmd.translation = this->GetTranslation(sc, sc.String); - if(sc.CheckToken(',')) - { - sc.MustGetToken(TK_IntConst); - cmd.special4 = sc.Number; - } - } - } - if(alternateonempty) - { - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - } - else - { - sc.MustGetToken(';'); - } - break; - } - case SBARINFO_DRAWINVENTORYBAR: - sc.MustGetToken(TK_Identifier); - if(sc.Compare("Doom")) - cmd.special = GAME_Doom; - else if(sc.Compare("Heretic")) - cmd.special = GAME_Heretic; - else if(sc.Compare("Hexen")) - cmd.special = GAME_Hexen; - else if(sc.Compare("Strife")) - cmd.special = GAME_Strife; - else - sc.ScriptError("Unknown style '%s'.", sc.String); - - sc.MustGetToken(','); - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("alwaysshow")) - { - cmd.flags |= DRAWINVENTORYBAR_ALWAYSSHOW; - } - else if(sc.Compare("noartibox")) - { - cmd.flags |= DRAWINVENTORYBAR_NOARTIBOX; - } - else if(sc.Compare("noarrows")) - { - cmd.flags |= DRAWINVENTORYBAR_NOARROWS; - } - else if(sc.Compare("alwaysshowcounter")) - { - cmd.flags |= DRAWINVENTORYBAR_ALWAYSSHOWCOUNTER; - } - else if(sc.Compare("translucent")) - { - cmd.flags |= DRAWINVENTORYBAR_TRANSLUCENT; - } - else if(sc.Compare("vertical")) - { - cmd.flags |= DRAWINVENTORYBAR_VERTICAL; - } - else - { - sc.ScriptError("Unknown flag '%s'.", sc.String); - } - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - sc.MustGetToken(TK_IntConst); - cmd.value = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); - cmd.font = V_GetFont(sc.String); - if(cmd.font == NULL) - sc.ScriptError("Unknown font '%s'.", sc.String); - - sc.MustGetToken(','); - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - cmd.sbcoord2 = cmd.x + 26; - cmd.sbcoord3 = cmd.y + 22; - cmd.translation = CR_GOLD; - if(sc.CheckToken(',')) //more font information - { - this->getCoordinates(sc, block.fullScreenOffsets, cmd.sbcoord2, cmd.sbcoord3); - if(sc.CheckToken(',')) - { - sc.MustGetToken(TK_Identifier); - cmd.translation = this->GetTranslation(sc, sc.String); - if(sc.CheckToken(',')) - { - sc.MustGetToken(TK_IntConst); - cmd.special4 = sc.Number; - } - } - } - sc.MustGetToken(';'); - break; - case SBARINFO_DRAWBAR: - sc.MustGetToken(TK_StringConst); - cmd.image_index = newImage(sc.String); - cmd.sprite_index.SetInvalid(); - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - cmd.special = newImage(sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); //yeah, this is the same as drawnumber, there might be a better way to copy it... - if(sc.Compare("health")) - { - cmd.flags = DRAWNUMBER_HEALTH; - if(sc.CheckToken(TK_Identifier)) //comparing reference - { - cmd.setString(sc, sc.String, 0); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of inventory - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - } - else - cmd.special2 = DRAWBAR_COMPAREDEFAULTS; - } - else if(sc.Compare("armor")) - { - cmd.flags = DRAWNUMBER_ARMOR; - if(sc.CheckToken(TK_Identifier)) - { - cmd.setString(sc, sc.String, 0); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("Inventory")->IsAncestorOf(item)) //must be a kind of inventory - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - } - else - cmd.special2 = DRAWBAR_COMPAREDEFAULTS; - } - else if(sc.Compare("ammo1")) - cmd.flags = DRAWNUMBER_AMMO1; - else if(sc.Compare("ammo2")) - cmd.flags = DRAWNUMBER_AMMO2; - else if(sc.Compare("ammo")) //request the next string to be an ammo type - { - sc.MustGetToken(TK_Identifier); - cmd.setString(sc, sc.String, 0); - cmd.flags = DRAWNUMBER_AMMO; - const PClass* ammo = PClass::FindClass(sc.String); - if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo - { - sc.ScriptError("'%s' is not a type of ammo.", sc.String); - } - } - else if(sc.Compare("frags")) - cmd.flags = DRAWNUMBER_FRAGS; - else if(sc.Compare("kills")) - cmd.flags = DRAWNUMBER_KILLS; - else if(sc.Compare("items")) - cmd.flags = DRAWNUMBER_ITEMS; - else if(sc.Compare("secrets")) - cmd.flags = DRAWNUMBER_SECRETS; - else if(sc.Compare("airtime")) - cmd.flags = DRAWNUMBER_AIRTIME; - else if(sc.Compare("poweruptime")) - { - cmd.flags |= DRAWNUMBER_POWERUPTIME; - sc.MustGetToken(TK_Identifier); - cmd.setString(sc, sc.String, 0); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !PClass::FindClass("PowerupGiver")->IsAncestorOf(item)) - { - sc.ScriptError("'%s' is not a type of PowerupGiver.", sc.String); - } - } - else - { - cmd.flags = DRAWNUMBER_INVENTORY; - cmd.setString(sc, sc.String, 0); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - } - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); - if(sc.Compare("horizontal")) - cmd.special2 += DRAWBAR_HORIZONTAL; - else if(!sc.Compare("vertical")) - sc.ScriptError("Unknown direction '%s'.", sc.String); - sc.MustGetToken(','); - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("reverse")) - cmd.special2 += DRAWBAR_REVERSE; - else - sc.ScriptError("Unkown flag '%s'.", sc.String); - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - if(sc.CheckToken(',')) //border - { - sc.MustGetToken(TK_IntConst); - cmd.special3 = sc.Number; - } - sc.MustGetToken(';'); - break; - case SBARINFO_DRAWGEM: - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("wiggle")) - cmd.flags |= DRAWGEM_WIGGLE; - else if(sc.Compare("translatable")) - cmd.flags |= DRAWGEM_TRANSLATABLE; - else if(sc.Compare("armor")) - cmd.flags |= DRAWGEM_ARMOR; - else if(sc.Compare("reverse")) - cmd.flags |= DRAWGEM_REVERSE; - else - sc.ScriptError("Unknown drawgem flag '%s'.", sc.String); - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - sc.MustGetToken(TK_StringConst); //chain - cmd.special = newImage(sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); //gem - cmd.image_index = newImage(sc.String); - cmd.sprite_index.SetInvalid(); - sc.MustGetToken(','); - cmd.special2 = this->getSignedInteger(sc); - sc.MustGetToken(','); - cmd.special3 = this->getSignedInteger(sc); - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - if(sc.Number < 0) - sc.ScriptError("Chain size must be a positive number."); - cmd.special4 = sc.Number; - sc.MustGetToken(','); - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - sc.MustGetToken(';'); - break; - case SBARINFO_DRAWSHADER: - sc.MustGetToken(TK_IntConst); - cmd.special = sc.Number; - if(sc.Number < 1) - sc.ScriptError("Width must be greater than 1."); - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - cmd.special2 = sc.Number; - if(sc.Number < 1) - sc.ScriptError("Height must be greater than 1."); - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); - if(sc.Compare("vertical")) - cmd.flags |= DRAWSHADER_VERTICAL; - else if(!sc.Compare("horizontal")) - sc.ScriptError("Unknown direction '%s'.", sc.String); - sc.MustGetToken(','); - if(sc.CheckToken(TK_Identifier)) - { - if(!sc.Compare("reverse")) - { - sc.ScriptError("Exspected 'reverse', got '%s' instead.", sc.String); - } - cmd.flags |= DRAWSHADER_REVERSE; - sc.MustGetToken(','); - } - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - sc.MustGetToken(';'); - break; - case SBARINFO_DRAWSTRING: - sc.MustGetToken(TK_Identifier); - cmd.font = V_GetFont(sc.String); - if(cmd.font == NULL) - sc.ScriptError("Unknown font '%s'.", sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); - cmd.translation = this->GetTranslation(sc, sc.String); - sc.MustGetToken(','); - sc.MustGetToken(TK_StringConst); - cmd.setString(sc, sc.String, 0, -1, false); - sc.MustGetToken(','); - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - if(sc.CheckToken(',')) //spacing - { - sc.MustGetToken(TK_IntConst); - cmd.special = sc.Number; - } - sc.MustGetToken(';'); - break; - case SBARINFO_DRAWKEYBAR: - sc.MustGetToken(TK_IntConst); - cmd.value = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_Identifier); - if(sc.Compare("vertical")) - cmd.flags |= DRAWKEYBAR_VERTICAL; - else if(!sc.Compare("horizontal")) - sc.ScriptError("Unknown direction '%s'.", sc.String); - sc.MustGetToken(','); - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("reverserows")) - cmd.flags |= DRAWKEYBAR_REVERSEROWS; - else - sc.ScriptError("Unknown flag '%s'.", sc.String); - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - if(sc.CheckToken(TK_Auto)) - cmd.special = -1; - else - { - sc.MustGetToken(TK_IntConst); - cmd.special = sc.Number; - } - sc.MustGetToken(','); - this->getCoordinates(sc, block.fullScreenOffsets, cmd.x, cmd.y); - if(sc.CheckToken(',')) - { - //key offset - sc.MustGetToken(TK_IntConst); - cmd.special2 = sc.Number; - if(sc.CheckToken(',')) - { - //max per row/column - sc.MustGetToken(TK_IntConst); - cmd.special3 = sc.Number; - sc.MustGetToken(','); - //row/column spacing (opposite of previous) - if(sc.CheckToken(TK_Auto)) - cmd.special4 = -1; - else - { - sc.MustGetToken(TK_IntConst); - cmd.special4 = sc.Number; - } - } - } - sc.MustGetToken(';'); - break; - case SBARINFO_GAMEMODE: - while(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("singleplayer")) - cmd.flags |= GAMETYPE_SINGLEPLAYER; - else if(sc.Compare("cooperative")) - cmd.flags |= GAMETYPE_COOPERATIVE; - else if(sc.Compare("deathmatch")) - cmd.flags |= GAMETYPE_DEATHMATCH; - else if(sc.Compare("teamgame")) - cmd.flags |= GAMETYPE_TEAMGAME; - //else I'm removing this error to allow cross port compatiblity. If it doesn't know what a gamemode is lets just ignore it. - // sc.ScriptError("Unknown gamemode: %s", sc.String); - if(sc.CheckToken('{')) - break; - sc.MustGetToken(','); - } - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - case SBARINFO_PLAYERCLASS: - cmd.special = cmd.special2 = cmd.special3 = -1; - for(int i = 0;i < 3 && sc.CheckToken(TK_Identifier);i++) //up to 3 classes - { - bool foundClass = false; - for(unsigned int c = 0;c < PlayerClasses.Size();c++) - { - if(stricmp(sc.String, PlayerClasses[c].Type->Meta.GetMetaString(APMETA_DisplayName)) == 0) - { - foundClass = true; - if(i == 0) - cmd.special = PlayerClasses[c].Type->ClassIndex; - else if(i == 1) - cmd.special2 = PlayerClasses[c].Type->ClassIndex; - else //should be 2 - cmd.special3 = PlayerClasses[c].Type->ClassIndex; - break; - } - } - if(!foundClass) - sc.ScriptError("Unkown PlayerClass '%s'.", sc.String); - if(sc.CheckToken('{') || i == 2) - goto FinishPlayerClass; - sc.MustGetToken(','); - } - FinishPlayerClass: - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - case SBARINFO_ASPECTRATIO: - sc.MustGetToken(TK_StringConst); - if(sc.Compare("4:3")) - cmd.value = ASPECTRATIO_4_3; - else if(sc.Compare("16:9")) - cmd.value = ASPECTRATIO_16_9; - else if(sc.Compare("16:10")) - cmd.value = ASPECTRATIO_16_10; - else if(sc.Compare("5:4")) - cmd.value = ASPECTRATIO_5_4; - else - sc.ScriptError("Unkown aspect ratio: %s", sc.String); - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - case SBARINFO_ISSELECTED: - //Using StringConst instead of Identifieres is deperecated! - if(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("not")) - { - cmd.flags |= SBARINFOEVENT_NOT; - if(!sc.CheckToken(TK_StringConst)) - sc.MustGetToken(TK_Identifier); - } - } - else - sc.MustGetToken(TK_StringConst); - for(int i = 0;i < 2;i++) - { - cmd.setString(sc, sc.String, i); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(item)) - { - sc.ScriptError("'%s' is not a type of weapon.", sc.String); - } - if(sc.CheckToken(',')) - { - if(!sc.CheckToken(TK_StringConst)) - sc.MustGetToken(TK_Identifier); - } - else - break; - } - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - case SBARINFO_USESSECONDARYAMMO: - case SBARINFO_USESAMMO: - if(sc.CheckToken(TK_Identifier)) - { - if(sc.Compare("not")) - cmd.flags |= SBARINFOEVENT_NOT; - else - sc.ScriptError("Expected 'not' got '%s' instead.", sc.String); - } - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - case SBARINFO_HASWEAPONPIECE: - { - sc.MustGetToken(TK_Identifier); - const PClass* weapon = PClass::FindClass(sc.String); - if(weapon == NULL || !RUNTIME_CLASS(AWeapon)->IsAncestorOf(weapon)) //must be a weapon - sc.ScriptError("%s is not a kind of weapon.", sc.String); - cmd.setString(sc, sc.String, 0); - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - if(sc.Number < 1) - sc.ScriptError("Weapon piece number can not be less than 1."); - cmd.value = sc.Number; - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - } - case SBARINFO_INVENTORYBARNOTVISIBLE: - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - case SBARINFO_WEAPONAMMO: - sc.MustGetToken(TK_Identifier); - if(sc.Compare("not")) - { - cmd.flags |= SBARINFOEVENT_NOT; - sc.MustGetToken(TK_Identifier); - } - for(int i = 0;i < 2;i++) - { - cmd.setString(sc, sc.String, i); - const PClass* ammo = PClass::FindClass(sc.String); - if(ammo == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(ammo)) //must be a kind of ammo - { - sc.ScriptError("'%s' is not a type of ammo.", sc.String); - } - if(sc.CheckToken(TK_OrOr)) - { - cmd.flags |= SBARINFOEVENT_OR; - sc.MustGetToken(TK_Identifier); - } - else if(sc.CheckToken(TK_AndAnd)) - { - cmd.flags |= SBARINFOEVENT_AND; - sc.MustGetToken(TK_Identifier); - } - else - break; - } - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - case SBARINFO_ININVENTORY: - cmd.special2 = cmd.special3 = 0; - sc.MustGetToken(TK_Identifier); - if(sc.Compare("not")) - { - cmd.flags |= SBARINFOEVENT_NOT; - sc.MustGetToken(TK_Identifier); - } - for(int i = 0;i < 2;i++) - { - cmd.setString(sc, sc.String, i); - const PClass* item = PClass::FindClass(sc.String); - if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item)) - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - if (sc.CheckToken(',')) - { - sc.MustGetNumber(); - if (i == 0) cmd.special2 = sc.Number; - else cmd.special3 = sc.Number; - } - - if(sc.CheckToken(TK_OrOr)) - { - cmd.flags |= SBARINFOEVENT_OR; - sc.MustGetToken(TK_Identifier); - } - else if(sc.CheckToken(TK_AndAnd)) - { - cmd.flags |= SBARINFOEVENT_AND; - sc.MustGetToken(TK_Identifier); - } - else - break; - } - sc.MustGetToken('{'); - cmd.subBlock.fullScreenOffsets = block.fullScreenOffsets; - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - } - block.commands.Push(cmd); - } - sc.MustGetToken('}'); -} - -void SBarInfo::ParseMugShotBlock(FScanner &sc, FMugShotState &state) -{ - sc.MustGetToken('{'); - while(!sc.CheckToken('}')) - { - FMugShotFrame frame; - bool multiframe = false; - if(sc.CheckToken('{')) - multiframe = true; - do - { - sc.MustGetToken(TK_Identifier); - if(strlen(sc.String) > 5) - 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); - sc.MustGetToken(';'); - state.Frames.Push(frame); - } -} - -void SBarInfo::getCoordinates(FScanner &sc, bool fullScreenOffsets, SBarInfoCoordinate &x, SBarInfoCoordinate &y) -{ - bool negative = false; - bool relCenter = false; - SBarInfoCoordinate *coords[2] = {&x, &y}; - for(int i = 0;i < 2;i++) - { - negative = false; - relCenter = false; - if(i > 0) - sc.MustGetToken(','); - - // [-]INT center - negative = sc.CheckToken('-'); - sc.MustGetToken(TK_IntConst); - coords[i]->Set(negative ? -sc.Number : sc.Number, false); - if(sc.CheckToken('+')) - { - sc.MustGetToken(TK_Identifier); - if(!sc.Compare("center")) - sc.ScriptError("Expected 'center' but got '%s' instead.", sc.String); - relCenter = true; - } - if(fullScreenOffsets) - { - coords[i]->SetRelCenter(relCenter); - } - } - - if(!fullScreenOffsets) - y.SetCoord((negative ? -sc.Number : sc.Number) - (200 - this->height)); -} - -int SBarInfo::getSignedInteger(FScanner &sc) -{ - if(sc.CheckToken('-')) - { - sc.MustGetToken(TK_IntConst); - return -sc.Number; - } - else - { - sc.MustGetToken(TK_IntConst); - return sc.Number; - } -} - -int SBarInfo::newImage(const char *patchname) -{ - if(patchname[0] == '\0' || stricmp(patchname, "nullimage") == 0) - { - return -1; - } - for(unsigned int i = 0;i < this->Images.Size();i++) //did we already load it? - { - if(stricmp(this->Images[i], patchname) == 0) - { - return i; - } - } - return this->Images.Push(patchname); -} - -//converts a string into a tranlation. -EColorRange SBarInfo::GetTranslation(FScanner &sc, const char* translation) -{ - EColorRange returnVal = CR_UNTRANSLATED; - FString namedTranslation; //we must send in "[translation]" - const BYTE *trans_ptr; - namedTranslation.Format("[%s]", translation); - trans_ptr = (const BYTE *)(&namedTranslation[0]); - if((returnVal = V_ParseFontColor(trans_ptr, CR_UNTRANSLATED, CR_UNTRANSLATED)) == CR_UNDEFINED) - { - sc.ScriptError("Missing definition for color %s.", translation); - } - return returnVal; -} - -SBarInfo::SBarInfo() //make results more predicable -{ - Init(); -} - -SBarInfo::SBarInfo(int lumpnum) -{ - Init(); - ParseSBarInfo(lumpnum); -} - -void SBarInfo::Init() -{ - automapbar = false; - interpolateHealth = false; - interpolateArmor = false; - completeBorder = false; - lowerHealthCap = true; - interpolationSpeed = 8; - armorInterpolationSpeed = 8; - height = 0; - spacingCharacter = '\0'; -} - -SBarInfo::~SBarInfo() -{ - for (size_t i = 0; i < NUMHUDS; ++i) - { - huds[i].commands.Clear(); - } -} - -void SBarInfoCommand::setString(FScanner &sc, const char* source, int strnum, int maxlength, bool exact) -{ - if(!exact) - { - if(maxlength != -1 && strlen(source) > (unsigned int) maxlength) - { - sc.ScriptError("%s is greater than %d characters.", source, maxlength); - return; - } - } - else - { - if(maxlength != -1 && strlen(source) != (unsigned int) maxlength) - { - sc.ScriptError("%s must be %d characters.", source, maxlength); - return; - } - } - string[strnum] = source; -} - -SBarInfoCommand::SBarInfoCommand() //sets the default values for more predicable behavior -{ - type = 0; - special = 0; - special2 = 0; - special3 = 0; - special4 = 0; - flags = 0; - x.Set(0, 0); - y.Set(0, 0); - value = 0; - image_index = 0; - sprite_index.SetInvalid(); - translation = CR_UNTRANSLATED; - translation2 = CR_UNTRANSLATED; - translation3 = CR_UNTRANSLATED; - font = V_GetFont("CONFONT"); -} - -SBarInfoCommand::~SBarInfoCommand() -{ -} - -SBarInfoBlock::SBarInfoBlock() -{ - forceScaled = false; - fullScreenOffsets = false; - alpha = FRACUNIT; -} - -//Popup -Popup::Popup() -{ - transition = TRANSITION_NONE; - height = 320; - width = 200; - speed = 0; - x = 320; - y = 200; - alpha = FRACUNIT; - opened = false; - moving = false; -} - -void Popup::init() -{ - x = width; - y = height; - if(transition == TRANSITION_SLIDEINBOTTOM) - { - x = 0; - } - else if(transition == TRANSITION_FADE) - { - alpha = 0; - x = 0; - y = 0; - } -} - -void Popup::tick() -{ - if(transition == TRANSITION_SLIDEINBOTTOM) - { - if(moving) - { - if(opened) - y -= clamp(height + (y - height), 1, speed); - else - y += clamp(height - y, 1, speed); - } - if(y != 0 && y != height) - moving = true; - else - moving = false; - } - else if(transition == TRANSITION_FADE) - { - if(moving) - { - if(opened) - alpha = clamp(alpha + speed, 0, FRACUNIT); - else - alpha = clamp(alpha - speed2, 0, FRACUNIT); - } - if(alpha == 0 || alpha == FRACUNIT) - moving = false; - else - moving = true; - } - else - { - if(opened) - { - y = 0; - x = 0; - } - else - { - y = height; - x = width; - } - moving = false; - } -} - -bool Popup::isDoneMoving() -{ - return !moving; -} - -int Popup::getXOffset() -{ - return x; -} - -int Popup::getYOffset() -{ - return y; -} - -int Popup::getAlpha(int maxAlpha) -{ - double a = (double) alpha / (double) FRACUNIT; - double b = (double) maxAlpha / (double) FRACUNIT; - return fixed_t((a * b) * FRACUNIT); -} - -void Popup::open() -{ - opened = true; - moving = true; -} - -void Popup::close() -{ - opened = false; - moving = true; -} diff --git a/src/p_acs.cpp b/src/p_acs.cpp index c6f4791c40..6ffabeec3e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -67,7 +67,6 @@ #include "c_bind.h" #include "info.h" #include "r_translate.h" -#include "sbarinfo.h" #include "cmdlib.h" #include "m_png.h" #include "p_setup.h" diff --git a/zdoom.vcproj b/zdoom.vcproj index f31bbbbe22..97a2f13788 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + @@ -1864,14 +1872,6 @@ Outputs="$(IntDir)/$(InputName).obj" /> - - - @@ -2061,14 +2061,6 @@ Outputs="$(IntDir)\$(InputName).obj" /> - - - @@ -2079,6 +2071,14 @@ Outputs="$(IntDir)\$(InputName).obj" /> + + + + + - - + + + + + + - - - + + + - - - @@ -5355,6 +5363,14 @@ AdditionalIncludeDirectories="src\win32;$(NoInherit)" /> + + + @@ -5633,7 +5649,7 @@ />